@datarailsshared/dr_renderer 1.4.10 → 1.4.12

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.
@@ -51,7 +51,7 @@ const GAUGE_OPTIONS_DEFAULT = {
51
51
  ],
52
52
  };
53
53
 
54
- function DrGaugeChart(pivotData, opts) {
54
+ function DrGaugeChart(pivotData, opts, isDynamicGoal) {
55
55
  this.render = function () {
56
56
  return DrGaugeChart.highchartsRenderer.ptCreateElementAndDraw(this.configChart(), opts);
57
57
  };
@@ -84,13 +84,20 @@ function DrGaugeChart(pivotData, opts) {
84
84
  return (value - min) < (max - min) / 2;
85
85
  };
86
86
 
87
- this.createTicks = DrGaugeChart.createTicks;
87
+ this.createTicks = function(plotBands, options) {
88
+ return DrGaugeChart.createTicks(plotBands, options);
89
+ }
88
90
 
89
91
  this.mergeOptions = function (options) {
92
+ const clone = (o) =>
93
+ o && typeof o === 'object'
94
+ ? (globalThis.structuredClone ? structuredClone(o) : JSON.parse(JSON.stringify(o)))
95
+ : o;
96
+
90
97
  return helpers.mergeDeep(
91
- JSON.parse(JSON.stringify(GAUGE_OPTIONS_DEFAULT)),
92
- this.getDefaultValueForChart(DrGaugeChart.highchartsRenderer.CHART_TYPES.GAUGE_CHART_ENHANCED),
93
- options
98
+ clone(GAUGE_OPTIONS_DEFAULT),
99
+ clone(this.getDefaultValueForChart(DrGaugeChart.highchartsRenderer.CHART_TYPES.GAUGE_CHART_ENHANCED)),
100
+ clone(options || {})
94
101
  );
95
102
  };
96
103
 
@@ -111,7 +118,7 @@ function DrGaugeChart(pivotData, opts) {
111
118
  };
112
119
 
113
120
  this.toPercent = function (value) {
114
- return `${Math.round((value * 100) / (this.options.isAbsoluteValue ? this.max : this.goal.value))}%`;
121
+ return `${Math.round((value * 100) / (this.options.isAbsoluteValue ? this.max : this.options.goal.value))}%`;
115
122
  };
116
123
 
117
124
  this.formatValueLabel = function (value, options) {
@@ -139,9 +146,11 @@ function DrGaugeChart(pivotData, opts) {
139
146
  const goalValue = isGoal
140
147
  ? `<span style="font-size: 1.125em; color: ${options.gauge.colors.goal};">${formattedValue}</span>`
141
148
  : `<span style="color: ${options.label.font_color};">${formattedValue}</span>`;
149
+
150
+ const goalTitleText = DrGaugeChart.getGoalTitleText(options);
142
151
  const goalTitle =
143
- isGoal && options.label.show_goal_name && options.goal.title
144
- ? `<span style="font-size: 0.75em; color: ${options.gauge.colors.goal};">${options.goal.title}</span>`
152
+ isGoal && options.label.show_goal_name && goalTitleText
153
+ ? `<span style="font-size: 0.75em; color: ${options.gauge.colors.goal};">${goalTitleText}</span>`
145
154
  : "";
146
155
  const percentage = options.label.show_percentage_in_segments
147
156
  ? `<span style="font-size: 0.75em; color: ${options.gauge.colors.meta}; font-weight: 400;">(${this.toPercent(
@@ -171,9 +180,17 @@ function DrGaugeChart(pivotData, opts) {
171
180
  goal: { value },
172
181
  } = options;
173
182
 
183
+ let valueForPosition = value;
184
+ let verticalOffset = 0;
185
+
186
+ if (DrGaugeChart.dynamicGoalFeatureEnabled() && (value > this.max || value < this.min)) {
187
+ valueForPosition = value > this.max ? this.max : this.min;
188
+ verticalOffset = 30;
189
+ }
190
+
174
191
  return {
175
- x: center[0] - radius * Math.sin(Math.PI / 2 - this.getAngleForValue(value)) - goalIconSize[0] / 2,
176
- y: center[1] - radius * Math.cos(Math.PI / 2 - this.getAngleForValue(value)) - goalIconSize[1] / 2,
192
+ x: center[0] - radius * Math.sin(Math.PI / 2 - this.getAngleForValue(valueForPosition)) - goalIconSize[0] / 2,
193
+ y: center[1] + verticalOffset - radius * Math.cos(Math.PI / 2 - this.getAngleForValue(valueForPosition)) - goalIconSize[1] / 2,
177
194
  };
178
195
  };
179
196
 
@@ -197,46 +214,112 @@ function DrGaugeChart(pivotData, opts) {
197
214
  return label;
198
215
  };
199
216
 
217
+ this.getGoalLabelPosition = function (chart, options, goalLabel) {
218
+ const padding = 7;
219
+ const point = this.getGoalIconPosition(chart, options);
220
+ const isLower = options.goal.value < this.min;
221
+
222
+ return {
223
+ x: point.x + (isLower ? -goalLabel.element.clientWidth : padding),
224
+ y: point.y + padding,
225
+ };
226
+ }
227
+
228
+ this.createGoalLabel = function (chart, options) {
229
+ const label = chart.renderer.text(
230
+ this.formatTickLabel(options.goal.value, options), 0, 0, true
231
+ ).add().toFront();
232
+
233
+ label.attr(this.getGoalLabelPosition(chart, options, label));
234
+
235
+ if (options.tooltips.show) {
236
+ const drTooltip = new DrChartTooltip(chart, {
237
+ fontSize: options.tooltips.font_size,
238
+ fontFamily: options.tooltips.font_style,
239
+ color: options.tooltips.font_color,
240
+ });
241
+ drTooltip.add(
242
+ this.toPercent(options.goal.value),
243
+ label.element,
244
+ {
245
+ direction: "right",
246
+ }
247
+ );
248
+ }
249
+
250
+ return label;
251
+ };
252
+
200
253
  this.getPaneDimensions = function (chart, options) {
201
- const { renderer } = chart;
202
- const valueLabel = this.createValueLabel(chart, this.options);
254
+ const valueLabel = this.createValueLabel(chart, options);
255
+ const { height: labelH } = valueLabel.getBBox ? valueLabel.getBBox() : { height: 0 };
256
+ valueLabel.destroy && valueLabel.destroy();
257
+
203
258
  const { offset } = options.gauge;
204
- const { height: labelH } = valueLabel.getBBox();
259
+ const offsetTop = Array.isArray(offset) ? offset[0] : 0;
260
+ const offsetRight = Array.isArray(offset) ? offset[1] : 0;
261
+ const offsetBottomG= Array.isArray(offset) ? offset[2] : 0;
262
+ const offsetLeft = Array.isArray(offset) ? offset[3] : 0;
263
+
264
+ const vOff = options.gauge.valueOffset || [0,0,0,0];
205
265
 
206
- const offsetBottom = labelH + options.gauge.valueOffset[0] + options.gauge.valueOffset[2] + offset[2];
207
- valueLabel.destroy();
266
+ const offsetBottom = (labelH || 0) + (vOff[0] || 0) + (vOff[2] || 0) + (offsetBottomG || 0);
267
+
268
+ const safeDiv = (num, den) => {
269
+ const v = num / den;
270
+ return Number.isFinite(v) ? v : Infinity;
271
+ };
272
+
273
+ const radiuses = [
274
+ chart.chartWidth / 2 - Math.max(offsetRight || 0, offsetLeft || 0),
275
+ chart.chartHeight - offsetBottom - (offsetTop || 0),
276
+ ];
208
277
 
209
- const radiuses = [chart.chartWidth / 2 - Math.max(offset[1], offset[3]), chart.chartHeight - offsetBottom - offset[0]];
210
278
  if (options.label.show) {
211
279
  this.ticks.forEach((tick) => {
212
- const label = renderer.label(this.formatTickLabel(tick, options), 0, 0, null, null, null, true).add();
280
+ const label = chart.renderer
281
+ .label(this.formatTickLabel(tick, options), 0, 0, null, null, null, true)
282
+ .add();
283
+
213
284
  const angle = this.getAngleForValue(tick);
214
- // depends on label width
215
- radiuses.push(
216
- (chart.chartWidth / 2 - label.bBox.width - Math.max(offset[1], offset[3])) /
217
- Math.sin(Math.abs(Math.PI / 2 - angle))
218
- );
219
- // depends on label height
285
+ const s = Math.sin(Math.abs(Math.PI / 2 - angle));
286
+ const c = Math.cos(Math.abs(Math.PI / 2 - angle));
287
+
220
288
  radiuses.push(
221
- (chart.chartHeight - offsetBottom - label.bBox.height / 2 - offset[0]) /
222
- Math.cos(Math.abs(Math.PI / 2 - angle))
289
+ safeDiv(
290
+ chart.chartWidth / 2 - label.bBox.width - Math.max(offsetRight || 0, offsetLeft || 0),
291
+ s
292
+ ),
293
+ safeDiv(
294
+ chart.chartHeight - offsetBottom - label.bBox.height / 2 - (offsetTop || 0),
295
+ c
296
+ )
223
297
  );
224
- label.destroy();
298
+
299
+ label.destroy && label.destroy();
225
300
  });
226
301
  } else {
227
- // reserve space for the goal icon
228
302
  const angle = this.getAngleForValue(options.goal.value);
229
- const [iconW, iconH] = options.gauge.goalIconSize;
230
- radiuses.push((chart.chartWidth / 2 - iconW / 2 - offset[1]) / Math.sin(Math.abs(Math.PI / 2 - angle)));
231
- radiuses.push((chart.chartHeight - offsetBottom - iconH / 2 - offset[0]) / Math.cos(Math.abs(Math.PI / 2 - angle)));
303
+ const [iconW, iconH] = options.gauge.goalIconSize || [0, 0];
304
+ const s = Math.sin(Math.abs(Math.PI / 2 - angle));
305
+ const c = Math.cos(Math.abs(Math.PI / 2 - angle));
306
+
307
+ radiuses.push(
308
+ safeDiv(chart.chartWidth / 2 - iconW / 2 - (offsetRight || 0), s),
309
+ safeDiv(chart.chartHeight - offsetBottom - iconH / 2 - (offsetTop || 0), c)
310
+ );
232
311
  }
233
312
 
313
+ const finite = radiuses.filter(Number.isFinite);
314
+ const radius = finite.length ? Math.min(...finite) : 0;
315
+
234
316
  return {
235
- radius: Math.min(...radiuses),
317
+ radius,
236
318
  center: [chart.chartWidth / 2, chart.chartHeight - offsetBottom],
237
319
  };
238
320
  };
239
321
 
322
+
240
323
  this.setTicksStyles = function (chart, options) {
241
324
  const ticks = chart.yAxis[0].ticks;
242
325
  Object.keys(ticks).forEach((i) => {
@@ -265,7 +348,7 @@ function DrGaugeChart(pivotData, opts) {
265
348
  };
266
349
 
267
350
  this.updateLabelsWhenGoalIsHidden = function (ticks, options) {
268
- if (ticks[options.goal.value].label.opacity === 0) {
351
+ if (ticks[options.goal.value] && ticks[options.goal.value].label.opacity === 0) {
269
352
 
270
353
  const ticksArray = Object.entries(ticks);
271
354
 
@@ -330,7 +413,7 @@ function DrGaugeChart(pivotData, opts) {
330
413
  // goal tooltip if lebels are hidden
331
414
  if (tick.pos === options.goal.value && !options.label.show) {
332
415
  drTooltip.add(
333
- `${options.label.show_goal_name ? options.goal.title || "" : ""
416
+ `${options.label.show_goal_name ? DrGaugeChart.getGoalTitleText(options) || "" : ""
334
417
  }<span style="font-weight: 600">${this.formatValue(options.goal.value)}</span>`,
335
418
  chart.goalIcon.element,
336
419
  {
@@ -350,19 +433,35 @@ function DrGaugeChart(pivotData, opts) {
350
433
 
351
434
  this.setPane = function (chart, options) {
352
435
  const { radius, center } = this.getPaneDimensions(chart, options);
353
- chart.pane[0].options.size = 2 * radius;
436
+
437
+ const MIN_RADIUS = Math.max(8, options.gauge.thickness / 2 + 1);
438
+ const R = Math.max(MIN_RADIUS, radius);
439
+
440
+ chart.pane[0].options.size = 2 * R;
354
441
  chart.pane[0].options.center = center;
442
+
443
+ const effectiveTick = Math.min(options.gauge.tickLength, Math.floor(R * 0.8));
444
+ chart.yAxis[0].options.tickLength = effectiveTick;
445
+
355
446
  chart.yAxis[0].options.plotBands.forEach((band) => {
356
- band.outerRadius = radius - (options.gauge.tickLength - options.gauge.thickness) / 2;
447
+ band.outerRadius = Math.max(1, R - (effectiveTick - options.gauge.thickness) / 2);
357
448
  });
358
- chart.series[0].options.dial.radius = Math.round((100 * (radius - options.gauge.tickLength - 10)) / radius) + "%";
449
+
450
+ chart.series[0].options.dial.radius = R > 0
451
+ ? Math.round((100 * (R - effectiveTick - 10)) / R) + "%"
452
+ : "0%";
359
453
  };
360
454
 
455
+
361
456
  this.setCustomElements = function (chart, options) {
362
457
  chart.label = this.createValueLabel(chart, options);
363
458
  chart.startBorder = DrGaugeChart.createBorder(chart, options, "start");
364
459
  chart.endBorder = DrGaugeChart.createBorder(chart, options, "end");
365
460
  chart.goalIcon = this.createGoalIcon(chart, options);
461
+
462
+ if (DrGaugeChart.dynamicGoalFeatureEnabled() && (options.goal.value > this.max || options.goal.value < this.min)) {
463
+ chart.goalLabel = this.createGoalLabel(chart, options);
464
+ }
366
465
  };
367
466
 
368
467
  this.updateCustomElements = function (chart, options) {
@@ -370,6 +469,10 @@ function DrGaugeChart(pivotData, opts) {
370
469
  chart.endBorder.attr(DrGaugeChart.getBorderPosition(chart, options, "end"));
371
470
  chart.goalIcon.attr(this.getGoalIconPosition(chart, options));
372
471
  chart.label.attr(DrGaugeChart.getValueLabelPosition(chart, options));
472
+
473
+ if (chart.goalLabel) {
474
+ chart.goalLabel.attr(this.getGoalLabelPosition(chart, options, chart.goalLabel));
475
+ }
373
476
  };
374
477
 
375
478
  this.createPlotBands = function (options) {
@@ -380,10 +483,22 @@ function DrGaugeChart(pivotData, opts) {
380
483
  gauge: { thickness },
381
484
  } = options;
382
485
 
486
+ // If goal is not positive in percentage mode, scale segments by the current needle magnitude
487
+ const scaleBase = !isAbsoluteValue && (!helpers.isNumber(goalValue) || goalValue === 0)
488
+ ? (helpers.isNumber(this.value) && Math.abs(this.value)) || 1
489
+ : goalValue;
490
+
383
491
  const bands = segments.map((item) => {
492
+ const fromValue = isAbsoluteValue ? item.from : (item.from * scaleBase) / 100;
493
+ const toValue = isAbsoluteValue ? item.to : (item.to * scaleBase) / 100;
494
+
495
+ // Ensure a valid interval for Highcharts plotBands even when goal is negative
496
+ const normalizedFrom = Math.min(fromValue, toValue);
497
+ const normalizedTo = Math.max(fromValue, toValue);
498
+
384
499
  return {
385
- from: isAbsoluteValue ? item.from : (item.from * goalValue) / 100,
386
- to: isAbsoluteValue ? item.to : (item.to * goalValue) / 100,
500
+ from: normalizedFrom,
501
+ to: normalizedTo,
387
502
  color: item.color,
388
503
  thickness: thickness,
389
504
  title: item.title,
@@ -391,7 +506,9 @@ function DrGaugeChart(pivotData, opts) {
391
506
  });
392
507
 
393
508
  // clamp last segment
394
- bands[bands.length - 1].to = Math.max(bands[bands.length - 1].to, goalValue);
509
+ if (!DrGaugeChart.dynamicGoalFeatureEnabled()) {
510
+ bands[bands.length - 1].to = Math.max(bands[bands.length - 1].to, goalValue);
511
+ }
395
512
 
396
513
  return bands;
397
514
  };
@@ -400,6 +517,10 @@ function DrGaugeChart(pivotData, opts) {
400
517
  chart.startBorder.toFront();
401
518
  chart.endBorder.toFront();
402
519
  chart.goalIcon.toFront();
520
+
521
+ if (chart.goalLabel) {
522
+ chart.goalLabel.toFront();
523
+ }
403
524
  };
404
525
 
405
526
  this.clampValueToPane = function (value, max = this.max, min = this.min) {
@@ -407,6 +528,16 @@ function DrGaugeChart(pivotData, opts) {
407
528
  return helpers.clamp(min - correction, value, max + correction);
408
529
  };
409
530
 
531
+ this.setGoal = function (pivotData, opts) {
532
+ if (isDynamicGoal) {
533
+ this.options.goal = {
534
+ title: DrGaugeChart.getGoalTitleText(this.options),
535
+ value: DrGaugeChart.getValue(pivotData, opts, true, true),
536
+ };
537
+ }
538
+ this.goal = this.options.goal;
539
+ };
540
+
410
541
  this.configChart = function () {
411
542
  return {
412
543
  title: {
@@ -513,18 +644,25 @@ function DrGaugeChart(pivotData, opts) {
513
644
 
514
645
  this.originalOptions = opts;
515
646
  this.options = this.mergeOptions(opts.chartOptions);
516
- this.aggregation = pivotData.getAggregator([], []);
647
+ this.aggregation = DrGaugeChart.getAggregation(pivotData, opts.chartOptions);
517
648
  this.format = this.aggregation.widget_values_format;
518
- this.goal = this.options.goal;
649
+ this.value = DrGaugeChart.getValue(pivotData, opts, isDynamicGoal);
650
+ this.setGoal(pivotData, opts);
519
651
  this.plotBands = this.createPlotBands(this.options);
520
652
  this.ticks = this.createTicks(this.plotBands, this.options);
521
- this.value = DrGaugeChart.getValue(pivotData, opts);
522
653
  this.max = this.ticks[this.ticks.length - 1];
523
654
  this.min = this.ticks[0];
524
655
  }
525
656
 
526
657
  DrGaugeChart.createTicks = function (plotBands, options) {
527
- return _.uniq([plotBands[0].from || 0, ...plotBands.map((b) => b.to), options.goal.value]).sort((a, b) => a - b);
658
+ const goal = options.goal.value;
659
+ const ticks = [plotBands[0].from || 0, ...plotBands.map((b) => b.to)];
660
+
661
+ if (!DrGaugeChart.dynamicGoalFeatureEnabled() || goal < Math.max(...ticks) && goal > Math.min(...ticks)) {
662
+ ticks.push(options.goal.value);
663
+ }
664
+
665
+ return _.uniq(ticks.sort((a, b) => a - b));
528
666
  };
529
667
 
530
668
  DrGaugeChart.getBorderPosition = function (chart, options, position) {
@@ -583,33 +721,57 @@ DrGaugeChart.getSingleValueAgg = function (opts, aggfunc, base) {
583
721
  return DrGaugeChart.highchartsRenderer.getSingleValueAgg(opts, aggfunc, base);
584
722
  };
585
723
 
586
- DrGaugeChart.getValue = function (pivotData, opts) {
587
- const lineSeries = DrGaugeChart.ptCreateBasicLineSeries(pivotData, null, true, null, null, opts, {});
724
+ DrGaugeChart.getAggregation = function(pivotData, options, isForGoal = false) {
725
+ if (_.get(options, 'dynamicGaugeConfig')) {
726
+ return pivotData.getAggregator([], [isForGoal ? options.dynamicGaugeConfig.goal : options.dynamicGaugeConfig.needle]);
727
+ }
728
+ return pivotData.getAggregator([], []);
729
+ }
588
730
 
589
- let total = _.flatten(lineSeries
590
- .map((s) => s.data.map((v) => v))
591
- .filter((v) => !_.isNaN(v))
592
- );
593
731
 
594
- let aggfunc = (a, b) => a + b;
595
- let base = 0;
596
- let singleValueAgg = DrGaugeChart.getSingleValueAgg(
597
- {
598
- value: {
599
- value: "Sum",
732
+ DrGaugeChart.getValue = function (pivotData, opts, isDynamicGoal = false, isForGoal = false) {
733
+ const aggregator = DrGaugeChart.getAggregation(pivotData, opts.chartOptions, isForGoal)
734
+
735
+ let total;
736
+ if (!isDynamicGoal) {
737
+ const lineSeries = DrGaugeChart.ptCreateBasicLineSeries(pivotData, null, true, null, null, opts, {});
738
+
739
+ total = _.flatten(lineSeries
740
+ .map((s) => s.data.map((v) => v))
741
+ .filter((v) => !_.isNaN(v))
742
+ );
743
+
744
+ let aggfunc = (a, b) => a + b;
745
+ let base = 0;
746
+ let singleValueAgg = DrGaugeChart.getSingleValueAgg(
747
+ {
748
+ value: {
749
+ value: "Sum",
750
+ },
600
751
  },
601
- },
602
- aggfunc,
603
- base
604
- );
752
+ aggfunc,
753
+ base
754
+ );
605
755
 
606
- aggfunc = singleValueAgg.aggfunc;
607
- base = singleValueAgg.base;
756
+ aggfunc = singleValueAgg.aggfunc;
757
+ base = singleValueAgg.base;
608
758
 
609
- const aggregator = pivotData.getAggregator([], []);
610
- const value = total.length > 0 ? total.reduce(aggfunc, base) : aggregator.value();
759
+ if (total.length > 0) {
760
+ return total.reduce(aggfunc, base);
761
+ }
762
+ }
611
763
 
612
- return value;
764
+ return aggregator.value();
613
765
  };
614
766
 
767
+ DrGaugeChart.getGoalTitleText = function(options) {
768
+ return DrGaugeChart.dynamicGoalFeatureEnabled()
769
+ ? _.get(options, 'label.goal_name') || options.goal.title
770
+ : options.goal.title;
771
+ }
772
+
773
+ DrGaugeChart.dynamicGoalFeatureEnabled = function() {
774
+ return DrGaugeChart.highchartsRenderer.hasFeature(helpers.FEATURES.ENABLE_GAUGE_DYNAMIC_GOAL);
775
+ }
776
+
615
777
  module.exports = { DrGaugeChart, GAUGE_OPTIONS_DEFAULT };
@@ -18,25 +18,32 @@ function isNumber(n) {
18
18
  }
19
19
 
20
20
  function mergeDeep(target, ...sources) {
21
- const isObject = (obj) => obj && typeof obj === 'object' && !Array.isArray(obj);
21
+ const deepClone = (val) => {
22
+ if (Array.isArray(val)) return val.map(deepClone);
23
+ if (_.isPlainObject(val)) {
24
+ const out = {};
25
+ for (const k of Object.keys(val)) out[k] = deepClone(val[k]);
26
+ return out;
27
+ }
28
+ return val;
29
+ };
22
30
 
23
- if (!isObject(target)) return target;
31
+ if (!_.isPlainObject(target)) return target;
24
32
 
25
- sources.forEach((source) => {
26
- if (!isObject(source)) return;
33
+ for (const source of sources) {
34
+ if (!_.isPlainObject(source)) continue;
27
35
 
28
- Object.keys(source).forEach((key) => {
29
- const targetValue = target[key];
30
- const sourceValue = source[key];
36
+ for (const key of Object.keys(source)) {
37
+ const tVal = target[key];
38
+ const sVal = source[key];
31
39
 
32
- if (isObject(targetValue) && isObject(sourceValue)) {
33
- target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue);
40
+ if (_.isPlainObject(tVal) && _.isPlainObject(sVal)) {
41
+ target[key] = mergeDeep({}, tVal, sVal);
34
42
  } else {
35
- target[key] = sourceValue;
43
+ target[key] = deepClone(sVal);
36
44
  }
37
- });
38
- });
39
-
45
+ }
46
+ }
40
47
  return target;
41
48
  }
42
49
 
@@ -66,6 +73,15 @@ function isShowingEmptyValues(additionOptions) {
66
73
  return !additionOptions || !additionOptions.chart || additionOptions.chart.dislay_empty_values !== false;
67
74
  }
68
75
 
76
+ const FEATURES = {
77
+ ENABLE_NEW_WIDGET_VALUE_FORMATTING: 'enable_new_widget_value_formatting',
78
+ FORMAT_DATES_AS_OTHER_AXIS_TYPES: 'format_dates_as_other_axis_types',
79
+ MULTIPLE_DIMENSION_TAGS: 'multiple_dimension_tags',
80
+ USE_NEW_SCENARIO_TAG: 'use_new_scenario_tag',
81
+ ENABLE_SERVER_WIDGET_DATA_SORTING: 'enable_server_widget_data_sorting',
82
+ ENABLE_GAUGE_DYNAMIC_GOAL: 'enable_gauge_dynamic_goal',
83
+ }
84
+
69
85
  module.exports = {
70
86
  backendSortingKeysAreNotEmpty,
71
87
  capitalize,
@@ -75,4 +91,5 @@ module.exports = {
75
91
  removeSVGTextCorrection,
76
92
  disableLegendInteractionIfRequired,
77
93
  isShowingEmptyValues,
94
+ FEATURES
78
95
  }
@@ -1,5 +1,5 @@
1
1
  const { DR_SCENARIO } = require('./smart_queries_helper');
2
-
2
+ const { TooMuchDataError } = require('./errors');
3
3
 
4
4
  let initDRPivotTable = function($, window, document) {
5
5
  var hasProp = {}.hasOwnProperty;
@@ -177,7 +177,7 @@ let initDRPivotTable = function($, window, document) {
177
177
  return keys.join(delim);
178
178
  }
179
179
 
180
- DRPivotData.prototype.processRecord = function(record) {
180
+ DRPivotData.prototype.processRecord = function(record, isSmartQueriesEnabled) {
181
181
  if (!this.notFirst) {
182
182
  this.keysLength = _.filter(_.keys(record), key => !_.includes(['data_types', 'formats', 'values_formats'], key)).length - 1;
183
183
  this.notFirst = true;
@@ -211,7 +211,7 @@ let initDRPivotTable = function($, window, document) {
211
211
  if (!colKey.length && !rowKey.length) {
212
212
  this.allTotal.push(record);
213
213
  } else if (!colKey.length && rowKey.length) {
214
- if (!this.rowTotals[flatRowKey]) {
214
+ if (!this.rowTotals[flatRowKey] || isSmartQueriesEnabled) {
215
215
  this.rowTotals[flatRowKey] = getRowAggregator(rowKey.slice());
216
216
  this.rowTotals[flatRowKey].push(record);
217
217
  }
@@ -437,7 +437,6 @@ let initDRPivotTable = function($, window, document) {
437
437
 
438
438
  return resultsArr;
439
439
  } else {
440
- let tooMuch = false;
441
440
  const show_more_than_thousand_rows = _.get(opts, 'chartOptions.table_options.show_more_than_thousand_rows', false);
442
441
  if (pvtData &&
443
442
  (pvtData.rowKeys.length > 1000 || pvtData.colKeys.length > 500) &&
@@ -445,15 +444,16 @@ let initDRPivotTable = function($, window, document) {
445
444
  !show_more_than_thousand_rows) {
446
445
  pvtData.rowKeys = [];
447
446
  pvtData.colKeys = [];
448
- tooMuch = true;
449
- opts.error_has_occurred = true;
450
- opts.error_params = $.pivotUtilities.errorHandling.placeholders.tooMuchData;
447
+
448
+ const tooMuchDataError = new TooMuchDataError();
449
+ console.error(tooMuchDataError.title);
450
+ throw tooMuchDataError;
451
451
  }
452
- return SubtotalRenderer(pvtData, opts, charttype, tooMuch, opts.error_params);
452
+ return SubtotalRenderer(pvtData, opts, charttype);
453
453
  }
454
454
  }
455
455
 
456
- SubtotalRenderer = function(pivotData, opts, charttype, tooMuch = false, error_params) {
456
+ SubtotalRenderer = function(pivotData, opts, charttype) {
457
457
  var addClass, allTotal, arrowCollapsed, arrowExpanded, buildColHeaderHeader, buildColHeaderHeaders, buildColHeaderHeadersClickEvents, buildColHeaders, buildColTotals, buildColTotalsHeader, buildGrandTotal, buildRowHeaderHeaders, buildRowHeaderHeadersClickEvents, buildRowHeaders, buildRowTotalsHeader, buildValues, classColCollapsed, classColExpanded, classColHide, classColShow, classCollapsed, classExpanded, classRowCollapsed, classRowExpanded, classRowHide, classRowShow, clickStatusCollapsed, clickStatusExpanded, colAttrs, colDisableAfter, colKeys, colTotals, collapseCol, collapseColsAt, collapseHideDescendantRow, collapseRow, collapseRowsAt, collapseShowColSubtotal, collapseShowRowSubtotal, applyInlineStyles, createElement, defaults, expandChildCol, expandChildRow, expandCol, expandColsAt, expandHideColSubtotal, expandHideRowSubtotal, expandRow, expandRowsAt, expandShowColSubtotal, expandShowRowSubtotal, getTableEventHandlers, hasClass, hideDescendantCol, isColDisable, isColDisableExpandCollapse, isColHideOnExpand, isRowDisable, isRowDisableExpandCollapse, isRowHideOnExpand, main, getSubtotalInBrackets, processKeys, encodeHtmlEntities, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, removeClass, replaceClass, rowAttrs, rowDisableAfter, rowKeys, rowTotals, setAttributes, showChildCol, showChildRow, toggleCol, toggleColHeaderHeader, toggleRow, toggleRowHeaderHeader, tree, subscribeToClick;
458
458
  var createTotalValsBolder, createGrandTotalBolder, getHeaderColorProperties, colorizeRowLabelHeaders, colorizeTableIfNeed, valueNoDashes, getColorsWithOffsetForTable, offsetColors, handleFreezePanesScroll, selectFreezableElements, removeRowHeaderNullValue;
459
459
  var getAdditionalAggregation, buildAdditionalHeaderCols, buildAdditionalHeaderRows, buildAdditionalColValues, buildAdditionalRowValues, buildAdditionalRowTotals, buildAdditionalColTotals;
@@ -1526,7 +1526,7 @@ let initDRPivotTable = function($, window, document) {
1526
1526
  if (opts.chartOptions.isSmartQueriesEnabled && flatRowKey.split(' , ').includes(DR_SCENARIO.Forecast)) {
1527
1527
  const actualsRow = tree[flatRowKey.replace(DR_SCENARIO.Forecast, DR_SCENARIO.SQ_Actuals)] || {};
1528
1528
  if (actualsRow && actualsRow[flatColKey]) {
1529
- val += actualsRow[flatColKey]?.value() || 0;
1529
+ val += (actualsRow[flatColKey] && actualsRow[flatColKey].value()) || 0;
1530
1530
  }
1531
1531
  }
1532
1532
  isColSubtotal = colHeader.children.length !== 0;
@@ -1572,7 +1572,7 @@ let initDRPivotTable = function($, window, document) {
1572
1572
 
1573
1573
  val = totalAggregator.value();
1574
1574
  if (opts.chartOptions.isSmartQueriesEnabled && flatRowKey.split(' , ').includes(DR_SCENARIO.Forecast)) {
1575
- val += rowTotals[flatRowKey.replace(DR_SCENARIO.Forecast, DR_SCENARIO.SQ_Actuals)]?.value() || 0;
1575
+ val += _.get(rowTotals[flatRowKey.replace(DR_SCENARIO.Forecast, DR_SCENARIO.SQ_Actuals)], 'value', () => null)() || 0;
1576
1576
  }
1577
1577
  style = "pvtTotal rowTotal";
1578
1578
  if (isRowSubtotal) {
@@ -2356,6 +2356,9 @@ let initDRPivotTable = function($, window, document) {
2356
2356
  main = function(rowAttrs, rowKeys, colAttrs, colKeys, pivotData) {
2357
2357
  if (opts.chartOptions.isSmartQueriesEnabled) {
2358
2358
  rowKeys = rowKeys.filter(rowKey => !rowKey.includes(DR_SCENARIO.SQ_Actuals));
2359
+ rowKeys = Array.from(
2360
+ new Set(rowKeys.map(JSON.stringify))
2361
+ ).map(JSON.parse);
2359
2362
  }
2360
2363
  var c,rowspan, colHeaderCols, colHeaderHeaders, colHeaders, h, k, l, len, len1, result, rowHeaderHeaders, rowHeaderRows, rowHeaders, tbody, thead, tr;
2361
2364
  rowHeaders = [];
@@ -2494,24 +2497,13 @@ let initDRPivotTable = function($, window, document) {
2494
2497
  resultsArr.push(subTitle);
2495
2498
  }
2496
2499
 
2497
- if (tooMuch) {
2498
- const defaultPlaceholder = $(`
2499
- <div class="noData--table-many-rows">
2500
- <span><i class="noData-icon dr-icon-info"></i> There are too many rows to display in the table.</span>
2501
- <span>Please filter or change the table type in options.</span>
2502
- </div>
2503
- `);
2504
-
2505
- resultsArr.push($.pivotUtilities.errorHandling.getErrorPlaceholder(error_params) || defaultPlaceholder);
2506
- } else {
2507
- var tableContainer = document.createElement("div");
2508
- tableContainer.className = "pivot-div";
2509
- tableContainer.appendChild(result);
2510
- if (opts.chartOptions.table_options.freeze_panes) {
2511
- tableContainer.onscroll = handleFreezePanesScroll(selectFreezableElements(tableContainer));
2512
- }
2513
- resultsArr.push(tableContainer);
2500
+ var tableContainer = document.createElement("div");
2501
+ tableContainer.className = "pivot-div";
2502
+ tableContainer.appendChild(result);
2503
+ if (opts.chartOptions.table_options.freeze_panes) {
2504
+ tableContainer.onscroll = handleFreezePanesScroll(selectFreezableElements(tableContainer));
2514
2505
  }
2506
+ resultsArr.push(tableContainer);
2515
2507
 
2516
2508
  var wrapper = document.createElement("div");
2517
2509
  wrapper.className = "pivot-wrapper";
@@ -2522,7 +2514,7 @@ let initDRPivotTable = function($, window, document) {
2522
2514
  };
2523
2515
  return main(rowAttrs, rowKeys, colAttrs, colKeys, pivotData);
2524
2516
  };
2525
- // $.pivotUtilities.subtotal_renderers = SubtotalRenderer;
2517
+
2526
2518
  $.pivotUtilities.subtotal_renderers = NovixRenderer;
2527
2519
  $.pivotUtilities.delim = delim;
2528
2520