Pivot table visualization

This commit is contained in:
Arik Fraimovich 2016-11-22 12:27:14 +02:00
parent c67828f48d
commit 8952919f41
6 changed files with 71 additions and 88 deletions

View File

@ -2,10 +2,7 @@
"name": "redash", "name": "redash",
"version": "0.11.0", "version": "0.11.0",
"dependencies": { "dependencies": {
"pivottable": "2.0.2",
"pace": "~0.5.1", "pace": "~0.5.1",
"canvg": "gabelerner/canvg", "canvg": "gabelerner/canvg",
"leaflet": "~0.7.3",
"leaflet.markercluster": "^0.5.0"
}, },
} }

View File

@ -13,6 +13,7 @@ import wordCloudVisualization from './word-cloud';
import boxPlotVisualization from './box-plot'; import boxPlotVisualization from './box-plot';
import cohortVisualization from './cohort'; import cohortVisualization from './cohort';
import mapVisualization from './map'; import mapVisualization from './map';
import pivotVisualization from './pivot';
function VisualizationProvider() { function VisualizationProvider() {
this.visualizations = {}; this.visualizations = {};
@ -168,5 +169,6 @@ export default function (ngModule) {
boxPlotVisualization(ngModule); boxPlotVisualization(ngModule);
cohortVisualization(ngModule); cohortVisualization(ngModule);
mapVisualization(ngModule); mapVisualization(ngModule);
pivotVisualization(ngModule);
tableVisualization(ngModule); tableVisualization(ngModule);
} }

View File

@ -0,0 +1,68 @@
import $ from 'jquery';
import 'pivottable';
import 'pivottable/dist/pivot.css';
function pivotTableRenderer() {
return {
restrict: 'E',
scope: {
queryResult: '=',
visualization: '=',
},
template: '',
replace: false,
link($scope, element) {
$scope.$watch('queryResult && queryResult.getData()', (data) => {
if (!data) {
return;
}
if ($scope.queryResult.getData() !== null) {
// We need to give the pivot table its own copy of the data, because it changes
// it which interferes with other visualizations.
data = $.extend(true, [], $scope.queryResult.getRawData());
const options = {
renderers: $.pivotUtilities.renderers,
onRefresh(config) {
const configCopy = Object.assign({}, config);
// delete some values which are functions
delete configCopy.aggregators;
delete configCopy.renderers;
delete configCopy.onRefresh;
// delete some bulky default values
delete configCopy.rendererOptions;
delete configCopy.localeStrings;
if ($scope.visualization) {
$scope.visualization.options = configCopy;
}
},
};
if ($scope.visualization) {
Object.assign(options, $scope.visualization.options);
}
$(element).pivotUI(data, options, true);
}
});
},
};
}
export default function (ngModule) {
ngModule.directive('pivotTableRenderer', pivotTableRenderer);
ngModule.config((VisualizationProvider) => {
const editTemplate = '<div/>';
const defaultOptions = {
};
VisualizationProvider.registerVisualization({
type: 'PIVOT',
name: 'Pivot Table',
renderTemplate: '<pivot-table-renderer visualization="visualization" query-result="queryResult"></pivot-table-renderer>',
editorTemplate: editTemplate,
defaultOptions,
});
});
}

View File

@ -58,6 +58,7 @@
"ng-annotate": "^1.2.1", "ng-annotate": "^1.2.1",
"ng-annotate-loader": "^0.2.0", "ng-annotate-loader": "^0.2.0",
"ng-table": "^2.1.0", "ng-table": "^2.1.0",
"pivottable": "^2.3.0",
"plotly.js": "^1.16.0", "plotly.js": "^1.16.0",
"raw-loader": "^0.5.1", "raw-loader": "^0.5.1",
"ui-select": "^0.19.6", "ui-select": "^0.19.6",

View File

@ -10,7 +10,6 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- build:css /styles/main.css --> <!-- build:css /styles/main.css -->
<link rel="stylesheet" href="/bower_components/pivottable/dist/pivot.css">
<link rel="stylesheet" href="/bower_components/pace/themes/pace-theme-minimal.css"> <link rel="stylesheet" href="/bower_components/pace/themes/pace-theme-minimal.css">
<link rel="stylesheet" href="/styles/redash.css"> <link rel="stylesheet" href="/styles/redash.css">
<!-- endbuild --> <!-- endbuild -->
@ -55,8 +54,6 @@
{% include 'vendor_scripts.html' %} {% include 'vendor_scripts.html' %}
<!-- build:js({.tmp,rd_ui/app}) /scripts/scripts.js --> <!-- build:js({.tmp,rd_ui/app}) /scripts/scripts.js -->
<script src="/scripts/vendor/cloud.js"></script>
<script src="/scripts/vendor/d3.sankey.js"></script>
<script src="/scripts/app.js"></script> <script src="/scripts/app.js"></script>
<script src="/scripts/services/services.js"></script> <script src="/scripts/services/services.js"></script>
<script src="/scripts/services/resources.js"></script> <script src="/scripts/services/resources.js"></script>
@ -71,23 +68,6 @@
<script src="/scripts/controllers/query_source.js"></script> <script src="/scripts/controllers/query_source.js"></script>
<script src="/scripts/controllers/users.js"></script> <script src="/scripts/controllers/users.js"></script>
<script src="/scripts/controllers/snippets.js"></script> <script src="/scripts/controllers/snippets.js"></script>
<script src="/scripts/visualizations/base.js"></script>
<script src="/scripts/visualizations/chart.js"></script>
<script src="/scripts/visualizations/cohort.js"></script>
<script src="/scripts/visualizations/map.js"></script>
<script src="/scripts/visualizations/counter.js"></script>
<script src="/scripts/visualizations/boxplot.js"></script>
<script src="/scripts/visualizations/box.js"></script>
<script src="/scripts/visualizations/table.js"></script>
<script src="/scripts/visualizations/pivot.js"></script>
<script src="/scripts/visualizations/wordcloud.js"></script>
<script src="/scripts/visualizations/sunburst_sequence.js"></script>
<script src="/scripts/visualizations/sankey.js"></script>
<script src="/scripts/directives/directives.js"></script>
<script src="/scripts/directives/query_directives.js"></script>
<script src="/scripts/directives/dashboard_directives.js"></script>
<script src="/scripts/filters.js"></script>
<script src="/scripts/controllers/alerts.js"></script>
<!-- endbuild --> <!-- endbuild -->
<script> <script>

View File

@ -1,65 +0,0 @@
(function() {
var module = angular.module('redash.visualization');
module.directive('pivotTableRenderer', function () {
return {
restrict: 'E',
scope: {
queryResult: '=',
visualization: '='
},
template: "",
replace: false,
link: function($scope, element) {
$scope.$watch('queryResult && queryResult.getData()', function (data) {
if (!data) {
return;
}
if ($scope.queryResult.getData() === null) {
} else {
// We need to give the pivot table its own copy of the data, because it changes
// it which interferes with other visualizations.
data = $.extend(true, [], $scope.queryResult.getRawData());
var options = {
renderers: $.pivotUtilities.renderers,
onRefresh: function(config) {
var configCopy = $.extend(true, {}, config);
//delete some values which are functions
delete configCopy.aggregators;
delete configCopy.renderers;
delete configCopy.onRefresh;
//delete some bulky default values
delete configCopy.rendererOptions;
delete configCopy.localeStrings;
if ($scope.visualization) {
$scope.visualization.options = configCopy;
}
}
};
if ($scope.visualization) {
$.extend(options, $scope.visualization.options);
}
$(element).pivotUI(data, options, true);
}
});
}
};
});
module.config(['VisualizationProvider', function (VisualizationProvider) {
var editTemplate = '<div/>';
var defaultOptions = {
};
VisualizationProvider.registerVisualization({
type: 'PIVOT',
name: 'Pivot Table',
renderTemplate: '<pivot-table-renderer visualization="visualization" query-result="queryResult"></pivot-table-renderer>',
editorTemplate: editTemplate,
defaultOptions: defaultOptions
});
}]);
})();