@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarailsshared/dr_renderer",
3
- "version": "1.5.114",
3
+ "version": "1.5.118",
4
4
  "description": "DataRails charts and tables renderer",
5
5
  "keywords": [
6
6
  "datarails",
@@ -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 hasProp = {}.hasOwnProperty;
7
- var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
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
- // const numberOfRows = 500; // change to activate the handsontable when num of rows bigger then this.
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
- DRPivotData = (function(superClass) {
16
- extend(DRPivotData, superClass);
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
- DRPivotData.__super__.constructor.call(this, input, opts);
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
- })($.pivotUtilities.PivotData);
326
+ })();
199
327
 
200
- $.pivotUtilities.DRPivotData = DRPivotData;
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('column-chart-stacked-percent');
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('bar-chart-stacked-percent');
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
- 'column-chart': {
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
- 'column-chart-stacked': {
6342
+ [optionsBuilders.CHART_TYPES.COLUMN_CHART_STACKED]: {
6331
6343
  name: 'Stacked column chart',
6332
- label: 'Stacked Column',
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
- 'column-chart-stacked-percent': {
6353
+ [optionsBuilders.CHART_TYPES.COLUMN_CHART_STACKED_PERCENT]: {
6342
6354
  name: '100% Stacked column chart',
6343
- label: '100% Stacked Column',
6344
- title: 'Shows the percentage contribution of each segment within a category.',
6345
- description: 'Each bar represents 100%, with segments showing their percentage share. Ideal for comparing proportions across categories.',
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
- 'bar-chart': {
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
- 'bar-chart-stacked': {
6375
+ [optionsBuilders.CHART_TYPES.BAR_CHART_STACKED]: {
6364
6376
  name: 'Stacked bar chart',
6365
- label: 'Stacked Bar',
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
- 'bar-chart-stacked-percent': {
6386
+ [optionsBuilders.CHART_TYPES.BAR_CHART_STACKED_PERCENT]: {
6375
6387
  name: '100% Stacked bar chart',
6376
- label: '100% Stacked Bar',
6377
- title: 'Shows the percentage contribution of each segment within a category.',
6378
- description: 'Each bar represents 100%, with segments showing their percentage share. Ideal for comparing proportions across categories.',
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: 'column-chart-stacked-percent',
6737
- hidden: true,
6738
- name: highchartsRenderer.chartsTypesInfo['column-chart-stacked-percent'].name,
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: 'bar-chart-stacked-percent',
6805
- hidden: true,
6806
- name: highchartsRenderer.chartsTypesInfo['bar-chart-stacked-percent'].name,
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
@@ -38,6 +38,7 @@ declare namespace DrRenderFactory {
38
38
  disable_animation?: boolean;
39
39
  fiscal_year_starts_from?: number;
40
40
  fiscal_year_back?: boolean;
41
+ enableStackedPercentCharts?: boolean;
41
42
  }
42
43
 
43
44
  interface Factory {
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;