@datarailsshared/dr_renderer 1.5.19 → 1.5.39
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-renderer-helpers.js +3 -1
- package/src/dr_pivottable.js +22 -30
- package/src/highcharts_renderer.js +6 -30
- package/src/pivottable.js +3 -504
- package/src/smart_queries_helper.js +52 -127
package/package.json
CHANGED
|
@@ -73,6 +73,7 @@ function isShowingEmptyValues(additionOptions) {
|
|
|
73
73
|
return !additionOptions || !additionOptions.chart || additionOptions.chart.dislay_empty_values !== false;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
const DELIMER = ' , '
|
|
76
77
|
const FEATURES = {
|
|
77
78
|
ENABLE_NEW_WIDGET_VALUE_FORMATTING: 'enable_new_widget_value_formatting',
|
|
78
79
|
FORMAT_DATES_AS_OTHER_AXIS_TYPES: 'format_dates_as_other_axis_types',
|
|
@@ -91,5 +92,6 @@ module.exports = {
|
|
|
91
92
|
removeSVGTextCorrection,
|
|
92
93
|
disableLegendInteractionIfRequired,
|
|
93
94
|
isShowingEmptyValues,
|
|
94
|
-
FEATURES
|
|
95
|
+
FEATURES,
|
|
96
|
+
DELIMER
|
|
95
97
|
}
|
package/src/dr_pivottable.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const { DR_SCENARIO } = require('./smart_queries_helper');
|
|
1
|
+
const { DR_SCENARIO, getSqAggregator } = require('./smart_queries_helper');
|
|
2
|
+
const { DELIMER } = require('./dr-renderer-helpers');
|
|
2
3
|
const { TooMuchDataError } = require('./errors');
|
|
3
4
|
|
|
4
5
|
let initDRPivotTable = function($, window, document) {
|
|
@@ -10,13 +11,12 @@ let initDRPivotTable = function($, window, document) {
|
|
|
10
11
|
const newTableColors = ['rgb(127, 196, 255)', 'rgb(200, 243,243)', 'rgb(247, 161, 173)', 'rgb(255, 237, 178)', 'rgb(221, 239, 255)',
|
|
11
12
|
'rgb(171, 216, 255)', 'rgb(174, 231, 220)', 'rgb(227, 255, 236)', 'rgb(162, 215, 227)', 'rgb(223, 239, 236)'];
|
|
12
13
|
|
|
13
|
-
var delim = " , ";
|
|
14
14
|
const useNewUx = document.ReportHippo && document.ReportHippo && document.ReportHippo.user &&
|
|
15
15
|
document.ReportHippo.user.organization.settings && document.ReportHippo.user.organization.settings.use_new_ux;
|
|
16
16
|
// const numberOfRows = 500; // change to activate the handsontable when num of rows bigger then this.
|
|
17
17
|
|
|
18
18
|
const isFlatKeyInPivotKeys = function(keys, flatKey) {
|
|
19
|
-
return keys.some(key => key.join(
|
|
19
|
+
return keys.some(key => key.join(DELIMER) === flatKey);
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
DRPivotData = (function(superClass) {
|
|
@@ -138,7 +138,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
138
138
|
for (k = 0, len = attrs.length; k < len; k++) {
|
|
139
139
|
attr = attrs[k];
|
|
140
140
|
key.push((ref = record[attr]) != null ? ref : "null");
|
|
141
|
-
flatKey = key.join(
|
|
141
|
+
flatKey = key.join(DELIMER);
|
|
142
142
|
if (!totals[flatKey]) {
|
|
143
143
|
totals[flatKey] = getAggregator(key.slice());
|
|
144
144
|
addKey = true;
|
|
@@ -174,7 +174,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
174
174
|
|
|
175
175
|
DRPivotData.prototype.getFlatKey = function(record, attrs) {
|
|
176
176
|
const keys = this.getAttrsKeys(record, attrs);
|
|
177
|
-
return keys.join(
|
|
177
|
+
return keys.join(DELIMER);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
DRPivotData.prototype.processRecord = function(record, isSmartQueriesEnabled) {
|
|
@@ -196,8 +196,8 @@ let initDRPivotTable = function($, window, document) {
|
|
|
196
196
|
const rowKey = this.getAttrsKeys(record, this.rowAttrs);
|
|
197
197
|
const colKey = this.getAttrsKeys(record, this.colAttrs);
|
|
198
198
|
|
|
199
|
-
let flatRowKey = rowKey.join(
|
|
200
|
-
let flatColKey = colKey.join(
|
|
199
|
+
let flatRowKey = rowKey.join(DELIMER);
|
|
200
|
+
let flatColKey = colKey.join(DELIMER);
|
|
201
201
|
|
|
202
202
|
if (this.keysLength === rowKey.length + colKey.length) {
|
|
203
203
|
if (!this.isKeysSortingDoneOnBackendSide && !isFlatKeyInPivotKeys(this.rowKeys, flatRowKey)) {
|
|
@@ -232,8 +232,8 @@ let initDRPivotTable = function($, window, document) {
|
|
|
232
232
|
DRPivotData.prototype.getAggregator = function(rowKey, colKey) {
|
|
233
233
|
var agg, flatColKey, flatRowKey;
|
|
234
234
|
let hebrewMarkRegex = new RegExp(String.fromCharCode(8206), 'g');
|
|
235
|
-
flatRowKey = rowKey.join(
|
|
236
|
-
flatColKey = colKey.join(
|
|
235
|
+
flatRowKey = rowKey.join(DELIMER).replace(hebrewMarkRegex, '');
|
|
236
|
+
flatColKey = colKey.join(DELIMER).replace(hebrewMarkRegex, '');
|
|
237
237
|
if (rowKey.length === 0 && colKey.length === 0) {
|
|
238
238
|
agg = this.allTotal;
|
|
239
239
|
} else if (rowKey.length === 0) {
|
|
@@ -241,7 +241,8 @@ let initDRPivotTable = function($, window, document) {
|
|
|
241
241
|
} else if (colKey.length === 0) {
|
|
242
242
|
agg = this.rowTotals[flatRowKey];
|
|
243
243
|
} else {
|
|
244
|
-
|
|
244
|
+
const sqAgg = this.isSmartQueriesEnabled ? getSqAggregator(this.tree, rowKey, flatColKey) : null;
|
|
245
|
+
agg = sqAgg || this.tree[flatRowKey][flatColKey];
|
|
245
246
|
}
|
|
246
247
|
return agg != null ? agg : {
|
|
247
248
|
value: (function() {
|
|
@@ -880,7 +881,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
880
881
|
descendants: lastCol,
|
|
881
882
|
leaves: 1,
|
|
882
883
|
key: key,
|
|
883
|
-
flatKey: key.join(
|
|
884
|
+
flatKey: key.join(DELIMER)
|
|
884
885
|
};
|
|
885
886
|
headers.push(node);
|
|
886
887
|
rMark[0] = node;
|
|
@@ -900,7 +901,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
900
901
|
descendants: lastCol - c,
|
|
901
902
|
leaves: 1,
|
|
902
903
|
key: key,
|
|
903
|
-
flatKey: key.join(
|
|
904
|
+
flatKey: key.join(DELIMER)
|
|
904
905
|
};
|
|
905
906
|
rMark[c] = node;
|
|
906
907
|
rMark[c - 1].children.push(node);
|
|
@@ -941,7 +942,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
941
942
|
descendants: 0,
|
|
942
943
|
leaves: 0,
|
|
943
944
|
key: key,
|
|
944
|
-
flatKey: key.join(
|
|
945
|
+
flatKey: key.join(DELIMER)
|
|
945
946
|
};
|
|
946
947
|
|
|
947
948
|
headers.push(node);
|
|
@@ -964,7 +965,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
964
965
|
descendants: 0,
|
|
965
966
|
leaves: 0,
|
|
966
967
|
key: key,
|
|
967
|
-
flatKey: key.join(
|
|
968
|
+
flatKey: key.join(DELIMER)
|
|
968
969
|
};
|
|
969
970
|
if (c === 0) {
|
|
970
971
|
headers.push(node);
|
|
@@ -1272,7 +1273,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
1272
1273
|
"rowspan": rowHeader.descendants + 1,
|
|
1273
1274
|
"colspan": colspan
|
|
1274
1275
|
});
|
|
1275
|
-
if (
|
|
1276
|
+
if (pivotData.isSmartQueriesEnabled) {
|
|
1276
1277
|
th.textContent = th.textContent.replace(DR_SCENARIO.Forecast, 'Forecast Smart Query');
|
|
1277
1278
|
}
|
|
1278
1279
|
if (opts.chartOptions.table_options.hide_nulls_in_headers) {
|
|
@@ -1506,8 +1507,9 @@ let initDRPivotTable = function($, window, document) {
|
|
|
1506
1507
|
for (l = 0, len1 = colHeaderCols.length; l < len1; l++) {
|
|
1507
1508
|
colHeader = colHeaderCols[l];
|
|
1508
1509
|
flatColKey = colHeader.flatKey;
|
|
1509
|
-
|
|
1510
|
-
|
|
1510
|
+
const sqAgg = pivotData.isSmartQueriesEnabled && tree ? getSqAggregator(tree, rowHeader.key, flatColKey) : null;
|
|
1511
|
+
if(sqAgg || (tree && tree[flatRowKey] && tree[flatRowKey][flatColKey])){
|
|
1512
|
+
ref8 = sqAgg || tree[flatRowKey][flatColKey]
|
|
1511
1513
|
}
|
|
1512
1514
|
else{
|
|
1513
1515
|
ref8 = null;
|
|
@@ -1522,13 +1524,6 @@ let initDRPivotTable = function($, window, document) {
|
|
|
1522
1524
|
}
|
|
1523
1525
|
};
|
|
1524
1526
|
val = aggregator.value();
|
|
1525
|
-
|
|
1526
|
-
if (opts.chartOptions.isSmartQueriesEnabled && flatRowKey.split(' , ').includes(DR_SCENARIO.Forecast)) {
|
|
1527
|
-
const actualsRow = tree[flatRowKey.replace(DR_SCENARIO.Forecast, DR_SCENARIO.SQ_Actuals)] || {};
|
|
1528
|
-
if (actualsRow && actualsRow[flatColKey]) {
|
|
1529
|
-
val += (actualsRow[flatColKey] && actualsRow[flatColKey].value()) || 0;
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
1527
|
isColSubtotal = colHeader.children.length !== 0;
|
|
1533
1528
|
style = "pvtVal";
|
|
1534
1529
|
if (isColSubtotal) {
|
|
@@ -1571,9 +1566,6 @@ let initDRPivotTable = function($, window, document) {
|
|
|
1571
1566
|
}
|
|
1572
1567
|
|
|
1573
1568
|
val = totalAggregator.value();
|
|
1574
|
-
if (opts.chartOptions.isSmartQueriesEnabled && flatRowKey.split(' , ').includes(DR_SCENARIO.Forecast)) {
|
|
1575
|
-
val += _.get(rowTotals[flatRowKey.replace(DR_SCENARIO.Forecast, DR_SCENARIO.SQ_Actuals)], 'value', () => null)() || 0;
|
|
1576
|
-
}
|
|
1577
1569
|
style = "pvtTotal rowTotal";
|
|
1578
1570
|
if (isRowSubtotal) {
|
|
1579
1571
|
style += " pvtRowSubtotal";
|
|
@@ -1694,7 +1686,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
1694
1686
|
};
|
|
1695
1687
|
removeRowHeaderNullValue = function(h) {
|
|
1696
1688
|
if (opts.chartOptions.table_options.hide_nulls_in_headers) {
|
|
1697
|
-
h.th.innerHTML = h.th.innerHTML.replace('[null]'
|
|
1689
|
+
h.th.innerHTML = h.th.innerHTML.replace('[null]', '');
|
|
1698
1690
|
}
|
|
1699
1691
|
};
|
|
1700
1692
|
hideDescendantCol = function(d) {
|
|
@@ -2354,7 +2346,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
2354
2346
|
}
|
|
2355
2347
|
|
|
2356
2348
|
main = function(rowAttrs, rowKeys, colAttrs, colKeys, pivotData) {
|
|
2357
|
-
if (
|
|
2349
|
+
if (pivotData.isSmartQueriesEnabled) {
|
|
2358
2350
|
rowKeys = rowKeys.filter(rowKey => !rowKey.includes(DR_SCENARIO.SQ_Actuals));
|
|
2359
2351
|
rowKeys = Array.from(
|
|
2360
2352
|
new Set(rowKeys.map(JSON.stringify))
|
|
@@ -2516,7 +2508,7 @@ let initDRPivotTable = function($, window, document) {
|
|
|
2516
2508
|
};
|
|
2517
2509
|
|
|
2518
2510
|
$.pivotUtilities.subtotal_renderers = NovixRenderer;
|
|
2519
|
-
$.pivotUtilities.delim =
|
|
2511
|
+
$.pivotUtilities.delim = DELIMER;
|
|
2520
2512
|
|
|
2521
2513
|
$.pivotUtilities.getFormattedNumber = getFormattedNumber;
|
|
2522
2514
|
$.pivotUtilities.sortDateStrings = sortDateStrings;
|
|
@@ -85,7 +85,7 @@ const CHART_TYPES = {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
const HIGHCHARTS_CONSTANTS = {
|
|
88
|
-
delimer:
|
|
88
|
+
delimer: helpers.DELIMER,
|
|
89
89
|
DRILL_BUTTON_FONT_SIZE: '16px',
|
|
90
90
|
MAX_ROWS_FOR_AUTO_REFRESH: 100000,
|
|
91
91
|
MAX_ROWS_FOR_SHOW_RESULTS: 10000,
|
|
@@ -1274,10 +1274,10 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
1274
1274
|
row_n_keys = pivotData.getRowKeys(),
|
|
1275
1275
|
col_n_keys = pivotData.getColKeys();
|
|
1276
1276
|
const chartType = chartOptions && chartOptions.chart && chartOptions.chart.type ? chartOptions.chart.type : null;
|
|
1277
|
-
const isCombiLineForecastChart = opts.chartOptions.isSmartQueriesEnabled;
|
|
1278
1277
|
const indexOfScenarioCycleFilter = lodash.findIndex(pivotData.rowAttrs, (rowAttr) => rowAttr === 'Scenario Cycle');
|
|
1278
|
+
const withExtraScenarioCycle = pivotData.rowAttrs && row_n_keys[0] && pivotData.rowAttrs.length < row_n_keys[0].length
|
|
1279
1279
|
|
|
1280
|
-
if (isChartTypeSupportedForSmartQuery(chartType) &&
|
|
1280
|
+
if (isChartTypeSupportedForSmartQuery(chartType) && withExtraScenarioCycle && indexOfScenarioCycleFilter > -1) {
|
|
1281
1281
|
const indexOfScenarioFilter = row_n_keys[0].length - 1;
|
|
1282
1282
|
for (let i = 0; i < row_n_keys?.length; i++) {
|
|
1283
1283
|
row_n_keys[i].splice(indexOfScenarioFilter, 1);
|
|
@@ -1454,7 +1454,7 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
1454
1454
|
col_n_keys.forEach(columnKey => {
|
|
1455
1455
|
let totalKey = columnKey;
|
|
1456
1456
|
if (lodash.isArray(columnKey)) {
|
|
1457
|
-
totalKey = totalKey.join(
|
|
1457
|
+
totalKey = totalKey.join(helpers.DELIMER);
|
|
1458
1458
|
}
|
|
1459
1459
|
const value = pivotData.colTotals[totalKey] ? pivotData.colTotals[totalKey].value() : 0;
|
|
1460
1460
|
newSeries.data.push(value);
|
|
@@ -1466,26 +1466,10 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
1466
1466
|
chart_series = chart_series.concat(trendSerieses);
|
|
1467
1467
|
|
|
1468
1468
|
highchartsRenderer.moveSeriesToSecondYAxisIfNeeded(chart_series, pivotData, chartOptions, additionOptions, opts, opts.total && opts.totalSeriesSettings && opts.totalSeriesSettings.secondaryAxis);
|
|
1469
|
-
const smartQuerySeries = isChartTypeSupportedForSmartQuery(chartType)
|
|
1470
|
-
? smartQueriesHelper.createSingleDataSeriesForForecast(chart_series, opts.chartOptions, pivotData, isCombiLineForecastChart)
|
|
1471
|
-
: null;
|
|
1472
1469
|
|
|
1473
|
-
if (
|
|
1474
|
-
if (chart_series.length > 1) {
|
|
1475
|
-
if (isCombiLineForecastChart) {
|
|
1476
|
-
chart_series = smartQuerySeries;
|
|
1477
|
-
} else {
|
|
1478
|
-
lodash.remove(chart_series, s =>
|
|
1479
|
-
(s.name && lodash.includes(s.name, 'SQ_Actuals')) || s.name === 'Forecast'
|
|
1480
|
-
);
|
|
1481
|
-
chart_series.push(smartQuerySeries);
|
|
1482
|
-
}
|
|
1483
|
-
} else {
|
|
1484
|
-
chart_series = [smartQuerySeries];
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1470
|
+
if (!opts.chartOptions || !opts.chartOptions.chart || !opts.chartOptions.chart.smart_query || !pivotData.isSmartQueriesEnabled) return chart_series;
|
|
1487
1471
|
|
|
1488
|
-
return chart_series
|
|
1472
|
+
return smartQueriesHelper.handleForecastSeries(chart_series, opts.chartOptions, pivotData)
|
|
1489
1473
|
};
|
|
1490
1474
|
|
|
1491
1475
|
highchartsRenderer.ptCreateColumnSeries = function (pivotData, colors, onlyNumbers, isUniqueVals, isNotDrilldown, additionOptions, opts, chartOptions, chartType) {
|
|
@@ -4856,7 +4840,6 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
4856
4840
|
dateValuesDictionary: pivotOptions ? pivotOptions.dateValuesDictionary : null,
|
|
4857
4841
|
keysObject: pivotOptions ? pivotOptions.keysObject : null,
|
|
4858
4842
|
isDrillDownDisabled: pivotOptions ? pivotOptions.isDrillDownDisabled : false,
|
|
4859
|
-
pivotUiFnRemoved: pivotOptions ? pivotOptions.pivotUiFnRemoved : false,
|
|
4860
4843
|
};
|
|
4861
4844
|
|
|
4862
4845
|
if (!subopts.rendererOptions) {
|
|
@@ -10099,13 +10082,6 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
|
|
|
10099
10082
|
e.point = lodash.cloneDeep(e.point);
|
|
10100
10083
|
e.point.name = e.point.initialName;
|
|
10101
10084
|
e.point.series.name = lodash.get(e.point.series, 'userOptions.initialName', e.point.series.name);
|
|
10102
|
-
const seriesData = lodash.get(e.point.series, 'userOptions.data');
|
|
10103
|
-
const initialSeriesName = seriesData
|
|
10104
|
-
? lodash.find(seriesData, obj => obj.name === e.point.name)
|
|
10105
|
-
: null;
|
|
10106
|
-
if (initialSeriesName && initialSeriesName.type && ['SQ_Actuals', 'Forecast'].includes(initialSeriesName.type)) {
|
|
10107
|
-
e.point.series.name = 'Forecast';
|
|
10108
|
-
}
|
|
10109
10085
|
lodash.set(e, 'point.category.userOptions', e.point.initialName.toString().split(highchartsRenderer.delimer));
|
|
10110
10086
|
}
|
|
10111
10087
|
|
package/src/pivottable.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
1
2
|
const helpers = require('./dr-renderer-helpers');
|
|
3
|
+
const { DR_SCENARIO } = require('./smart_queries_helper');
|
|
2
4
|
const { GenericRenderingError, GenericComputationalError} = require('./errors');
|
|
3
5
|
|
|
4
6
|
// from pivottable@2.23.0
|
|
@@ -641,7 +643,7 @@ let initPivotTable = function($, window, document) {
|
|
|
641
643
|
this.filter = (ref9 = opts.filter) != null ? ref9 : (function() {
|
|
642
644
|
return true;
|
|
643
645
|
});
|
|
644
|
-
this.isSmartQueriesEnabled =
|
|
646
|
+
this.isSmartQueriesEnabled = _.some(input, item => item.Scenario === DR_SCENARIO.SQ_Actuals);
|
|
645
647
|
this.tree = {};
|
|
646
648
|
|
|
647
649
|
this.isKeysSortingDoneOnBackendSide = opts.keysObject && typeof opts.keysObject === 'object' && helpers.backendSortingKeysAreNotEmpty(opts.keysObject);
|
|
@@ -666,7 +668,6 @@ let initPivotTable = function($, window, document) {
|
|
|
666
668
|
this.getFormattedColKeys = (keys) => opts.getFormattedColKeys(this, keys);
|
|
667
669
|
this.getFormattedRowKeys = (keys) => opts.getFormattedRowKeys(this, keys);
|
|
668
670
|
this.isDrillDownDisabled = opts.isDrillDownDisabled;
|
|
669
|
-
this.pivotUiFnRemoved = opts.pivotUiFnRemoved;
|
|
670
671
|
|
|
671
672
|
PivotData.forEachRecord(this.input, this.derivedAttributes, (function(_this) {
|
|
672
673
|
return function(record) {
|
|
@@ -1212,508 +1213,6 @@ let initPivotTable = function($, window, document) {
|
|
|
1212
1213
|
return this.append(result);
|
|
1213
1214
|
};
|
|
1214
1215
|
|
|
1215
|
-
/*
|
|
1216
|
-
Pivot Table UI: calls Pivot Table core above with options set by user
|
|
1217
|
-
*/
|
|
1218
|
-
$.fn.pivotUI = function(input, inputOpts, overwrite, locale) {
|
|
1219
|
-
if (!this.pivotUiFnRemoved) {
|
|
1220
|
-
var a, aggregator, attr, attrLength, attrValues, c, colOrderArrow, defaults, e, existingOpts, fn1, i, initialRender, l, len1, len2, len3, localeDefaults, localeStrings, materializedInput, n, o, opts, ordering, pivotTable, recordsProcessed, ref, ref1, ref2, ref3, refresh, refreshDelayed, renderer, rendererControl, rowOrderArrow, shownAttributes, shownInAggregators, shownInDragDrop, tr1, tr2, uiTable, unused, unusedAttrsVerticalAutoCutoff, unusedAttrsVerticalAutoOverride, x;
|
|
1221
|
-
if (overwrite == null) {
|
|
1222
|
-
overwrite = false;
|
|
1223
|
-
}
|
|
1224
|
-
if (locale == null) {
|
|
1225
|
-
locale = "en";
|
|
1226
|
-
}
|
|
1227
|
-
if (locales[locale] == null) {
|
|
1228
|
-
locale = "en";
|
|
1229
|
-
}
|
|
1230
|
-
defaults = {
|
|
1231
|
-
derivedAttributes: {},
|
|
1232
|
-
aggregators: locales[locale].aggregators,
|
|
1233
|
-
renderers: locales[locale].renderers,
|
|
1234
|
-
hiddenAttributes: [],
|
|
1235
|
-
hiddenFromAggregators: [],
|
|
1236
|
-
hiddenFromDragDrop: [],
|
|
1237
|
-
menuLimit: 500,
|
|
1238
|
-
cols: [],
|
|
1239
|
-
rows: [],
|
|
1240
|
-
vals: [],
|
|
1241
|
-
rowOrder: "key_a_to_z",
|
|
1242
|
-
colOrder: "key_a_to_z",
|
|
1243
|
-
dataClass: PivotData,
|
|
1244
|
-
exclusions: {},
|
|
1245
|
-
inclusions: {},
|
|
1246
|
-
unusedAttrsVertical: 85,
|
|
1247
|
-
autoSortUnusedAttrs: false,
|
|
1248
|
-
onRefresh: null,
|
|
1249
|
-
showUI: true,
|
|
1250
|
-
filter: function() {
|
|
1251
|
-
return true;
|
|
1252
|
-
},
|
|
1253
|
-
sorters: {}
|
|
1254
|
-
};
|
|
1255
|
-
localeStrings = $.extend(true, {}, locales.en.localeStrings, locales[locale].localeStrings);
|
|
1256
|
-
localeDefaults = {
|
|
1257
|
-
rendererOptions: {
|
|
1258
|
-
localeStrings: localeStrings
|
|
1259
|
-
},
|
|
1260
|
-
localeStrings: localeStrings
|
|
1261
|
-
};
|
|
1262
|
-
existingOpts = this.data("pivotUIOptions");
|
|
1263
|
-
if ((existingOpts == null) || overwrite) {
|
|
1264
|
-
opts = $.extend(true, {}, localeDefaults, $.extend({}, defaults, inputOpts));
|
|
1265
|
-
} else {
|
|
1266
|
-
opts = existingOpts;
|
|
1267
|
-
}
|
|
1268
|
-
try {
|
|
1269
|
-
attrValues = {};
|
|
1270
|
-
materializedInput = [];
|
|
1271
|
-
recordsProcessed = 0;
|
|
1272
|
-
PivotData.forEachRecord(input, opts.derivedAttributes, function(record) {
|
|
1273
|
-
var attr, base, ref, value;
|
|
1274
|
-
if (!opts.filter(record)) {
|
|
1275
|
-
return;
|
|
1276
|
-
}
|
|
1277
|
-
materializedInput.push(record);
|
|
1278
|
-
for (attr in record) {
|
|
1279
|
-
if (!hasProp.call(record, attr)) continue;
|
|
1280
|
-
if (attrValues[attr] == null) {
|
|
1281
|
-
attrValues[attr] = {};
|
|
1282
|
-
if (recordsProcessed > 0) {
|
|
1283
|
-
attrValues[attr]["null"] = recordsProcessed;
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
for (attr in attrValues) {
|
|
1288
|
-
value = (ref = record[attr]) != null ? ref : "null";
|
|
1289
|
-
if ((base = attrValues[attr])[value] == null) {
|
|
1290
|
-
base[value] = 0;
|
|
1291
|
-
}
|
|
1292
|
-
attrValues[attr][value]++;
|
|
1293
|
-
}
|
|
1294
|
-
return recordsProcessed++;
|
|
1295
|
-
});
|
|
1296
|
-
uiTable = $("<table>", {
|
|
1297
|
-
"class": "pvtUi"
|
|
1298
|
-
}).attr("cellpadding", 5);
|
|
1299
|
-
rendererControl = $("<td>").addClass("pvtUiCell");
|
|
1300
|
-
renderer = $("<select>").addClass('pvtRenderer').appendTo(rendererControl).bind("change", function() {
|
|
1301
|
-
return refresh();
|
|
1302
|
-
});
|
|
1303
|
-
ref = opts.renderers;
|
|
1304
|
-
for (x in ref) {
|
|
1305
|
-
if (!hasProp.call(ref, x)) continue;
|
|
1306
|
-
$("<option>").val(x).html(x).appendTo(renderer);
|
|
1307
|
-
}
|
|
1308
|
-
unused = $("<td>").addClass('pvtAxisContainer pvtUnused pvtUiCell');
|
|
1309
|
-
shownAttributes = (function() {
|
|
1310
|
-
var results;
|
|
1311
|
-
results = [];
|
|
1312
|
-
for (a in attrValues) {
|
|
1313
|
-
if (indexOf.call(opts.hiddenAttributes, a) < 0) {
|
|
1314
|
-
results.push(a);
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
return results;
|
|
1318
|
-
})();
|
|
1319
|
-
shownInAggregators = (function() {
|
|
1320
|
-
var l, len1, results;
|
|
1321
|
-
results = [];
|
|
1322
|
-
for (l = 0, len1 = shownAttributes.length; l < len1; l++) {
|
|
1323
|
-
c = shownAttributes[l];
|
|
1324
|
-
if (indexOf.call(opts.hiddenFromAggregators, c) < 0) {
|
|
1325
|
-
results.push(c);
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
return results;
|
|
1329
|
-
})();
|
|
1330
|
-
shownInDragDrop = (function() {
|
|
1331
|
-
var l, len1, results;
|
|
1332
|
-
results = [];
|
|
1333
|
-
for (l = 0, len1 = shownAttributes.length; l < len1; l++) {
|
|
1334
|
-
c = shownAttributes[l];
|
|
1335
|
-
if (indexOf.call(opts.hiddenFromDragDrop, c) < 0) {
|
|
1336
|
-
results.push(c);
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
return results;
|
|
1340
|
-
})();
|
|
1341
|
-
unusedAttrsVerticalAutoOverride = false;
|
|
1342
|
-
if (opts.unusedAttrsVertical === "auto") {
|
|
1343
|
-
unusedAttrsVerticalAutoCutoff = 120;
|
|
1344
|
-
} else {
|
|
1345
|
-
unusedAttrsVerticalAutoCutoff = parseInt(opts.unusedAttrsVertical);
|
|
1346
|
-
}
|
|
1347
|
-
if (!isNaN(unusedAttrsVerticalAutoCutoff)) {
|
|
1348
|
-
attrLength = 0;
|
|
1349
|
-
for (l = 0, len1 = shownInDragDrop.length; l < len1; l++) {
|
|
1350
|
-
a = shownInDragDrop[l];
|
|
1351
|
-
attrLength += a.length;
|
|
1352
|
-
}
|
|
1353
|
-
unusedAttrsVerticalAutoOverride = attrLength > unusedAttrsVerticalAutoCutoff;
|
|
1354
|
-
}
|
|
1355
|
-
if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
|
|
1356
|
-
unused.addClass('pvtVertList');
|
|
1357
|
-
} else {
|
|
1358
|
-
unused.addClass('pvtHorizList');
|
|
1359
|
-
}
|
|
1360
|
-
fn1 = function(attr) {
|
|
1361
|
-
var attrElem, checkContainer, closeFilterBox, controls, filterItem, filterItemExcluded, finalButtons, hasExcludedItem, len2, n, placeholder, ref1, sorter, triangleLink, v, value, valueCount, valueList, values;
|
|
1362
|
-
values = (function() {
|
|
1363
|
-
var results;
|
|
1364
|
-
results = [];
|
|
1365
|
-
for (v in attrValues[attr]) {
|
|
1366
|
-
results.push(v);
|
|
1367
|
-
}
|
|
1368
|
-
return results;
|
|
1369
|
-
})();
|
|
1370
|
-
hasExcludedItem = false;
|
|
1371
|
-
valueList = $("<div>").addClass('pvtFilterBox').hide();
|
|
1372
|
-
valueList.append($("<h4>").append($("<span>").text(attr), $("<span>").addClass("count").text("(" + values.length + ")")));
|
|
1373
|
-
if (values.length > opts.menuLimit) {
|
|
1374
|
-
valueList.append($("<p>").html(opts.localeStrings.tooMany));
|
|
1375
|
-
} else {
|
|
1376
|
-
if (values.length > 5) {
|
|
1377
|
-
controls = $("<p>").appendTo(valueList);
|
|
1378
|
-
sorter = getSort(opts.sorters, attr);
|
|
1379
|
-
placeholder = opts.localeStrings.filterResults;
|
|
1380
|
-
$("<input>", {
|
|
1381
|
-
type: "text"
|
|
1382
|
-
}).appendTo(controls).attr({
|
|
1383
|
-
placeholder: placeholder,
|
|
1384
|
-
"class": "pvtSearch"
|
|
1385
|
-
}).bind("keyup", function() {
|
|
1386
|
-
var accept, accept_gen, filter;
|
|
1387
|
-
filter = $(this).val().toLowerCase().trim();
|
|
1388
|
-
accept_gen = function(prefix, accepted) {
|
|
1389
|
-
return function(v) {
|
|
1390
|
-
var real_filter, ref1;
|
|
1391
|
-
real_filter = filter.substring(prefix.length).trim();
|
|
1392
|
-
if (real_filter.length === 0) {
|
|
1393
|
-
return true;
|
|
1394
|
-
}
|
|
1395
|
-
return ref1 = Math.sign(sorter(v.toLowerCase(), real_filter)), indexOf.call(accepted, ref1) >= 0;
|
|
1396
|
-
};
|
|
1397
|
-
};
|
|
1398
|
-
accept = filter.indexOf(">=") === 0 ? accept_gen(">=", [1, 0]) : filter.indexOf("<=") === 0 ? accept_gen("<=", [-1, 0]) : filter.indexOf(">") === 0 ? accept_gen(">", [1]) : filter.indexOf("<") === 0 ? accept_gen("<", [-1]) : filter.indexOf("~") === 0 ? function(v) {
|
|
1399
|
-
if (filter.substring(1).trim().length === 0) {
|
|
1400
|
-
return true;
|
|
1401
|
-
}
|
|
1402
|
-
return v.toLowerCase().match(filter.substring(1));
|
|
1403
|
-
} : function(v) {
|
|
1404
|
-
return v.toLowerCase().indexOf(filter) !== -1;
|
|
1405
|
-
};
|
|
1406
|
-
return valueList.find('.pvtCheckContainer p label span.value').each(function() {
|
|
1407
|
-
if (accept($(this).text())) {
|
|
1408
|
-
return $(this).parent().parent().show();
|
|
1409
|
-
} else {
|
|
1410
|
-
return $(this).parent().parent().hide();
|
|
1411
|
-
}
|
|
1412
|
-
});
|
|
1413
|
-
});
|
|
1414
|
-
controls.append($("<br>"));
|
|
1415
|
-
$("<button>", {
|
|
1416
|
-
type: "button"
|
|
1417
|
-
}).appendTo(controls).html(opts.localeStrings.selectAll).bind("click", function() {
|
|
1418
|
-
valueList.find("input:visible:not(:checked)").prop("checked", true).toggleClass("changed");
|
|
1419
|
-
return false;
|
|
1420
|
-
});
|
|
1421
|
-
$("<button>", {
|
|
1422
|
-
type: "button"
|
|
1423
|
-
}).appendTo(controls).html(opts.localeStrings.selectNone).bind("click", function() {
|
|
1424
|
-
valueList.find("input:visible:checked").prop("checked", false).toggleClass("changed");
|
|
1425
|
-
return false;
|
|
1426
|
-
});
|
|
1427
|
-
}
|
|
1428
|
-
checkContainer = $("<div>").addClass("pvtCheckContainer").appendTo(valueList);
|
|
1429
|
-
ref1 = values.sort(getSort(opts.sorters, attr));
|
|
1430
|
-
for (n = 0, len2 = ref1.length; n < len2; n++) {
|
|
1431
|
-
value = ref1[n];
|
|
1432
|
-
valueCount = attrValues[attr][value];
|
|
1433
|
-
filterItem = $("<label>");
|
|
1434
|
-
filterItemExcluded = false;
|
|
1435
|
-
if (opts.inclusions[attr]) {
|
|
1436
|
-
filterItemExcluded = (indexOf.call(opts.inclusions[attr], value) < 0);
|
|
1437
|
-
} else if (opts.exclusions[attr]) {
|
|
1438
|
-
filterItemExcluded = (indexOf.call(opts.exclusions[attr], value) >= 0);
|
|
1439
|
-
}
|
|
1440
|
-
hasExcludedItem || (hasExcludedItem = filterItemExcluded);
|
|
1441
|
-
$("<input>").attr("type", "checkbox").addClass('pvtFilter').attr("checked", !filterItemExcluded).data("filter", [attr, value]).appendTo(filterItem).bind("change", function() {
|
|
1442
|
-
return $(this).toggleClass("changed");
|
|
1443
|
-
});
|
|
1444
|
-
filterItem.append($("<span>").addClass("value").text(value));
|
|
1445
|
-
filterItem.append($("<span>").addClass("count").text("(" + valueCount + ")"));
|
|
1446
|
-
checkContainer.append($("<p>").append(filterItem));
|
|
1447
|
-
}
|
|
1448
|
-
}
|
|
1449
|
-
closeFilterBox = function() {
|
|
1450
|
-
if (valueList.find("[type='checkbox']").length > valueList.find("[type='checkbox']:checked").length) {
|
|
1451
|
-
attrElem.addClass("pvtFilteredAttribute");
|
|
1452
|
-
} else {
|
|
1453
|
-
attrElem.removeClass("pvtFilteredAttribute");
|
|
1454
|
-
}
|
|
1455
|
-
valueList.find('.pvtSearch').val('');
|
|
1456
|
-
valueList.find('.pvtCheckContainer p').show();
|
|
1457
|
-
return valueList.hide();
|
|
1458
|
-
};
|
|
1459
|
-
finalButtons = $("<p>").appendTo(valueList);
|
|
1460
|
-
if (values.length <= opts.menuLimit) {
|
|
1461
|
-
$("<button>", {
|
|
1462
|
-
type: "button"
|
|
1463
|
-
}).text(opts.localeStrings.apply).appendTo(finalButtons).bind("click", function() {
|
|
1464
|
-
if (valueList.find(".changed").removeClass("changed").length) {
|
|
1465
|
-
refresh();
|
|
1466
|
-
}
|
|
1467
|
-
return closeFilterBox();
|
|
1468
|
-
});
|
|
1469
|
-
}
|
|
1470
|
-
$("<button>", {
|
|
1471
|
-
type: "button"
|
|
1472
|
-
}).text(opts.localeStrings.cancel).appendTo(finalButtons).bind("click", function() {
|
|
1473
|
-
valueList.find(".changed:checked").removeClass("changed").prop("checked", false);
|
|
1474
|
-
valueList.find(".changed:not(:checked)").removeClass("changed").prop("checked", true);
|
|
1475
|
-
return closeFilterBox();
|
|
1476
|
-
});
|
|
1477
|
-
triangleLink = $("<span>").addClass('pvtTriangle').html(" ▾").bind("click", function(e) {
|
|
1478
|
-
var left, ref2, top;
|
|
1479
|
-
ref2 = $(e.currentTarget).position(), left = ref2.left, top = ref2.top;
|
|
1480
|
-
return valueList.css({
|
|
1481
|
-
left: left + 10,
|
|
1482
|
-
top: top + 10
|
|
1483
|
-
}).show();
|
|
1484
|
-
});
|
|
1485
|
-
attrElem = $("<li>").addClass("axis_" + i).append($("<span>").addClass('pvtAttr').text(attr).data("attrName", attr).append(triangleLink));
|
|
1486
|
-
if (hasExcludedItem) {
|
|
1487
|
-
attrElem.addClass('pvtFilteredAttribute');
|
|
1488
|
-
}
|
|
1489
|
-
return unused.append(attrElem).append(valueList);
|
|
1490
|
-
};
|
|
1491
|
-
for (i in shownInDragDrop) {
|
|
1492
|
-
if (!hasProp.call(shownInDragDrop, i)) continue;
|
|
1493
|
-
attr = shownInDragDrop[i];
|
|
1494
|
-
fn1(attr);
|
|
1495
|
-
}
|
|
1496
|
-
tr1 = $("<tr>").appendTo(uiTable);
|
|
1497
|
-
aggregator = $("<select>").addClass('pvtAggregator').bind("change", function() {
|
|
1498
|
-
return refresh();
|
|
1499
|
-
});
|
|
1500
|
-
ref1 = opts.aggregators;
|
|
1501
|
-
for (x in ref1) {
|
|
1502
|
-
if (!hasProp.call(ref1, x)) continue;
|
|
1503
|
-
aggregator.append($("<option>").val(x).html(x));
|
|
1504
|
-
}
|
|
1505
|
-
ordering = {
|
|
1506
|
-
key_a_to_z: {
|
|
1507
|
-
rowSymbol: "↕",
|
|
1508
|
-
colSymbol: "↔",
|
|
1509
|
-
next: "value_a_to_z"
|
|
1510
|
-
},
|
|
1511
|
-
value_a_to_z: {
|
|
1512
|
-
rowSymbol: "↓",
|
|
1513
|
-
colSymbol: "→",
|
|
1514
|
-
next: "value_z_to_a"
|
|
1515
|
-
},
|
|
1516
|
-
value_z_to_a: {
|
|
1517
|
-
rowSymbol: "↑",
|
|
1518
|
-
colSymbol: "←",
|
|
1519
|
-
next: "key_a_to_z"
|
|
1520
|
-
}
|
|
1521
|
-
};
|
|
1522
|
-
rowOrderArrow = $("<a>", {
|
|
1523
|
-
role: "button"
|
|
1524
|
-
}).addClass("pvtRowOrder").data("order", opts.rowOrder).html(ordering[opts.rowOrder].rowSymbol).bind("click", function() {
|
|
1525
|
-
$(this).data("order", ordering[$(this).data("order")].next);
|
|
1526
|
-
$(this).html(ordering[$(this).data("order")].rowSymbol);
|
|
1527
|
-
return refresh();
|
|
1528
|
-
});
|
|
1529
|
-
colOrderArrow = $("<a>", {
|
|
1530
|
-
role: "button"
|
|
1531
|
-
}).addClass("pvtColOrder").data("order", opts.colOrder).html(ordering[opts.colOrder].colSymbol).bind("click", function() {
|
|
1532
|
-
$(this).data("order", ordering[$(this).data("order")].next);
|
|
1533
|
-
$(this).html(ordering[$(this).data("order")].colSymbol);
|
|
1534
|
-
return refresh();
|
|
1535
|
-
});
|
|
1536
|
-
$("<td>").addClass('pvtVals pvtUiCell').appendTo(tr1).append(aggregator).append(rowOrderArrow).append(colOrderArrow).append($("<br>"));
|
|
1537
|
-
$("<td>").addClass('pvtAxisContainer pvtHorizList pvtCols pvtUiCell').appendTo(tr1);
|
|
1538
|
-
tr2 = $("<tr>").appendTo(uiTable);
|
|
1539
|
-
tr2.append($("<td>").addClass('pvtAxisContainer pvtRows pvtUiCell').attr("valign", "top"));
|
|
1540
|
-
pivotTable = $("<td>").attr("valign", "top").addClass('pvtRendererArea').appendTo(tr2);
|
|
1541
|
-
if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
|
|
1542
|
-
uiTable.find('tr:nth-child(1)').prepend(rendererControl);
|
|
1543
|
-
uiTable.find('tr:nth-child(2)').prepend(unused);
|
|
1544
|
-
} else {
|
|
1545
|
-
uiTable.prepend($("<tr>").append(rendererControl).append(unused));
|
|
1546
|
-
}
|
|
1547
|
-
this.html(uiTable);
|
|
1548
|
-
ref2 = opts.cols;
|
|
1549
|
-
for (n = 0, len2 = ref2.length; n < len2; n++) {
|
|
1550
|
-
x = ref2[n];
|
|
1551
|
-
this.find(".pvtCols").append(this.find(".axis_" + ($.inArray(x, shownInDragDrop))));
|
|
1552
|
-
}
|
|
1553
|
-
ref3 = opts.rows;
|
|
1554
|
-
for (o = 0, len3 = ref3.length; o < len3; o++) {
|
|
1555
|
-
x = ref3[o];
|
|
1556
|
-
this.find(".pvtRows").append(this.find(".axis_" + ($.inArray(x, shownInDragDrop))));
|
|
1557
|
-
}
|
|
1558
|
-
if (opts.aggregatorName != null) {
|
|
1559
|
-
this.find(".pvtAggregator").val(opts.aggregatorName);
|
|
1560
|
-
}
|
|
1561
|
-
if (opts.rendererName != null) {
|
|
1562
|
-
this.find(".pvtRenderer").val(opts.rendererName);
|
|
1563
|
-
}
|
|
1564
|
-
if (!opts.showUI) {
|
|
1565
|
-
this.find(".pvtUiCell").hide();
|
|
1566
|
-
}
|
|
1567
|
-
initialRender = true;
|
|
1568
|
-
refreshDelayed = (function(_this) {
|
|
1569
|
-
return function() {
|
|
1570
|
-
var exclusions, inclusions, len4, newDropdown, numInputsToProcess, pivotUIOptions, pvtVals, ref4, ref5, subopts, t, u, unusedAttrsContainer, vals;
|
|
1571
|
-
subopts = {
|
|
1572
|
-
derivedAttributes: opts.derivedAttributes,
|
|
1573
|
-
localeStrings: opts.localeStrings,
|
|
1574
|
-
rendererOptions: opts.rendererOptions,
|
|
1575
|
-
sorters: opts.sorters,
|
|
1576
|
-
cols: [],
|
|
1577
|
-
rows: [],
|
|
1578
|
-
dataClass: opts.dataClass
|
|
1579
|
-
};
|
|
1580
|
-
numInputsToProcess = (ref4 = opts.aggregators[aggregator.val()]([])().numInputs) != null ? ref4 : 0;
|
|
1581
|
-
vals = [];
|
|
1582
|
-
_this.find(".pvtRows li span.pvtAttr").each(function() {
|
|
1583
|
-
return subopts.rows.push($(this).data("attrName"));
|
|
1584
|
-
});
|
|
1585
|
-
_this.find(".pvtCols li span.pvtAttr").each(function() {
|
|
1586
|
-
return subopts.cols.push($(this).data("attrName"));
|
|
1587
|
-
});
|
|
1588
|
-
_this.find(".pvtVals select.pvtAttrDropdown").each(function() {
|
|
1589
|
-
if (numInputsToProcess === 0) {
|
|
1590
|
-
return $(this).remove();
|
|
1591
|
-
} else {
|
|
1592
|
-
numInputsToProcess--;
|
|
1593
|
-
if ($(this).val() !== "") {
|
|
1594
|
-
return vals.push($(this).val());
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
});
|
|
1598
|
-
if (numInputsToProcess !== 0) {
|
|
1599
|
-
pvtVals = _this.find(".pvtVals");
|
|
1600
|
-
for (x = t = 0, ref5 = numInputsToProcess; 0 <= ref5 ? t < ref5 : t > ref5; x = 0 <= ref5 ? ++t : --t) {
|
|
1601
|
-
newDropdown = $("<select>").addClass('pvtAttrDropdown').append($("<option>")).bind("change", function() {
|
|
1602
|
-
return refresh();
|
|
1603
|
-
});
|
|
1604
|
-
for (u = 0, len4 = shownInAggregators.length; u < len4; u++) {
|
|
1605
|
-
attr = shownInAggregators[u];
|
|
1606
|
-
newDropdown.append($("<option>").val(attr).text(attr));
|
|
1607
|
-
}
|
|
1608
|
-
pvtVals.append(newDropdown);
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1611
|
-
if (initialRender) {
|
|
1612
|
-
vals = opts.vals;
|
|
1613
|
-
i = 0;
|
|
1614
|
-
_this.find(".pvtVals select.pvtAttrDropdown").each(function() {
|
|
1615
|
-
$(this).val(vals[i]);
|
|
1616
|
-
return i++;
|
|
1617
|
-
});
|
|
1618
|
-
initialRender = false;
|
|
1619
|
-
}
|
|
1620
|
-
subopts.aggregatorName = aggregator.val();
|
|
1621
|
-
subopts.vals = vals;
|
|
1622
|
-
subopts.aggregator = opts.aggregators[aggregator.val()](vals);
|
|
1623
|
-
subopts.renderer = opts.renderers[renderer.val()];
|
|
1624
|
-
subopts.rowOrder = rowOrderArrow.data("order");
|
|
1625
|
-
subopts.colOrder = colOrderArrow.data("order");
|
|
1626
|
-
exclusions = {};
|
|
1627
|
-
_this.find('input.pvtFilter').not(':checked').each(function() {
|
|
1628
|
-
var filter;
|
|
1629
|
-
filter = $(this).data("filter");
|
|
1630
|
-
if (exclusions[filter[0]] != null) {
|
|
1631
|
-
return exclusions[filter[0]].push(filter[1]);
|
|
1632
|
-
} else {
|
|
1633
|
-
return exclusions[filter[0]] = [filter[1]];
|
|
1634
|
-
}
|
|
1635
|
-
});
|
|
1636
|
-
inclusions = {};
|
|
1637
|
-
_this.find('input.pvtFilter:checked').each(function() {
|
|
1638
|
-
var filter;
|
|
1639
|
-
filter = $(this).data("filter");
|
|
1640
|
-
if (exclusions[filter[0]] != null) {
|
|
1641
|
-
if (inclusions[filter[0]] != null) {
|
|
1642
|
-
return inclusions[filter[0]].push(filter[1]);
|
|
1643
|
-
} else {
|
|
1644
|
-
return inclusions[filter[0]] = [filter[1]];
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
});
|
|
1648
|
-
subopts.filter = function(record) {
|
|
1649
|
-
var excludedItems, k, ref6, ref7;
|
|
1650
|
-
if (!opts.filter(record)) {
|
|
1651
|
-
return false;
|
|
1652
|
-
}
|
|
1653
|
-
for (k in exclusions) {
|
|
1654
|
-
excludedItems = exclusions[k];
|
|
1655
|
-
if (ref6 = "" + ((ref7 = record[k]) != null ? ref7 : 'null'), indexOf.call(excludedItems, ref6) >= 0) {
|
|
1656
|
-
return false;
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
return true;
|
|
1660
|
-
};
|
|
1661
|
-
pivotTable.pivot(materializedInput, subopts);
|
|
1662
|
-
pivotUIOptions = $.extend({}, opts, {
|
|
1663
|
-
cols: subopts.cols,
|
|
1664
|
-
rows: subopts.rows,
|
|
1665
|
-
colOrder: subopts.colOrder,
|
|
1666
|
-
rowOrder: subopts.rowOrder,
|
|
1667
|
-
vals: vals,
|
|
1668
|
-
exclusions: exclusions,
|
|
1669
|
-
inclusions: inclusions,
|
|
1670
|
-
inclusionsInfo: inclusions,
|
|
1671
|
-
aggregatorName: aggregator.val(),
|
|
1672
|
-
rendererName: renderer.val()
|
|
1673
|
-
});
|
|
1674
|
-
_this.data("pivotUIOptions", pivotUIOptions);
|
|
1675
|
-
if (opts.autoSortUnusedAttrs) {
|
|
1676
|
-
unusedAttrsContainer = _this.find("td.pvtUnused.pvtAxisContainer");
|
|
1677
|
-
$(unusedAttrsContainer).children("li").sort(function(a, b) {
|
|
1678
|
-
return naturalSort($(a).text(), $(b).text());
|
|
1679
|
-
}).appendTo(unusedAttrsContainer);
|
|
1680
|
-
}
|
|
1681
|
-
pivotTable.css("opacity", 1);
|
|
1682
|
-
if (opts.onRefresh != null) {
|
|
1683
|
-
return opts.onRefresh(pivotUIOptions);
|
|
1684
|
-
}
|
|
1685
|
-
};
|
|
1686
|
-
})(this);
|
|
1687
|
-
refresh = (function(_this) {
|
|
1688
|
-
return function() {
|
|
1689
|
-
pivotTable.css("opacity", 0.5);
|
|
1690
|
-
return setTimeout(refreshDelayed, 10);
|
|
1691
|
-
};
|
|
1692
|
-
})(this);
|
|
1693
|
-
refresh();
|
|
1694
|
-
this.find(".pvtAxisContainer").sortable({
|
|
1695
|
-
update: function(e, ui) {
|
|
1696
|
-
if (ui.sender == null) {
|
|
1697
|
-
return refresh();
|
|
1698
|
-
}
|
|
1699
|
-
},
|
|
1700
|
-
connectWith: this.find(".pvtAxisContainer"),
|
|
1701
|
-
items: 'li',
|
|
1702
|
-
placeholder: 'pvtPlaceholder'
|
|
1703
|
-
});
|
|
1704
|
-
} catch (error) {
|
|
1705
|
-
e = error;
|
|
1706
|
-
if (typeof console !== "undefined" && console !== null) {
|
|
1707
|
-
console.error(e.stack);
|
|
1708
|
-
}
|
|
1709
|
-
// This function is not used internally or in webclient_angular/export_widget_service
|
|
1710
|
-
// TODO if it not removed in DR-39041, upgrade the error propagation
|
|
1711
|
-
this.html("An error occurred rendering the PivotTable UI.");
|
|
1712
|
-
}
|
|
1713
|
-
return this;
|
|
1714
|
-
}
|
|
1715
|
-
};
|
|
1716
|
-
|
|
1717
1216
|
/*
|
|
1718
1217
|
Heatmap post-processing
|
|
1719
1218
|
*/
|
|
@@ -1,144 +1,69 @@
|
|
|
1
|
-
const
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const { DELIMER } = require('./dr-renderer-helpers');
|
|
2
3
|
|
|
3
4
|
const DR_SCENARIO = {
|
|
4
5
|
SQ_Actuals: 'SQ_Actuals',
|
|
5
6
|
Forecast: 'Forecast',
|
|
6
7
|
};
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
buildChartSeriesForMultipleSeriesCombinedLine(chart_series, input, actuals, forecast, midMonthOffset) :
|
|
23
|
-
buildChartSeriesFromSeries(chart_series, actuals, forecast, midMonthOffset));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function buildChartSeriesFromPivotInputOnly(input, actuals, forecast, midMonthOffset, name) {
|
|
27
|
-
const filtered = input.filter(item =>
|
|
28
|
-
(item.Scenario === DR_SCENARIO.SQ_Actuals || item.Scenario === DR_SCENARIO.Forecast) && !!item['Reporting Month']
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const data = lodash.map(filtered, item => ({
|
|
32
|
-
y: item.Amount,
|
|
33
|
-
name: item['Reporting Month'],
|
|
34
|
-
initialName: item['Reporting Month'],
|
|
35
|
-
type: item.Scenario,
|
|
36
|
-
})).sort((a, b) => sortRowValuesByName(a, b));
|
|
37
|
-
|
|
38
|
-
const sqCount = lodash.filter(input, item => item.Scenario === DR_SCENARIO.SQ_Actuals).length;
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
name,
|
|
42
|
-
data,
|
|
43
|
-
zoneAxis: "x",
|
|
44
|
-
zones: [
|
|
45
|
-
{ value: sqCount - midMonthOffset, dashStyle: actuals },
|
|
46
|
-
{ dashStyle: forecast },
|
|
47
|
-
],
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function buildChartSeriesForMultipleSeriesCombinedLine(chart_series, input, actuals, forecast, midMonthOffset) {
|
|
52
|
-
const resultingSeries = [];
|
|
53
|
-
for (let i = 0; i < chart_series.length; i++) {
|
|
54
|
-
const series = chart_series[i];
|
|
55
|
-
if (!series || !series.data || !series.data.length) continue;
|
|
9
|
+
/**
|
|
10
|
+
* @param tree {DRPivotData['tree']}
|
|
11
|
+
* @param rowKey {string[]} ['6+6', 'Forecast 6+6 Mid'] OR ['6+6', 'SQ_Actuals']
|
|
12
|
+
* @param flatColKey {string} 'Jan-25'
|
|
13
|
+
* @returns {object|null} A aggregator object of SQ_Actuals or null if not found
|
|
14
|
+
*/
|
|
15
|
+
function getSqAggregator(tree, rowKey, flatColKey) {
|
|
16
|
+
const uniqueRowKeys = _.uniq(rowKey);
|
|
17
|
+
|
|
18
|
+
// if we have only scenarioCycle (uniqueRowKeys[1] is undefined) default aggregator should handle fine
|
|
19
|
+
// SQ_Actuals should be used only for Forecast items, if current item is SQ_Actuals we just ignore it
|
|
20
|
+
if(!uniqueRowKeys[1] || uniqueRowKeys[1] === DR_SCENARIO.SQ_Actuals) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
56
23
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
.map(item => ({
|
|
61
|
-
y: item.Amount,
|
|
62
|
-
name: item['Reporting Month'],
|
|
63
|
-
initialName: item['Reporting Month'],
|
|
64
|
-
type: item.Scenario,
|
|
65
|
-
}))
|
|
66
|
-
.value().sort((a, b) => {
|
|
67
|
-
return sortRowValuesByName(a, b);
|
|
68
|
-
});
|
|
69
|
-
if (!data.length) {
|
|
70
|
-
resultingSeries.push(series);
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
24
|
+
// at this point rowKey should be something like ['6+6', 'Forecast 6+6 Mid', ...]
|
|
25
|
+
// SQ_Actuals always contains scenarioCycle at 0 position ('6+6') and repeats 'SQ_Actuals' for rest of the rows
|
|
26
|
+
const sqFlatRowKey = _.map(rowKey, (key, index) => index === 0 ? key : DR_SCENARIO.SQ_Actuals).join(DELIMER)
|
|
73
27
|
|
|
74
|
-
|
|
75
|
-
resultingSeries.push(
|
|
76
|
-
{
|
|
77
|
-
name: series.name,
|
|
78
|
-
data,
|
|
79
|
-
zoneAxis: "x",
|
|
80
|
-
zones: [
|
|
81
|
-
{ value: sqCount - midMonthOffset, dashStyle: actuals },
|
|
82
|
-
{ dashStyle: forecast },
|
|
83
|
-
],
|
|
84
|
-
}
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
return resultingSeries;
|
|
28
|
+
return tree[sqFlatRowKey] ? tree[sqFlatRowKey][flatColKey] : null;
|
|
88
29
|
}
|
|
89
30
|
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
31
|
+
function handleForecastSeries(chart_series, chartOptions, pivotData) {
|
|
32
|
+
const midMonthOffset = 0.5;
|
|
33
|
+
const sqInput = _.filter(pivotData.input, item => item['Scenario'] === DR_SCENARIO.SQ_Actuals);
|
|
34
|
+
const noSqSeries = _.filter(chart_series, (s) => !_.includes(s.name, DR_SCENARIO.SQ_Actuals)); // SQ_Actuals are just base for forecast
|
|
35
|
+
|
|
36
|
+
return _.map(noSqSeries, series => {
|
|
37
|
+
const itemScenario = getSqScenarioCycle(series.name);
|
|
38
|
+
const sqCount = _.filter(sqInput, item => _.startsWith(pivotData.getFlatKey(item, pivotData.rowAttrs), itemScenario)).length;
|
|
39
|
+
|
|
40
|
+
if(!sqCount) return series;
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
name: series.name,
|
|
44
|
+
data: series.data,
|
|
45
|
+
zoneAxis: "x",
|
|
46
|
+
zones: [
|
|
47
|
+
{ value: sqCount - midMonthOffset, dashStyle: chartOptions.chart.actuals },
|
|
48
|
+
{ dashStyle: chartOptions.chart.forecast },
|
|
49
|
+
],
|
|
50
|
+
}
|
|
51
|
+
})
|
|
94
52
|
}
|
|
95
53
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const indexOfActualsFirstZero = lodash.findIndex(seriesA.data, function(value) {
|
|
106
|
-
return value.y === 0;
|
|
107
|
-
});
|
|
108
|
-
const cutoffIndex = Math.max(indexOfForecastFirstZero, indexOfActualsFirstZero);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const minLength = Math.min(seriesA.data.length, seriesB.data.length);
|
|
112
|
-
const data = [];
|
|
113
|
-
|
|
114
|
-
for (let i = 0; i < minLength; i++) {
|
|
115
|
-
const pointA = seriesA.data[i];
|
|
116
|
-
const pointB = seriesB.data[i];
|
|
117
|
-
|
|
118
|
-
const yA = (pointA && pointA.y !== null && typeof pointA.y !== undefined) ? pointA.y : pointA;
|
|
119
|
-
const yB = (pointB && pointB.y !== null && typeof pointB.y !== undefined) ? pointB.y : pointB;
|
|
120
|
-
|
|
121
|
-
data.push({
|
|
122
|
-
x: i,
|
|
123
|
-
y: yA + yB,
|
|
124
|
-
name: pointA && pointA.name ? pointA.name : null,
|
|
125
|
-
initialName: (pointA && pointA.name) ? pointA.name : 'Point ' + (i + 1),
|
|
126
|
-
type: yA ? DR_SCENARIO.SQ_Actuals : DR_SCENARIO.Forecast,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
name: "Forecast Smart Query",
|
|
132
|
-
data,
|
|
133
|
-
zoneAxis: "x",
|
|
134
|
-
zones: [
|
|
135
|
-
{ value: cutoffIndex - midMonthOffset, dashStyle: actuals },
|
|
136
|
-
{ dashStyle: forecast },
|
|
137
|
-
],
|
|
138
|
-
};
|
|
54
|
+
/**
|
|
55
|
+
* @example
|
|
56
|
+
* getSqScenarioCycle("6+6 , Forecast 6+6 Mid"); // "6+6"
|
|
57
|
+
* getSqScenarioCycle("6+6 , SQ_Actuals"); // "6+6"
|
|
58
|
+
*
|
|
59
|
+
* @returns {string|undefined}
|
|
60
|
+
*/
|
|
61
|
+
function getSqScenarioCycle(name) {
|
|
62
|
+
return _.first(_.split(name, DELIMER));
|
|
139
63
|
}
|
|
140
64
|
|
|
141
65
|
module.exports = {
|
|
142
|
-
|
|
66
|
+
getSqAggregator,
|
|
67
|
+
handleForecastSeries,
|
|
143
68
|
DR_SCENARIO
|
|
144
69
|
};
|