@datarailsshared/dr_renderer 1.5.114 → 1.5.118
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/dr_pivottable.js +141 -8
- package/src/highcharts_renderer.js +34 -22
- package/src/index.d.ts +1 -0
- package/src/index.js +0 -2
- package/tests/highcharts_renderer.test.js +0 -2
- package/tests/ptCreateDrillDownSeriesToDrilldownChart.test.js +0 -2
- package/src/pivottable.js +0 -715
package/package.json
CHANGED
package/src/dr_pivottable.js
CHANGED
|
@@ -3,20 +3,136 @@ const { DELIMER } = require('./dr-renderer-helpers');
|
|
|
3
3
|
const { TooMuchDataError } = require('./errors');
|
|
4
4
|
|
|
5
5
|
let initDRPivotTable = function($, window, document) {
|
|
6
|
-
var
|
|
7
|
-
|
|
6
|
+
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
|
7
|
+
hasProp = {}.hasOwnProperty;
|
|
8
8
|
|
|
9
9
|
var DRPivotData, processKey, SubtotalRenderer, getFormattedNumber, NovixRenderer;
|
|
10
10
|
const newTableColors = ['rgb(127, 196, 255)', 'rgb(200, 243,243)', 'rgb(247, 161, 173)', 'rgb(255, 237, 178)', 'rgb(221, 239, 255)',
|
|
11
11
|
'rgb(171, 216, 255)', 'rgb(174, 231, 220)', 'rgb(227, 255, 236)', 'rgb(162, 215, 227)', 'rgb(223, 239, 236)'];
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/*
|
|
14
|
+
Utilities (from pivottable@2.23.0)
|
|
15
|
+
*/
|
|
16
|
+
var addSeparators, aggregatorTemplates, locales, numberFormat, usFmtInt;
|
|
17
|
+
addSeparators = function(nStr, thousandsSep, decimalSep) {
|
|
18
|
+
var rgx, x, x1, x2;
|
|
19
|
+
nStr += '';
|
|
20
|
+
x = nStr.split('.');
|
|
21
|
+
x1 = x[0];
|
|
22
|
+
x2 = x.length > 1 ? decimalSep + x[1] : '';
|
|
23
|
+
rgx = /(\d+)(\d{3})/;
|
|
24
|
+
while (rgx.test(x1)) {
|
|
25
|
+
x1 = x1.replace(rgx, '$1' + thousandsSep + '$2');
|
|
26
|
+
}
|
|
27
|
+
return x1 + x2;
|
|
28
|
+
};
|
|
14
29
|
|
|
15
|
-
|
|
16
|
-
|
|
30
|
+
numberFormat = function(opts) {
|
|
31
|
+
var defaults;
|
|
32
|
+
defaults = {
|
|
33
|
+
digitsAfterDecimal: 2,
|
|
34
|
+
scaler: 1,
|
|
35
|
+
thousandsSep: ",",
|
|
36
|
+
decimalSep: ".",
|
|
37
|
+
prefix: "",
|
|
38
|
+
suffix: ""
|
|
39
|
+
};
|
|
40
|
+
opts = $.extend({}, defaults, opts);
|
|
41
|
+
return function(x) {
|
|
42
|
+
var result;
|
|
43
|
+
if (isNaN(x) || !isFinite(x)) {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
result = addSeparators((opts.scaler * x).toFixed(opts.digitsAfterDecimal), opts.thousandsSep, opts.decimalSep);
|
|
47
|
+
return "" + opts.prefix + result + opts.suffix;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
usFmtInt = numberFormat({
|
|
51
|
+
digitsAfterDecimal: 0
|
|
52
|
+
});
|
|
53
|
+
aggregatorTemplates = {
|
|
54
|
+
count: function(formatter) {
|
|
55
|
+
if (formatter == null) {
|
|
56
|
+
formatter = usFmtInt;
|
|
57
|
+
}
|
|
58
|
+
return function() {
|
|
59
|
+
return function(data, rowKey, colKey) {
|
|
60
|
+
return {
|
|
61
|
+
count: 0,
|
|
62
|
+
push: function() {
|
|
63
|
+
return this.count++;
|
|
64
|
+
},
|
|
65
|
+
value: function() {
|
|
66
|
+
return this.count;
|
|
67
|
+
},
|
|
68
|
+
format: formatter
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
locales = {
|
|
75
|
+
en: {
|
|
76
|
+
localeStrings: {
|
|
77
|
+
selectAll: "Select All",
|
|
78
|
+
selectNone: "Select None",
|
|
79
|
+
tooMany: "(too many to list)",
|
|
80
|
+
filterResults: "Filter values",
|
|
81
|
+
apply: "Apply",
|
|
82
|
+
cancel: "Cancel",
|
|
83
|
+
totals: "Totals",
|
|
84
|
+
vs: "vs",
|
|
85
|
+
by: "by"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
DRPivotData = (function() {
|
|
17
91
|
|
|
18
92
|
function DRPivotData(input, opts) {
|
|
19
|
-
|
|
93
|
+
if (opts == null) {
|
|
94
|
+
opts = {};
|
|
95
|
+
}
|
|
96
|
+
this.getAggregator = bind(this.getAggregator, this);
|
|
97
|
+
this.getRowKeys = bind(this.getRowKeys, this);
|
|
98
|
+
this.getColKeys = bind(this.getColKeys, this);
|
|
99
|
+
this.getRowKeysByCols = bind(this.getRowKeysByCols, this);
|
|
100
|
+
this.input = input;
|
|
101
|
+
this.aggregator = opts.aggregator != null ? opts.aggregator : aggregatorTemplates.count()();
|
|
102
|
+
this.aggregatorName = opts.aggregatorName != null ? opts.aggregatorName : "Count";
|
|
103
|
+
this.colAttrs = opts.cols != null ? opts.cols : [];
|
|
104
|
+
this.rowAttrs = opts.rows != null ? opts.rows : [];
|
|
105
|
+
this.derivedAttributes = opts.derivedAttributes != null ? opts.derivedAttributes : {};
|
|
106
|
+
this.filter = opts.filter != null ? opts.filter : (function() {
|
|
107
|
+
return true;
|
|
108
|
+
});
|
|
109
|
+
this.isSmartQueriesEnabled = _.some(input, item => item.Scenario === DR_SCENARIO.SQ_Actuals);
|
|
110
|
+
|
|
111
|
+
this.tree = {};
|
|
112
|
+
|
|
113
|
+
// some chart types don't have row/col keys (for example, KPI_WIDGET)
|
|
114
|
+
this.rowKeys = opts.keysObject ? opts.keysObject.row_keys : [];
|
|
115
|
+
this.colKeys = opts.keysObject ? opts.keysObject.col_keys : [];
|
|
116
|
+
this.rowKeysByCols = opts.keysObject ? opts.keysObject.row_keys_by_cols : [];
|
|
117
|
+
|
|
118
|
+
this.rowTotals = {};
|
|
119
|
+
this.colTotals = {};
|
|
120
|
+
this.allTotal = this.aggregator(this, [], []);
|
|
121
|
+
this.dateValuesDictionary = opts.dateValuesDictionary;
|
|
122
|
+
this.colFormats = opts.colFormats || [];
|
|
123
|
+
this.rowFormats = opts.rowFormats || [];
|
|
124
|
+
this.isFormattingAxisLabels = opts.rendererOptions && opts.rendererOptions.isFormattingAxisLabels;
|
|
125
|
+
this.getFormattedColKeys = (keys) => opts.getFormattedColKeys(this, keys);
|
|
126
|
+
this.getFormattedRowKeys = (keys) => opts.getFormattedRowKeys(this, keys);
|
|
127
|
+
this.isDrillDownDisabled = opts.isDrillDownDisabled;
|
|
128
|
+
|
|
129
|
+
this.forEachRecord(this.input, this.derivedAttributes, (function(_this) {
|
|
130
|
+
return function(record) {
|
|
131
|
+
if (_this.filter(record)) {
|
|
132
|
+
return _this.processRecord(record, _this.isSmartQueriesEnabled);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
})(this));
|
|
20
136
|
}
|
|
21
137
|
|
|
22
138
|
DRPivotData.prototype.forEachRecord = function(input, derivedAttributes, f) {
|
|
@@ -193,11 +309,28 @@ let initDRPivotTable = function($, window, document) {
|
|
|
193
309
|
};
|
|
194
310
|
};
|
|
195
311
|
|
|
312
|
+
DRPivotData.prototype.getColKeys = function() {
|
|
313
|
+
return this.colKeys;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
DRPivotData.prototype.getRowKeys = function() {
|
|
317
|
+
return this.rowKeys;
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
DRPivotData.prototype.getRowKeysByCols = function() {
|
|
321
|
+
return this.rowKeysByCols;
|
|
322
|
+
};
|
|
323
|
+
|
|
196
324
|
return DRPivotData;
|
|
197
325
|
|
|
198
|
-
})(
|
|
326
|
+
})();
|
|
199
327
|
|
|
200
|
-
$.pivotUtilities
|
|
328
|
+
$.pivotUtilities = {
|
|
329
|
+
aggregatorTemplates: aggregatorTemplates,
|
|
330
|
+
locales: locales,
|
|
331
|
+
numberFormat: numberFormat,
|
|
332
|
+
DRPivotData: DRPivotData
|
|
333
|
+
};
|
|
201
334
|
|
|
202
335
|
getFormattedNumber = function(val, aggregator, opts, format_argument) {
|
|
203
336
|
if (!aggregator) {
|
|
@@ -3265,7 +3265,7 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
3265
3265
|
highchartsRenderer.ptRenderStackedPercentColumn = function (pivotData, opts, _drilldownFunc, chartType) {
|
|
3266
3266
|
var chartOptions = {};
|
|
3267
3267
|
var rowAttrs = pivotData.rowAttrs;
|
|
3268
|
-
var additionOptions = opts.chartOptions ? opts.chartOptions : highchartsRenderer.getDefaultValueForChart(
|
|
3268
|
+
var additionOptions = opts.chartOptions ? opts.chartOptions : highchartsRenderer.getDefaultValueForChart(optionsBuilders.CHART_TYPES.COLUMN_CHART_STACKED_PERCENT);
|
|
3269
3269
|
|
|
3270
3270
|
chartOptions.chart = {
|
|
3271
3271
|
type: 'column',
|
|
@@ -3331,6 +3331,12 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
3331
3331
|
}
|
|
3332
3332
|
};
|
|
3333
3333
|
chartOptions = highchartsRenderer.prepareAxisX(chartOptions, additionOptions, pivotData.getColKeys());
|
|
3334
|
+
if (lodash.get(opts, 'paletteOptions.widgetPalette', null)) {
|
|
3335
|
+
const mc_palette = lodash.find(lodash.get(opts.paletteOptions, 'monochromePalettes', []), { selected: true });
|
|
3336
|
+
chartOptions.colors = mc_palette ? mc_palette.colors : opts.paletteOptions.widgetPalette;
|
|
3337
|
+
} else if (lodash.get(opts, 'paletteOptions.dashboardPalette.colors', null)) {
|
|
3338
|
+
chartOptions.colors = opts.paletteOptions.dashboardPalette.colors;
|
|
3339
|
+
}
|
|
3334
3340
|
|
|
3335
3341
|
chartOptions.series = highchartsRenderer.ptCreateColumnSeries(pivotData, chartOptions.colors, null, true, true, additionOptions, opts, chartOptions, chartType);
|
|
3336
3342
|
|
|
@@ -3563,7 +3569,7 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
3563
3569
|
highchartsRenderer.ptRenderStackedPercentBar = function (pivotData, opts) {
|
|
3564
3570
|
var chartOptions = {};
|
|
3565
3571
|
var rowAttrs = pivotData.rowAttrs;
|
|
3566
|
-
var additionOptions = opts.chartOptions ? opts.chartOptions : highchartsRenderer.getDefaultValueForChart(
|
|
3572
|
+
var additionOptions = opts.chartOptions ? opts.chartOptions : highchartsRenderer.getDefaultValueForChart(optionsBuilders.CHART_TYPES.BAR_CHART_STACKED_PERCENT);
|
|
3567
3573
|
|
|
3568
3574
|
const labelStyle = lodash.merge(
|
|
3569
3575
|
LABEL_DEFAULT_OPTIONS.style,
|
|
@@ -3634,6 +3640,12 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
3634
3640
|
},
|
|
3635
3641
|
};
|
|
3636
3642
|
chartOptions = highchartsRenderer.prepareAxisX(chartOptions, additionOptions, pivotData.getColKeys());
|
|
3643
|
+
if (lodash.get(opts, 'paletteOptions.widgetPalette', null)) {
|
|
3644
|
+
const mc_palette = lodash.find(lodash.get(opts.paletteOptions, 'monochromePalettes', []), { selected: true });
|
|
3645
|
+
chartOptions.colors = mc_palette ? mc_palette.colors : opts.paletteOptions.widgetPalette;
|
|
3646
|
+
} else if (lodash.get(opts, 'paletteOptions.dashboardPalette.colors', null)) {
|
|
3647
|
+
chartOptions.colors = opts.paletteOptions.dashboardPalette.colors;
|
|
3648
|
+
}
|
|
3637
3649
|
chartOptions.series = highchartsRenderer.ptCreateBasicLineSeries(pivotData, null, null, null, additionOptions, opts, chartOptions);
|
|
3638
3650
|
|
|
3639
3651
|
// Sanitize series data for 100% stacking (convert negative values to 0)
|
|
@@ -6315,7 +6327,7 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
6315
6327
|
axisTooltipTitle: 'Drag one or more fields to create the Polygons edges.',
|
|
6316
6328
|
legendTooltipTitle: 'Adding a field in this section will display data points in your chart for each item in that field.',
|
|
6317
6329
|
},
|
|
6318
|
-
|
|
6330
|
+
[optionsBuilders.CHART_TYPES.COLUMN_CHART]: {
|
|
6319
6331
|
name: 'Column chart',
|
|
6320
6332
|
label: 'Column',
|
|
6321
6333
|
title: 'Compare two or more data series in different categories.',
|
|
@@ -6327,9 +6339,9 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
6327
6339
|
axisTooltipDescription: 'To create a drill-down within this category, drag another field below the first field.',
|
|
6328
6340
|
legendTooltipTitle: 'Each field in the data series will appear as a separate column in the chart.',
|
|
6329
6341
|
},
|
|
6330
|
-
|
|
6342
|
+
[optionsBuilders.CHART_TYPES.COLUMN_CHART_STACKED]: {
|
|
6331
6343
|
name: 'Stacked column chart',
|
|
6332
|
-
label: 'Stacked
|
|
6344
|
+
label: 'Stacked column',
|
|
6333
6345
|
title: 'Useful for explaining part-to-whole comparisons over time, or across categories.',
|
|
6334
6346
|
description: 'For example, comparison over time of expenses divided into subcategories. The chart describes both total expenses over time and the relation between the different sub-categories.',
|
|
6335
6347
|
axisName: 'X - Axis',
|
|
@@ -6338,18 +6350,18 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
6338
6350
|
axisTooltipTitle: 'Drag one or more fields here to create your x-axis. Each item within the field will appear as a different column.',
|
|
6339
6351
|
legendTooltipTitle: 'Each field item will appear as a different segment within the column.',
|
|
6340
6352
|
},
|
|
6341
|
-
|
|
6353
|
+
[optionsBuilders.CHART_TYPES.COLUMN_CHART_STACKED_PERCENT]: {
|
|
6342
6354
|
name: '100% Stacked column chart',
|
|
6343
|
-
label: '100% Stacked
|
|
6344
|
-
title: '
|
|
6345
|
-
description: '
|
|
6355
|
+
label: '100% Stacked column',
|
|
6356
|
+
title: 'Explains the percentage contribution of each value to a total across categories',
|
|
6357
|
+
description: 'For example, showing each department’s share of total expenses per month.',
|
|
6346
6358
|
axisName: 'X - Axis',
|
|
6347
6359
|
legendName: 'Data series',
|
|
6348
6360
|
startedMessage: 'To get started, drag one field to the x-axis section, and one field to the value section. Best practice: we recommend adding one field to the data series section too.',
|
|
6349
6361
|
axisTooltipTitle: 'Drag one or more fields here to create your x-axis. Each item within the field will appear as a different column.',
|
|
6350
6362
|
legendTooltipTitle: 'Each field item will appear as a different segment within the column.',
|
|
6351
6363
|
},
|
|
6352
|
-
|
|
6364
|
+
[optionsBuilders.CHART_TYPES.BAR_CHART]: {
|
|
6353
6365
|
name: 'Bar chart',
|
|
6354
6366
|
label: 'Bar',
|
|
6355
6367
|
title: 'Compare one or more data series across a given category.',
|
|
@@ -6360,9 +6372,9 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
6360
6372
|
axisTooltipTitle: 'Drag one or more fields here to create your y-axis.',
|
|
6361
6373
|
legendTooltipTitle: 'Each field item will appear as a different segment within the bar.',
|
|
6362
6374
|
},
|
|
6363
|
-
|
|
6375
|
+
[optionsBuilders.CHART_TYPES.BAR_CHART_STACKED]: {
|
|
6364
6376
|
name: 'Stacked bar chart',
|
|
6365
|
-
label: 'Stacked
|
|
6377
|
+
label: 'Stacked bar',
|
|
6366
6378
|
title: 'Good for explaining part-to-whole comparisons across a given category.',
|
|
6367
6379
|
description: 'For example, compare between sales-rep contributions to the total Revenue in different regions.',
|
|
6368
6380
|
axisName: 'Y - Axis',
|
|
@@ -6371,11 +6383,11 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
6371
6383
|
axisTooltipTitle: 'Drag one or more fields here to create your y-axis.',
|
|
6372
6384
|
legendTooltipTitle: 'Each field item will appear as a different segment within the bar.',
|
|
6373
6385
|
},
|
|
6374
|
-
|
|
6386
|
+
[optionsBuilders.CHART_TYPES.BAR_CHART_STACKED_PERCENT]: {
|
|
6375
6387
|
name: '100% Stacked bar chart',
|
|
6376
|
-
label: '100% Stacked
|
|
6377
|
-
title: '
|
|
6378
|
-
description: '
|
|
6388
|
+
label: '100% Stacked bar',
|
|
6389
|
+
title: 'Explains the percentage contribution of each value to a total across categories',
|
|
6390
|
+
description: 'For example, showing each department’s share of total expenses per month.',
|
|
6379
6391
|
axisName: 'Y - Axis',
|
|
6380
6392
|
legendName: 'Data series',
|
|
6381
6393
|
startedMessage: 'To get started, drag one field to the y-axis section, and one field to the value section. Best practice: add one field to the Categories section too.',
|
|
@@ -6733,9 +6745,9 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
6733
6745
|
]
|
|
6734
6746
|
},
|
|
6735
6747
|
{
|
|
6736
|
-
type:
|
|
6737
|
-
hidden:
|
|
6738
|
-
name: highchartsRenderer.chartsTypesInfo[
|
|
6748
|
+
type: optionsBuilders.CHART_TYPES.COLUMN_CHART_STACKED_PERCENT,
|
|
6749
|
+
hidden: !environment.enableStackedPercentCharts,
|
|
6750
|
+
name: highchartsRenderer.chartsTypesInfo[optionsBuilders.CHART_TYPES.COLUMN_CHART_STACKED_PERCENT].name,
|
|
6739
6751
|
class: 'google-visualization-charteditor-thumbs-columnchart-stacked-percent',
|
|
6740
6752
|
render: highchartsRenderer.ptRenderStackedPercentColumn,
|
|
6741
6753
|
suboptions: [
|
|
@@ -6801,9 +6813,9 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
6801
6813
|
]
|
|
6802
6814
|
},
|
|
6803
6815
|
{
|
|
6804
|
-
type:
|
|
6805
|
-
hidden:
|
|
6806
|
-
name: highchartsRenderer.chartsTypesInfo[
|
|
6816
|
+
type: optionsBuilders.CHART_TYPES.BAR_CHART_STACKED_PERCENT,
|
|
6817
|
+
hidden: !environment.enableStackedPercentCharts,
|
|
6818
|
+
name: highchartsRenderer.chartsTypesInfo[optionsBuilders.CHART_TYPES.BAR_CHART_STACKED_PERCENT].name,
|
|
6807
6819
|
class: 'google-visualization-charteditor-thumbs-barchart-stacked-percent',
|
|
6808
6820
|
render: highchartsRenderer.ptRenderStackedPercentBar,
|
|
6809
6821
|
suboptions: [
|
package/src/index.d.ts
CHANGED
package/src/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const getPublishedItemsRenderer = require('./published_items_renderer');
|
|
2
2
|
const getHighchartsRenderer = require('./highcharts_renderer');
|
|
3
|
-
const initPivotTable = require('./pivottable');
|
|
4
3
|
const initDRPivotTable = require('./dr_pivottable');
|
|
5
4
|
const initNovixRenderer = require('./novix_renderer');
|
|
6
5
|
const DataFormatter = require('./dataformatter');
|
|
@@ -12,7 +11,6 @@ let dr_render_factory = {};
|
|
|
12
11
|
|
|
13
12
|
dr_render_factory.init = function($, window, document, Handsontable){
|
|
14
13
|
window.DataFormatter = DataFormatter;
|
|
15
|
-
initPivotTable($, window, document);
|
|
16
14
|
initDRPivotTable($, window, document);
|
|
17
15
|
if(Handsontable){
|
|
18
16
|
initNovixRenderer($, window, document, Handsontable);
|
|
@@ -6,7 +6,6 @@ import addInTables from './mock/add-in-tables.json';
|
|
|
6
6
|
import addInFunctions from './mock/add-in-functions.json';
|
|
7
7
|
import addInDynamicRanges from './mock/add-in-dynamic-ranges.json';
|
|
8
8
|
import widgets from './mock/widgets.json';
|
|
9
|
-
import initPivotTable from "../src/pivottable";
|
|
10
9
|
import initDRPivotTable from "../src/dr_pivottable";
|
|
11
10
|
import valueFormatter from "../src/value.formatter";
|
|
12
11
|
import { DrGaugeChart, GAUGE_OPTIONS_DEFAULT } from "../src/charts/dr_gauge_chart";
|
|
@@ -90,7 +89,6 @@ describe('highcharts_renderer', () => {
|
|
|
90
89
|
chart: () => {},
|
|
91
90
|
};
|
|
92
91
|
_window.DataFormatter = DataFormatter;
|
|
93
|
-
initPivotTable($, _window, _document);
|
|
94
92
|
initDRPivotTable($, _window, _document);
|
|
95
93
|
|
|
96
94
|
highchartsRenderer = getHighchartsRenderer($, _document, Highcharts, lodash.cloneDeep(DEFAULT_USER_COLORS), highchartsRenderer,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as JQuery from "jquery";
|
|
2
2
|
import * as lodash from 'lodash';
|
|
3
3
|
import moment from 'moment/min/moment.min';
|
|
4
|
-
import initPivotTable from "../src/pivottable";
|
|
5
4
|
import initDRPivotTable from "../src/dr_pivottable";
|
|
6
5
|
|
|
7
6
|
const getHighchartsRenderer = require('../src/highcharts_renderer');
|
|
@@ -69,7 +68,6 @@ describe('ptCreateDrillDownSeriesToDrilldownChart', () => {
|
|
|
69
68
|
DataFormatter: DataFormatter
|
|
70
69
|
};
|
|
71
70
|
|
|
72
|
-
initPivotTable(JQuery, _window, _document);
|
|
73
71
|
initDRPivotTable(JQuery, _window, _document);
|
|
74
72
|
|
|
75
73
|
const DEFAULT_USER_COLORS = ['#7cb5ec', '#434348', '#90ed7d', '#f7a35c', '#8085e9', '#f15c80', '#e4d354', '#2b908f', '#f45b5b', '#91e8e1'];
|
package/src/pivottable.js
DELETED
|
@@ -1,715 +0,0 @@
|
|
|
1
|
-
const _ = require('lodash');
|
|
2
|
-
const helpers = require('./dr-renderer-helpers');
|
|
3
|
-
const { DR_SCENARIO } = require('./smart_queries_helper');
|
|
4
|
-
const { GenericRenderingError, GenericComputationalError} = require('./errors');
|
|
5
|
-
|
|
6
|
-
// from pivottable@2.23.0
|
|
7
|
-
let initPivotTable = function($, window, document) {
|
|
8
|
-
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
|
9
|
-
hasProp = {}.hasOwnProperty;
|
|
10
|
-
/*
|
|
11
|
-
Utilities
|
|
12
|
-
*/
|
|
13
|
-
var PivotData, addSeparators, aggregatorTemplates, locales, numberFormat, pivotTableRenderer, usFmtInt;
|
|
14
|
-
addSeparators = function(nStr, thousandsSep, decimalSep) {
|
|
15
|
-
var rgx, x, x1, x2;
|
|
16
|
-
nStr += '';
|
|
17
|
-
x = nStr.split('.');
|
|
18
|
-
x1 = x[0];
|
|
19
|
-
x2 = x.length > 1 ? decimalSep + x[1] : '';
|
|
20
|
-
rgx = /(\d+)(\d{3})/;
|
|
21
|
-
while (rgx.test(x1)) {
|
|
22
|
-
x1 = x1.replace(rgx, '$1' + thousandsSep + '$2');
|
|
23
|
-
}
|
|
24
|
-
return x1 + x2;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
numberFormat = function(opts) {
|
|
28
|
-
var defaults;
|
|
29
|
-
defaults = {
|
|
30
|
-
digitsAfterDecimal: 2,
|
|
31
|
-
scaler: 1,
|
|
32
|
-
thousandsSep: ",",
|
|
33
|
-
decimalSep: ".",
|
|
34
|
-
prefix: "",
|
|
35
|
-
suffix: ""
|
|
36
|
-
};
|
|
37
|
-
opts = $.extend({}, defaults, opts);
|
|
38
|
-
return function(x) {
|
|
39
|
-
var result;
|
|
40
|
-
if (isNaN(x) || !isFinite(x)) {
|
|
41
|
-
return "";
|
|
42
|
-
}
|
|
43
|
-
result = addSeparators((opts.scaler * x).toFixed(opts.digitsAfterDecimal), opts.thousandsSep, opts.decimalSep);
|
|
44
|
-
return "" + opts.prefix + result + opts.suffix;
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
usFmtInt = numberFormat({
|
|
48
|
-
digitsAfterDecimal: 0
|
|
49
|
-
});
|
|
50
|
-
aggregatorTemplates = {
|
|
51
|
-
count: function(formatter) {
|
|
52
|
-
if (formatter == null) {
|
|
53
|
-
formatter = usFmtInt;
|
|
54
|
-
}
|
|
55
|
-
return function() {
|
|
56
|
-
return function(data, rowKey, colKey) {
|
|
57
|
-
return {
|
|
58
|
-
count: 0,
|
|
59
|
-
push: function() {
|
|
60
|
-
return this.count++;
|
|
61
|
-
},
|
|
62
|
-
value: function() {
|
|
63
|
-
return this.count;
|
|
64
|
-
},
|
|
65
|
-
format: formatter
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
};
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
locales = {
|
|
72
|
-
en: {
|
|
73
|
-
localeStrings: {
|
|
74
|
-
selectAll: "Select All",
|
|
75
|
-
selectNone: "Select None",
|
|
76
|
-
tooMany: "(too many to list)",
|
|
77
|
-
filterResults: "Filter values",
|
|
78
|
-
apply: "Apply",
|
|
79
|
-
cancel: "Cancel",
|
|
80
|
-
totals: "Totals",
|
|
81
|
-
vs: "vs",
|
|
82
|
-
by: "by"
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
/*
|
|
88
|
-
Data Model class
|
|
89
|
-
*/
|
|
90
|
-
PivotData = (function() {
|
|
91
|
-
function PivotData(input, opts) {
|
|
92
|
-
var ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9;
|
|
93
|
-
if (opts == null) {
|
|
94
|
-
opts = {};
|
|
95
|
-
}
|
|
96
|
-
this.getAggregator = bind(this.getAggregator, this);
|
|
97
|
-
this.getRowKeys = bind(this.getRowKeys, this);
|
|
98
|
-
this.getColKeys = bind(this.getColKeys, this);
|
|
99
|
-
this.getRowKeysByCols = bind(this.getRowKeysByCols, this);
|
|
100
|
-
this.input = input;
|
|
101
|
-
this.aggregator = (ref = opts.aggregator) != null ? ref : aggregatorTemplates.count()();
|
|
102
|
-
this.aggregatorName = (ref1 = opts.aggregatorName) != null ? ref1 : "Count";
|
|
103
|
-
this.colAttrs = (ref2 = opts.cols) != null ? ref2 : [];
|
|
104
|
-
this.rowAttrs = (ref3 = opts.rows) != null ? ref3 : [];
|
|
105
|
-
this.derivedAttributes = (ref8 = opts.derivedAttributes) != null ? ref8 : {};
|
|
106
|
-
this.filter = (ref9 = opts.filter) != null ? ref9 : (function() {
|
|
107
|
-
return true;
|
|
108
|
-
});
|
|
109
|
-
this.isSmartQueriesEnabled = _.some(input, item => item.Scenario === DR_SCENARIO.SQ_Actuals);
|
|
110
|
-
|
|
111
|
-
this.tree = {};
|
|
112
|
-
|
|
113
|
-
// some chart types don't have row/col keys (for example, KPI_WIDGET)
|
|
114
|
-
this.rowKeys = opts.keysObject ? opts.keysObject.row_keys : [];
|
|
115
|
-
this.colKeys = opts.keysObject ? opts.keysObject.col_keys : [];
|
|
116
|
-
this.rowKeysByCols = opts.keysObject ? opts.keysObject.row_keys_by_cols : [];
|
|
117
|
-
|
|
118
|
-
this.rowTotals = {};
|
|
119
|
-
this.colTotals = {};
|
|
120
|
-
this.allTotal = this.aggregator(this, [], []);
|
|
121
|
-
this.dateValuesDictionary = opts.dateValuesDictionary;
|
|
122
|
-
this.colFormats = opts.colFormats || [];
|
|
123
|
-
this.rowFormats = opts.rowFormats || [];
|
|
124
|
-
this.isFormattingAxisLabels = opts.rendererOptions && opts.rendererOptions.isFormattingAxisLabels;
|
|
125
|
-
this.getFormattedColKeys = (keys) => opts.getFormattedColKeys(this, keys);
|
|
126
|
-
this.getFormattedRowKeys = (keys) => opts.getFormattedRowKeys(this, keys);
|
|
127
|
-
this.isDrillDownDisabled = opts.isDrillDownDisabled;
|
|
128
|
-
|
|
129
|
-
PivotData.forEachRecord(this.input, this.derivedAttributes, (function(_this) {
|
|
130
|
-
return function(record) {
|
|
131
|
-
if (_this.filter(record)) {
|
|
132
|
-
return _this.processRecord(record, _this.isSmartQueriesEnabled);
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
})(this));
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
PivotData.forEachRecord = function(input, derivedAttributes, f) {
|
|
139
|
-
var addRecord, compactRecord, i, j, k, l, len1, record, ref, results, results1, tblCols;
|
|
140
|
-
if ($.isEmptyObject(derivedAttributes)) {
|
|
141
|
-
addRecord = f;
|
|
142
|
-
} else {
|
|
143
|
-
addRecord = function(record) {
|
|
144
|
-
var k, ref, v;
|
|
145
|
-
for (k in derivedAttributes) {
|
|
146
|
-
v = derivedAttributes[k];
|
|
147
|
-
record[k] = (ref = v(record)) != null ? ref : record[k];
|
|
148
|
-
}
|
|
149
|
-
return f(record);
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
if ($.isFunction(input)) {
|
|
153
|
-
return input(addRecord);
|
|
154
|
-
} else if ($.isArray(input)) {
|
|
155
|
-
if ($.isArray(input[0])) {
|
|
156
|
-
results = [];
|
|
157
|
-
for (i in input) {
|
|
158
|
-
if (!hasProp.call(input, i)) continue;
|
|
159
|
-
compactRecord = input[i];
|
|
160
|
-
if (!(i > 0)) {
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
record = {};
|
|
164
|
-
ref = input[0];
|
|
165
|
-
for (j in ref) {
|
|
166
|
-
if (!hasProp.call(ref, j)) continue;
|
|
167
|
-
k = ref[j];
|
|
168
|
-
record[k] = compactRecord[j];
|
|
169
|
-
}
|
|
170
|
-
results.push(addRecord(record));
|
|
171
|
-
}
|
|
172
|
-
return results;
|
|
173
|
-
} else {
|
|
174
|
-
results1 = [];
|
|
175
|
-
for (l = 0, len1 = input.length; l < len1; l++) {
|
|
176
|
-
record = input[l];
|
|
177
|
-
results1.push(addRecord(record));
|
|
178
|
-
}
|
|
179
|
-
return results1;
|
|
180
|
-
}
|
|
181
|
-
} else if (input instanceof $) {
|
|
182
|
-
tblCols = [];
|
|
183
|
-
$("thead > tr > th", input).each(function(i) {
|
|
184
|
-
return tblCols.push($(this).text());
|
|
185
|
-
});
|
|
186
|
-
return $("tbody > tr", input).each(function(i) {
|
|
187
|
-
record = {};
|
|
188
|
-
$("td", this).each(function(j) {
|
|
189
|
-
return record[tblCols[j]] = $(this).text();
|
|
190
|
-
});
|
|
191
|
-
return addRecord(record);
|
|
192
|
-
});
|
|
193
|
-
} else {
|
|
194
|
-
throw new Error("unknown input format");
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
PivotData.prototype.getColKeys = function() {
|
|
199
|
-
return this.colKeys;
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
PivotData.prototype.getRowKeys = function() {
|
|
203
|
-
return this.rowKeys;
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
PivotData.prototype.getRowKeysByCols = function() {
|
|
207
|
-
return this.rowKeysByCols;
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
PivotData.prototype.processRecord = function(record) {
|
|
211
|
-
var colKey, flatColKey, flatRowKey, l, len1, len2, n, ref, ref1, ref2, ref3, rowKey, x;
|
|
212
|
-
colKey = [];
|
|
213
|
-
rowKey = [];
|
|
214
|
-
ref = this.colAttrs;
|
|
215
|
-
for (l = 0, len1 = ref.length; l < len1; l++) {
|
|
216
|
-
x = ref[l];
|
|
217
|
-
colKey.push((ref1 = record[x]) != null ? ref1 : "null");
|
|
218
|
-
}
|
|
219
|
-
ref2 = this.rowAttrs;
|
|
220
|
-
for (n = 0, len2 = ref2.length; n < len2; n++) {
|
|
221
|
-
x = ref2[n];
|
|
222
|
-
rowKey.push((ref3 = record[x]) != null ? ref3 : "null");
|
|
223
|
-
}
|
|
224
|
-
flatRowKey = rowKey.join(String.fromCharCode(0));
|
|
225
|
-
flatColKey = colKey.join(String.fromCharCode(0));
|
|
226
|
-
this.allTotal.push(record);
|
|
227
|
-
if (rowKey.length !== 0) {
|
|
228
|
-
if (!this.rowTotals[flatRowKey]) {
|
|
229
|
-
this.rowKeys.push(rowKey);
|
|
230
|
-
this.rowTotals[flatRowKey] = this.aggregator(this, rowKey, []);
|
|
231
|
-
}
|
|
232
|
-
this.rowTotals[flatRowKey].push(record);
|
|
233
|
-
}
|
|
234
|
-
if (colKey.length !== 0) {
|
|
235
|
-
if (!this.colTotals[flatColKey]) {
|
|
236
|
-
this.colKeys.push(colKey);
|
|
237
|
-
this.colTotals[flatColKey] = this.aggregator(this, [], colKey);
|
|
238
|
-
}
|
|
239
|
-
this.colTotals[flatColKey].push(record);
|
|
240
|
-
}
|
|
241
|
-
if (colKey.length !== 0 && rowKey.length !== 0) {
|
|
242
|
-
if (!this.tree[flatRowKey]) {
|
|
243
|
-
this.tree[flatRowKey] = {};
|
|
244
|
-
}
|
|
245
|
-
if (!this.tree[flatRowKey][flatColKey]) {
|
|
246
|
-
this.tree[flatRowKey][flatColKey] = this.aggregator(this, rowKey, colKey);
|
|
247
|
-
}
|
|
248
|
-
return this.tree[flatRowKey][flatColKey].push(record);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
PivotData.prototype.getAggregator = function(rowKey, colKey) {
|
|
253
|
-
var agg, flatColKey, flatRowKey;
|
|
254
|
-
flatRowKey = rowKey.join(String.fromCharCode(0));
|
|
255
|
-
flatColKey = colKey.join(String.fromCharCode(0));
|
|
256
|
-
if (rowKey.length === 0 && colKey.length === 0) {
|
|
257
|
-
agg = this.allTotal;
|
|
258
|
-
} else if (rowKey.length === 0) {
|
|
259
|
-
agg = this.colTotals[flatColKey];
|
|
260
|
-
} else if (colKey.length === 0) {
|
|
261
|
-
agg = this.rowTotals[flatRowKey];
|
|
262
|
-
} else {
|
|
263
|
-
agg = this.tree[flatRowKey][flatColKey];
|
|
264
|
-
}
|
|
265
|
-
return agg != null ? agg : {
|
|
266
|
-
value: (function() {
|
|
267
|
-
return null;
|
|
268
|
-
}),
|
|
269
|
-
format: function() {
|
|
270
|
-
return "";
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
return PivotData;
|
|
276
|
-
|
|
277
|
-
})();
|
|
278
|
-
|
|
279
|
-
$.pivotUtilities = {
|
|
280
|
-
aggregatorTemplates: aggregatorTemplates,
|
|
281
|
-
locales: locales,
|
|
282
|
-
numberFormat: numberFormat,
|
|
283
|
-
PivotData: PivotData,
|
|
284
|
-
};
|
|
285
|
-
if (window.$) {
|
|
286
|
-
window.$.pivotUtilities = $.pivotUtilities
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/*
|
|
290
|
-
Default Renderer for hierarchical table layout
|
|
291
|
-
*/
|
|
292
|
-
pivotTableRenderer = function(pivotData, opts) {
|
|
293
|
-
var aggregator, c, colAttrs, colKey, colKeys, defaults, getClickHandler, i, j, r, result, rowAttrs, rowKey, rowKeys, spanSize, tbody, td, th, thead, totalAggregator, tr, txt, val, x;
|
|
294
|
-
defaults = {
|
|
295
|
-
table: {
|
|
296
|
-
clickCallback: null,
|
|
297
|
-
rowTotals: true,
|
|
298
|
-
colTotals: true
|
|
299
|
-
},
|
|
300
|
-
localeStrings: {
|
|
301
|
-
totals: "Totals"
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
opts = $.extend(true, {}, defaults, opts);
|
|
305
|
-
colAttrs = pivotData.colAttrs;
|
|
306
|
-
rowAttrs = pivotData.rowAttrs;
|
|
307
|
-
rowKeys = pivotData.getRowKeys();
|
|
308
|
-
colKeys = pivotData.getColKeys();
|
|
309
|
-
if (opts.table.clickCallback) {
|
|
310
|
-
getClickHandler = function(value, rowValues, colValues) {
|
|
311
|
-
var attr, filters, i;
|
|
312
|
-
filters = {};
|
|
313
|
-
for (i in colAttrs) {
|
|
314
|
-
if (!hasProp.call(colAttrs, i)) continue;
|
|
315
|
-
attr = colAttrs[i];
|
|
316
|
-
if (colValues[i] != null) {
|
|
317
|
-
filters[attr] = colValues[i];
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
for (i in rowAttrs) {
|
|
321
|
-
if (!hasProp.call(rowAttrs, i)) continue;
|
|
322
|
-
attr = rowAttrs[i];
|
|
323
|
-
if (rowValues[i] != null) {
|
|
324
|
-
filters[attr] = rowValues[i];
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return function(e) {
|
|
328
|
-
return opts.table.clickCallback(e, value, filters, pivotData);
|
|
329
|
-
};
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
|
-
result = document.createElement("table");
|
|
333
|
-
result.className = "pvtTable";
|
|
334
|
-
spanSize = function(arr, i, j) {
|
|
335
|
-
var l, len, n, noDraw, ref, ref1, stop, x;
|
|
336
|
-
if (i !== 0) {
|
|
337
|
-
noDraw = true;
|
|
338
|
-
for (x = l = 0, ref = j; 0 <= ref ? l <= ref : l >= ref; x = 0 <= ref ? ++l : --l) {
|
|
339
|
-
if (arr[i - 1][x] !== arr[i][x]) {
|
|
340
|
-
noDraw = false;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
if (noDraw) {
|
|
344
|
-
return -1;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
len = 0;
|
|
348
|
-
while (i + len < arr.length) {
|
|
349
|
-
stop = false;
|
|
350
|
-
for (x = n = 0, ref1 = j; 0 <= ref1 ? n <= ref1 : n >= ref1; x = 0 <= ref1 ? ++n : --n) {
|
|
351
|
-
if (arr[i][x] !== arr[i + len][x]) {
|
|
352
|
-
stop = true;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
if (stop) {
|
|
356
|
-
break;
|
|
357
|
-
}
|
|
358
|
-
len++;
|
|
359
|
-
}
|
|
360
|
-
return len;
|
|
361
|
-
};
|
|
362
|
-
thead = document.createElement("thead");
|
|
363
|
-
for (j in colAttrs) {
|
|
364
|
-
if (!hasProp.call(colAttrs, j)) continue;
|
|
365
|
-
c = colAttrs[j];
|
|
366
|
-
tr = document.createElement("tr");
|
|
367
|
-
if (parseInt(j) === 0 && rowAttrs.length !== 0) {
|
|
368
|
-
th = document.createElement("th");
|
|
369
|
-
th.setAttribute("colspan", rowAttrs.length);
|
|
370
|
-
th.setAttribute("rowspan", colAttrs.length);
|
|
371
|
-
tr.appendChild(th);
|
|
372
|
-
}
|
|
373
|
-
th = document.createElement("th");
|
|
374
|
-
th.className = "pvtAxisLabel";
|
|
375
|
-
th.textContent = c;
|
|
376
|
-
tr.appendChild(th);
|
|
377
|
-
for (i in colKeys) {
|
|
378
|
-
if (!hasProp.call(colKeys, i)) continue;
|
|
379
|
-
colKey = colKeys[i];
|
|
380
|
-
x = spanSize(colKeys, parseInt(i), parseInt(j));
|
|
381
|
-
if (x !== -1) {
|
|
382
|
-
th = document.createElement("th");
|
|
383
|
-
th.className = "pvtColLabel";
|
|
384
|
-
th.textContent = colKey[j];
|
|
385
|
-
th.setAttribute("colspan", x);
|
|
386
|
-
if (parseInt(j) === colAttrs.length - 1 && rowAttrs.length !== 0) {
|
|
387
|
-
th.setAttribute("rowspan", 2);
|
|
388
|
-
}
|
|
389
|
-
tr.appendChild(th);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
if (parseInt(j) === 0 && opts.table.rowTotals) {
|
|
393
|
-
th = document.createElement("th");
|
|
394
|
-
th.className = "pvtTotalLabel pvtRowTotalLabel";
|
|
395
|
-
th.innerHTML = opts.localeStrings.totals;
|
|
396
|
-
th.setAttribute("rowspan", colAttrs.length + (rowAttrs.length === 0 ? 0 : 1));
|
|
397
|
-
tr.appendChild(th);
|
|
398
|
-
}
|
|
399
|
-
thead.appendChild(tr);
|
|
400
|
-
}
|
|
401
|
-
if (rowAttrs.length !== 0) {
|
|
402
|
-
tr = document.createElement("tr");
|
|
403
|
-
for (i in rowAttrs) {
|
|
404
|
-
if (!hasProp.call(rowAttrs, i)) continue;
|
|
405
|
-
r = rowAttrs[i];
|
|
406
|
-
th = document.createElement("th");
|
|
407
|
-
th.className = "pvtAxisLabel";
|
|
408
|
-
th.textContent = r;
|
|
409
|
-
tr.appendChild(th);
|
|
410
|
-
}
|
|
411
|
-
th = document.createElement("th");
|
|
412
|
-
if (colAttrs.length === 0) {
|
|
413
|
-
th.className = "pvtTotalLabel pvtRowTotalLabel";
|
|
414
|
-
th.innerHTML = opts.localeStrings.totals;
|
|
415
|
-
}
|
|
416
|
-
tr.appendChild(th);
|
|
417
|
-
thead.appendChild(tr);
|
|
418
|
-
}
|
|
419
|
-
result.appendChild(thead);
|
|
420
|
-
tbody = document.createElement("tbody");
|
|
421
|
-
for (i in rowKeys) {
|
|
422
|
-
if (!hasProp.call(rowKeys, i)) continue;
|
|
423
|
-
rowKey = rowKeys[i];
|
|
424
|
-
tr = document.createElement("tr");
|
|
425
|
-
for (j in rowKey) {
|
|
426
|
-
if (!hasProp.call(rowKey, j)) continue;
|
|
427
|
-
txt = rowKey[j];
|
|
428
|
-
x = spanSize(rowKeys, parseInt(i), parseInt(j));
|
|
429
|
-
if (x !== -1) {
|
|
430
|
-
th = document.createElement("th");
|
|
431
|
-
th.className = "pvtRowLabel";
|
|
432
|
-
th.textContent = txt;
|
|
433
|
-
th.setAttribute("rowspan", x);
|
|
434
|
-
if (parseInt(j) === rowAttrs.length - 1 && colAttrs.length !== 0) {
|
|
435
|
-
th.setAttribute("colspan", 2);
|
|
436
|
-
}
|
|
437
|
-
tr.appendChild(th);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
for (j in colKeys) {
|
|
441
|
-
if (!hasProp.call(colKeys, j)) continue;
|
|
442
|
-
colKey = colKeys[j];
|
|
443
|
-
aggregator = pivotData.getAggregator(rowKey, colKey);
|
|
444
|
-
val = aggregator.value();
|
|
445
|
-
td = document.createElement("td");
|
|
446
|
-
td.className = "pvtVal row" + i + " col" + j;
|
|
447
|
-
td.textContent = aggregator.format(val);
|
|
448
|
-
td.setAttribute("data-value", val);
|
|
449
|
-
if (getClickHandler != null) {
|
|
450
|
-
td.onclick = getClickHandler(val, rowKey, colKey);
|
|
451
|
-
}
|
|
452
|
-
tr.appendChild(td);
|
|
453
|
-
}
|
|
454
|
-
if (opts.table.rowTotals || colAttrs.length === 0) {
|
|
455
|
-
totalAggregator = pivotData.getAggregator(rowKey, []);
|
|
456
|
-
val = totalAggregator.value();
|
|
457
|
-
td = document.createElement("td");
|
|
458
|
-
td.className = "pvtTotal rowTotal";
|
|
459
|
-
td.textContent = totalAggregator.format(val);
|
|
460
|
-
td.setAttribute("data-value", val);
|
|
461
|
-
if (getClickHandler != null) {
|
|
462
|
-
td.onclick = getClickHandler(val, rowKey, []);
|
|
463
|
-
}
|
|
464
|
-
td.setAttribute("data-for", "row" + i);
|
|
465
|
-
tr.appendChild(td);
|
|
466
|
-
}
|
|
467
|
-
tbody.appendChild(tr);
|
|
468
|
-
}
|
|
469
|
-
if (opts.table.colTotals || rowAttrs.length === 0) {
|
|
470
|
-
tr = document.createElement("tr");
|
|
471
|
-
if (opts.table.colTotals || rowAttrs.length === 0) {
|
|
472
|
-
th = document.createElement("th");
|
|
473
|
-
th.className = "pvtTotalLabel pvtColTotalLabel";
|
|
474
|
-
th.innerHTML = opts.localeStrings.totals;
|
|
475
|
-
th.setAttribute("colspan", rowAttrs.length + (colAttrs.length === 0 ? 0 : 1));
|
|
476
|
-
tr.appendChild(th);
|
|
477
|
-
}
|
|
478
|
-
for (j in colKeys) {
|
|
479
|
-
if (!hasProp.call(colKeys, j)) continue;
|
|
480
|
-
colKey = colKeys[j];
|
|
481
|
-
totalAggregator = pivotData.getAggregator([], colKey);
|
|
482
|
-
val = totalAggregator.value();
|
|
483
|
-
td = document.createElement("td");
|
|
484
|
-
td.className = "pvtTotal colTotal";
|
|
485
|
-
td.textContent = totalAggregator.format(val);
|
|
486
|
-
td.setAttribute("data-value", val);
|
|
487
|
-
if (getClickHandler != null) {
|
|
488
|
-
td.onclick = getClickHandler(val, [], colKey);
|
|
489
|
-
}
|
|
490
|
-
td.setAttribute("data-for", "col" + j);
|
|
491
|
-
tr.appendChild(td);
|
|
492
|
-
}
|
|
493
|
-
if (opts.table.rowTotals || colAttrs.length === 0) {
|
|
494
|
-
totalAggregator = pivotData.getAggregator([], []);
|
|
495
|
-
val = totalAggregator.value();
|
|
496
|
-
td = document.createElement("td");
|
|
497
|
-
td.className = "pvtGrandTotal";
|
|
498
|
-
td.textContent = totalAggregator.format(val);
|
|
499
|
-
td.setAttribute("data-value", val);
|
|
500
|
-
if (getClickHandler != null) {
|
|
501
|
-
td.onclick = getClickHandler(val, [], []);
|
|
502
|
-
}
|
|
503
|
-
tr.appendChild(td);
|
|
504
|
-
}
|
|
505
|
-
tbody.appendChild(tr);
|
|
506
|
-
}
|
|
507
|
-
result.appendChild(tbody);
|
|
508
|
-
result.setAttribute("data-numrows", rowKeys.length);
|
|
509
|
-
result.setAttribute("data-numcols", colKeys.length);
|
|
510
|
-
return result;
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
/*
|
|
514
|
-
Pivot Table core: create PivotData object and call Renderer on it
|
|
515
|
-
*/
|
|
516
|
-
$.fn.pivot = function(input, inputOpts, locale) {
|
|
517
|
-
var defaults, e, localeDefaults, localeStrings, opts, pivotData, result, x;
|
|
518
|
-
if (locale == null) {
|
|
519
|
-
locale = "en";
|
|
520
|
-
}
|
|
521
|
-
if (locales[locale] == null) {
|
|
522
|
-
locale = "en";
|
|
523
|
-
}
|
|
524
|
-
defaults = {
|
|
525
|
-
cols: [],
|
|
526
|
-
rows: [],
|
|
527
|
-
vals: [],
|
|
528
|
-
dataClass: PivotData,
|
|
529
|
-
filter: function() {
|
|
530
|
-
return true;
|
|
531
|
-
},
|
|
532
|
-
aggregator: aggregatorTemplates.count()(),
|
|
533
|
-
aggregatorName: "Count",
|
|
534
|
-
derivedAttributes: {},
|
|
535
|
-
renderer: pivotTableRenderer
|
|
536
|
-
};
|
|
537
|
-
localeStrings = $.extend(true, {}, locales.en.localeStrings, locales[locale].localeStrings);
|
|
538
|
-
localeDefaults = {
|
|
539
|
-
rendererOptions: {
|
|
540
|
-
localeStrings: localeStrings
|
|
541
|
-
},
|
|
542
|
-
localeStrings: localeStrings
|
|
543
|
-
};
|
|
544
|
-
opts = $.extend(true, {}, localeDefaults, $.extend({}, defaults, inputOpts));
|
|
545
|
-
try {
|
|
546
|
-
pivotData = new opts.dataClass(input, opts);
|
|
547
|
-
try {
|
|
548
|
-
result = opts.renderer(pivotData, opts.rendererOptions);
|
|
549
|
-
} catch (error) {
|
|
550
|
-
const genericRenderingError = new GenericRenderingError();
|
|
551
|
-
console.error(genericRenderingError.title);
|
|
552
|
-
throw genericRenderingError;
|
|
553
|
-
}
|
|
554
|
-
} catch (error) {
|
|
555
|
-
if (error instanceof GenericRenderingError) {
|
|
556
|
-
throw error;
|
|
557
|
-
} else {
|
|
558
|
-
const genericComputationalError = new GenericComputationalError();
|
|
559
|
-
console.error(genericComputationalError.title);
|
|
560
|
-
throw genericComputationalError;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
x = this[0];
|
|
564
|
-
while (x.hasChildNodes()) {
|
|
565
|
-
x.removeChild(x.lastChild);
|
|
566
|
-
}
|
|
567
|
-
return this.append(result);
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
/*
|
|
571
|
-
Heatmap post-processing
|
|
572
|
-
*/
|
|
573
|
-
$.fn.heatmap = function(scope, opts) {
|
|
574
|
-
var colorScaleGenerator, heatmapper, i, j, l, n, numCols, numRows, ref, ref1, ref2;
|
|
575
|
-
if (scope == null) {
|
|
576
|
-
scope = "heatmap";
|
|
577
|
-
}
|
|
578
|
-
numRows = this.data("numrows");
|
|
579
|
-
numCols = this.data("numcols");
|
|
580
|
-
colorScaleGenerator = opts != null ? (ref = opts.heatmap) != null ? ref.colorScaleGenerator : void 0 : void 0;
|
|
581
|
-
if (colorScaleGenerator == null) {
|
|
582
|
-
colorScaleGenerator = function(values) {
|
|
583
|
-
var max, min;
|
|
584
|
-
min = Math.min.apply(Math, values);
|
|
585
|
-
max = Math.max.apply(Math, values);
|
|
586
|
-
return function(x) {
|
|
587
|
-
var nonRed;
|
|
588
|
-
nonRed = 255 - Math.round(255 * (x - min) / (max - min));
|
|
589
|
-
return "rgb(255," + nonRed + "," + nonRed + ")";
|
|
590
|
-
};
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
heatmapper = (function(_this) {
|
|
594
|
-
return function(scope) {
|
|
595
|
-
var colorScale, forEachCell, values;
|
|
596
|
-
forEachCell = function(f) {
|
|
597
|
-
return _this.find(scope).each(function() {
|
|
598
|
-
var x;
|
|
599
|
-
x = $(this).data("value");
|
|
600
|
-
if ((x != null) && isFinite(x)) {
|
|
601
|
-
return f(x, $(this));
|
|
602
|
-
}
|
|
603
|
-
});
|
|
604
|
-
};
|
|
605
|
-
values = [];
|
|
606
|
-
forEachCell(function(x) {
|
|
607
|
-
return values.push(x);
|
|
608
|
-
});
|
|
609
|
-
colorScale = colorScaleGenerator(values);
|
|
610
|
-
return forEachCell(function(x, elem) {
|
|
611
|
-
return elem.css("background-color", colorScale(x));
|
|
612
|
-
});
|
|
613
|
-
};
|
|
614
|
-
})(this);
|
|
615
|
-
switch (scope) {
|
|
616
|
-
case "heatmap":
|
|
617
|
-
heatmapper(".pvtVal");
|
|
618
|
-
break;
|
|
619
|
-
case "rowheatmap":
|
|
620
|
-
for (i = l = 0, ref1 = numRows; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {
|
|
621
|
-
heatmapper(".pvtVal.row" + i);
|
|
622
|
-
}
|
|
623
|
-
break;
|
|
624
|
-
case "colheatmap":
|
|
625
|
-
for (j = n = 0, ref2 = numCols; 0 <= ref2 ? n < ref2 : n > ref2; j = 0 <= ref2 ? ++n : --n) {
|
|
626
|
-
heatmapper(".pvtVal.col" + j);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
heatmapper(".pvtTotal.rowTotal");
|
|
630
|
-
heatmapper(".pvtTotal.colTotal");
|
|
631
|
-
return this;
|
|
632
|
-
};
|
|
633
|
-
|
|
634
|
-
/*
|
|
635
|
-
Barchart post-processing
|
|
636
|
-
*/
|
|
637
|
-
return $.fn.barchart = function(opts) {
|
|
638
|
-
var barcharter, i, l, numCols, numRows, ref;
|
|
639
|
-
numRows = this.data("numrows");
|
|
640
|
-
numCols = this.data("numcols");
|
|
641
|
-
barcharter = (function(_this) {
|
|
642
|
-
return function(scope) {
|
|
643
|
-
var forEachCell, max, min, range, scaler, values;
|
|
644
|
-
forEachCell = function(f) {
|
|
645
|
-
return _this.find(scope).each(function() {
|
|
646
|
-
var x;
|
|
647
|
-
x = $(this).data("value");
|
|
648
|
-
if ((x != null) && isFinite(x)) {
|
|
649
|
-
return f(x, $(this));
|
|
650
|
-
}
|
|
651
|
-
});
|
|
652
|
-
};
|
|
653
|
-
values = [];
|
|
654
|
-
forEachCell(function(x) {
|
|
655
|
-
return values.push(x);
|
|
656
|
-
});
|
|
657
|
-
max = Math.max.apply(Math, values);
|
|
658
|
-
if (max < 0) {
|
|
659
|
-
max = 0;
|
|
660
|
-
}
|
|
661
|
-
range = max;
|
|
662
|
-
min = Math.min.apply(Math, values);
|
|
663
|
-
if (min < 0) {
|
|
664
|
-
range = max - min;
|
|
665
|
-
}
|
|
666
|
-
scaler = function(x) {
|
|
667
|
-
return 100 * x / (1.4 * range);
|
|
668
|
-
};
|
|
669
|
-
return forEachCell(function(x, elem) {
|
|
670
|
-
var bBase, bgColor, text, wrapper;
|
|
671
|
-
text = elem.text();
|
|
672
|
-
wrapper = $("<div>").css({
|
|
673
|
-
"position": "relative",
|
|
674
|
-
"height": "55px"
|
|
675
|
-
});
|
|
676
|
-
bgColor = "gray";
|
|
677
|
-
bBase = 0;
|
|
678
|
-
if (min < 0) {
|
|
679
|
-
bBase = scaler(-min);
|
|
680
|
-
}
|
|
681
|
-
if (x < 0) {
|
|
682
|
-
bBase += scaler(x);
|
|
683
|
-
bgColor = "darkred";
|
|
684
|
-
x = -x;
|
|
685
|
-
}
|
|
686
|
-
wrapper.append($("<div>").css({
|
|
687
|
-
"position": "absolute",
|
|
688
|
-
"bottom": bBase + "%",
|
|
689
|
-
"left": 0,
|
|
690
|
-
"right": 0,
|
|
691
|
-
"height": scaler(x) + "%",
|
|
692
|
-
"background-color": bgColor
|
|
693
|
-
}));
|
|
694
|
-
wrapper.append($("<div>").text(text).css({
|
|
695
|
-
"position": "relative",
|
|
696
|
-
"padding-left": "5px",
|
|
697
|
-
"padding-right": "5px"
|
|
698
|
-
}));
|
|
699
|
-
return elem.css({
|
|
700
|
-
"padding": 0,
|
|
701
|
-
"padding-top": "5px",
|
|
702
|
-
"text-align": "center"
|
|
703
|
-
}).html(wrapper);
|
|
704
|
-
});
|
|
705
|
-
};
|
|
706
|
-
})(this);
|
|
707
|
-
for (i = l = 0, ref = numRows; 0 <= ref ? l < ref : l > ref; i = 0 <= ref ? ++l : --l) {
|
|
708
|
-
barcharter(".pvtVal.row" + i);
|
|
709
|
-
}
|
|
710
|
-
barcharter(".pvtTotal.colTotal");
|
|
711
|
-
return this;
|
|
712
|
-
};
|
|
713
|
-
};
|
|
714
|
-
|
|
715
|
-
module.exports = initPivotTable;
|