@datarailsshared/dr_renderer 1.3.27 → 1.3.31

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.3.27",
3
+ "version": "1.3.31",
4
4
  "description": "DataRails charts and tables renderer",
5
5
  "keywords": [
6
6
  "datarails",
@@ -0,0 +1,323 @@
1
+ const _ = require('lodash');
2
+ const helpers = require("../dr-renderer-helpers");
3
+ const {DrGaugeChart} = require("./dr_gauge_chart");
4
+
5
+ const GAUGE_CATEGORIES_SUMMARY_OPTIONS_DEFAULT = {
6
+ gauge: {
7
+ background: "#fff",
8
+ startAngle: -90,
9
+ endAngle: 90,
10
+ thickness: 17,
11
+ tickLength: 0,
12
+ tickWidth: 0,
13
+ valueOffset: [0, 0, 0, 0],
14
+ offset: [12, 8, 12, 8],
15
+ goalIcon: '',
16
+ goalIconSize: [0, 0],
17
+ pivot: {
18
+ radius: 0,
19
+ color: "#808080",
20
+ },
21
+ colors: {
22
+ meta: "#333",
23
+ goal: "#4646CE",
24
+ },
25
+ },
26
+ goal: {
27
+ title: "Goal",
28
+ value: 1000000,
29
+ },
30
+ isAbsoluteValue: false,
31
+ segments: [
32
+ {
33
+ title: 'Completed',
34
+ count: 0,
35
+ isCompletionParameter: true,
36
+ color: '#037C5A',
37
+ },
38
+ {
39
+ title: 'Overdue',
40
+ count: 0,
41
+ color: '#BF1D30',
42
+ },
43
+ {
44
+ title: 'Pending',
45
+ count: 0,
46
+ color: '#FFA310',
47
+ },
48
+ {
49
+ title: 'Remaining',
50
+ count: 0,
51
+ color: '#F0F1F4',
52
+ }],
53
+ };
54
+
55
+ function DrGaugeCategoriesSummaryChart(pivotData, opts) {
56
+ this.completionPercentage = 0;
57
+
58
+ this.render = function () {
59
+ return DrGaugeChart.highchartsRenderer.ptCreateElementAndDraw(this.configChart(), opts);
60
+ };
61
+
62
+ this.createPlotBands = function (options) {
63
+ const {
64
+ segments,
65
+ goal: { value: goalValue },
66
+ gauge: { thickness },
67
+ } = options;
68
+
69
+ let bands = segments.map((item, index) => {
70
+ return {
71
+ from: item.from,
72
+ to: item.to,
73
+ color: item.color,
74
+ thickness: thickness,
75
+ title: item.title,
76
+ };
77
+ });
78
+
79
+ if (bands.length === 0) {
80
+ bands = [
81
+ {
82
+ from: 0,
83
+ to: 100,
84
+ color: '#F0F1F4',
85
+ thickness: thickness,
86
+ title: 'None',
87
+ }
88
+ ]
89
+ }
90
+
91
+ // clamp last segment
92
+ bands[bands.length - 1].to = Math.max(bands[bands.length - 1].to, goalValue);
93
+
94
+ return bands;
95
+ };
96
+
97
+ this.getDefaultValueForChart = function (type, existing_options) {
98
+ return DrGaugeChart.highchartsRenderer.getDefaultValueForChart(type, existing_options);
99
+ };
100
+
101
+ this.mergeOptions = function (options) {
102
+ return helpers.mergeDeep(
103
+ JSON.parse(JSON.stringify(GAUGE_CATEGORIES_SUMMARY_OPTIONS_DEFAULT)),
104
+ this.getDefaultValueForChart(DrGaugeChart.highchartsRenderer.CHART_TYPES.GAUGE_CHART_CATEGORIES_SUMMARY),
105
+ options
106
+ );
107
+ };
108
+
109
+ this.prepareSegments = function (options) {
110
+ let segmentsSumAggregator = 0;
111
+ let segmentsOutput = [];
112
+ for (let i = 0; i < options.segments.length; i++) {
113
+ let currentSegment = options.segments[i];
114
+ segmentsOutput.push(
115
+ {
116
+ from: segmentsSumAggregator,
117
+ to: segmentsSumAggregator += currentSegment.count,
118
+ color: currentSegment.color,
119
+ name: currentSegment.title,
120
+ }
121
+ );
122
+ }
123
+ segmentsOutput = segmentsOutput.filter(
124
+ (segment) => {
125
+ return segment.from !== segment.to;
126
+ }
127
+ );
128
+ options.segments = segmentsOutput;
129
+ options.goal = {
130
+ title: '',
131
+ value: segmentsSumAggregator,
132
+ };
133
+ }
134
+
135
+ this.getCompletionPercentage = function (options) {
136
+ const countOfCompletedItems = options.segments.find(segment => !!segment.isCompletionParameter)?.count || 0;
137
+ const totalCount = options.segments.reduce((acc, segment) => acc + segment.count, 0);
138
+ if (totalCount === 0) {
139
+ return 0;
140
+ }
141
+ return Math.round(countOfCompletedItems / totalCount * 100);
142
+ }
143
+
144
+ this.clampValueToPane = function (value, max = this.max, min = this.min) {
145
+ const correction = Math.abs(max - min) * 0.02;
146
+ return helpers.clamp(min - correction, value, max + correction);
147
+ };
148
+
149
+
150
+ this.formatValueLabel = function (value, options) {
151
+ return `<span style="display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: ${
152
+ options.label.font_size
153
+ }px;">
154
+ <span style="font-weight: 600; font-size: 1.5em; line-height: 1; color: ${options.label.font_color}">
155
+ ${this.completionPercentage}%
156
+ </span>
157
+ <span style="font-weight: 600; font-size: 0.75em; line-height: 1; color: ${
158
+ options.gauge.colors.meta
159
+ };">Completed</span>
160
+ </span>`;
161
+ };
162
+
163
+ this.clampValueToPane = function (value, max = this.max, min = this.min) {
164
+ const correction = Math.abs(max - min) * 0.02;
165
+ return helpers.clamp(min - correction, value, max + correction);
166
+ };
167
+
168
+ this.createValueLabel = function (chart, options) {
169
+ const label = chart.renderer.text(this.formatValueLabel(this.value, options), 0, 0, true).add().toFront();
170
+
171
+ helpers.removeSVGTextCorrection(label, "yCorr");
172
+
173
+ label.attr(DrGaugeChart.getValueLabelPosition(chart, options)).css({
174
+ transform: "translateX(-50%) translateY(-100%)",
175
+ });
176
+
177
+ return label;
178
+ };
179
+
180
+
181
+ this.getPaneDimensions = function (chart, options) {
182
+ const {renderer} = chart;
183
+ const {offset} = options.gauge;
184
+
185
+ const offsetBottom = options.gauge.valueOffset[0] + options.gauge.valueOffset[2] + offset[2];
186
+
187
+ const radiuses = [chart.chartWidth / 2 - Math.max(offset[1], offset[3]), chart.chartHeight - offsetBottom - offset[0]];
188
+
189
+ radiuses.push((chart.chartWidth / 2 - offset[1]) / Math.sin(Math.abs(Math.PI / 2)));
190
+ radiuses.push((chart.chartHeight - offsetBottom - offset[0]) / Math.cos(Math.abs(Math.PI / 2)));
191
+
192
+ return {
193
+ radius: Math.min(...radiuses),
194
+ center: [chart.chartWidth / 2, chart.chartHeight - offsetBottom],
195
+ };
196
+ };
197
+
198
+ this.setPane = function (chart, options) {
199
+ const {radius, center} = this.getPaneDimensions(chart, options);
200
+ chart.pane[0].options.size = 2 * radius;
201
+ chart.pane[0].options.center = center;
202
+ chart.yAxis[0].options.plotBands.forEach((band) => {
203
+ band.outerRadius = radius - (options.gauge.tickLength - options.gauge.thickness) / 2;
204
+ });
205
+ };
206
+
207
+ this.setCustomElements = function (chart, options) {
208
+ chart.label = this.createValueLabel(chart, options);
209
+ chart.startBorder = DrGaugeChart.createBorder(chart, options, "start");
210
+ chart.endBorder = DrGaugeChart.createBorder(chart, options, "end");
211
+ };
212
+
213
+ this.updateCustomElements = function (chart, options) {
214
+ chart.startBorder.attr(DrGaugeChart.getBorderPosition(chart, options, "start"));
215
+ chart.endBorder.attr(DrGaugeChart.getBorderPosition(chart, options, "end"));
216
+ chart.label.attr(DrGaugeChart.getValueLabelPosition(chart, options));
217
+ };
218
+
219
+ this.moveCustomElementsToFront = function (chart) {
220
+ chart.startBorder.toFront();
221
+ chart.endBorder.toFront();
222
+ };
223
+
224
+ this.configChart = function () {
225
+ return {
226
+ title: {
227
+ text: null,
228
+ },
229
+ subtitle: null,
230
+ exporting: {
231
+ allowHTML: true,
232
+ },
233
+ tooltip: {
234
+ enabled: false,
235
+ },
236
+ chart: {
237
+ type: "gauge",
238
+ backgroundColor: this.options.gauge.background,
239
+ plotBackgroundColor: null,
240
+ plotBackgroundImage: null,
241
+ plotBorderWidth: 0,
242
+ plotShadow: false,
243
+ events: {
244
+ render: ({target: chart}) => {
245
+ this.moveCustomElementsToFront(chart);
246
+ },
247
+ beforeRedraw: ({target: chart}) => {
248
+ this.setPane(chart, this.options);
249
+ this.updateCustomElements(chart, this.options);
250
+ },
251
+ beforeRender: ({target: chart}) => {
252
+ this.setPane(chart, this.options);
253
+ this.setCustomElements(chart, this.options);
254
+ }
255
+ },
256
+ margin: [0, 0, 0, 0],
257
+ spacing: [0, 0, 0, 0],
258
+ },
259
+
260
+ pane: {
261
+ startAngle: -90,
262
+ endAngle: 90,
263
+ background: null,
264
+ center: [0, 0],
265
+ },
266
+
267
+ // the value axis
268
+ yAxis: {
269
+ min: this.min,
270
+ max: this.max,
271
+ tickPositions: this.ticks,
272
+ tickPosition: "inside",
273
+ tickColor: this.options.gauge.background,
274
+ tickLength: this.options.gauge.tickLength,
275
+ tickWidth: this.options.gauge.tickWidth,
276
+ minorTickInterval: null,
277
+ labels: {
278
+ enabled: false
279
+ },
280
+ lineWidth: 0,
281
+ plotBands: this.plotBands,
282
+ },
283
+
284
+ series: [
285
+ {
286
+ name: null,
287
+ data: [this.clampValueToPane(this.value)],
288
+ dataLabels: [
289
+ {
290
+ enabled: false,
291
+ },
292
+ ],
293
+ dial: {
294
+ radius: "0",
295
+ backgroundColor: "rgba(0, 0, 0, 0)",
296
+ baseWidth: 2 * this.options.gauge.pivot.radius,
297
+ baseLength: "0%",
298
+ rearLength: "0%",
299
+ },
300
+ pivot: {
301
+ backgroundColor: "rgba(0, 0, 0, 0)",
302
+ radius: this.options.gauge.pivot.radius,
303
+ },
304
+ },
305
+ ],
306
+ };
307
+ };
308
+
309
+
310
+ this.options = this.mergeOptions(opts.chartOptions);
311
+ this.completionPercentage = this.getCompletionPercentage(this.options);
312
+ this.prepareSegments(this.options);
313
+ this.aggregation = pivotData.getAggregator([], []);
314
+ this.format = this.aggregation.widget_values_format;
315
+ this.goal = this.options.goal;
316
+ this.plotBands = this.createPlotBands(this.options);
317
+ this.ticks = DrGaugeChart.createTicks(this.plotBands, this.options);
318
+ this.value = DrGaugeChart.getValue(pivotData, opts);
319
+ this.max = this.ticks[this.ticks.length - 1];
320
+ this.min = this.ticks[0];
321
+ }
322
+
323
+ module.exports = {DrGaugeCategoriesSummaryChart, GAUGE_CATEGORIES_SUMMARY_OPTIONS_DEFAULT};
@@ -84,34 +84,7 @@ function DrGaugeChart(pivotData, opts) {
84
84
  return (value - min) < (max - min) / 2;
85
85
  };
86
86
 
87
- this.createPlotBands = function (options) {
88
- const {
89
- segments,
90
- isAbsoluteValue,
91
- goal: { value: goalValue },
92
- gauge: { thickness },
93
- } = options;
94
-
95
- const bands = segments.map((item, index) => {
96
- const itemFrom = !!index ? item.from - 1 : item.from;
97
- return {
98
- from: isAbsoluteValue ? itemFrom : (itemFrom * goalValue) / 100,
99
- to: isAbsoluteValue ? item.to : (item.to * goalValue) / 100,
100
- color: item.color,
101
- thickness: thickness,
102
- title: item.title,
103
- };
104
- });
105
-
106
- // clamp last segment
107
- bands[bands.length - 1].to = Math.max(bands[bands.length - 1].to, goalValue);
108
-
109
- return bands;
110
- };
111
-
112
- this.createTicks = function (plotBands, options) {
113
- return _.uniq([plotBands[0].from || 0, ...plotBands.map((b) => b.to), options.goal.value]).sort((a, b) => a - b);
114
- };
87
+ this.createTicks = DrGaugeChart.createTicks;
115
88
 
116
89
  this.mergeOptions = function (options) {
117
90
  return helpers.mergeDeep(
@@ -148,16 +121,16 @@ function DrGaugeChart(pivotData, opts) {
148
121
  <span style="font-weight: 600; font-size: 1.3em; line-height: 1; color: ${options.label.font_color}">
149
122
  ${this.formatValue(value)}
150
123
  ${
151
- options.label.show_percentage_in_value
152
- ? `<span style="font-size: 0.5833em; font-weight: 600; color: ${
153
- options.gauge.colors.meta
154
- };">(${this.toPercent(value)})</span>`
155
- : ""
156
- }
124
+ options.label.show_percentage_in_value
125
+ ? `<span style="font-size: 0.5833em; font-weight: 600; color: ${
126
+ options.gauge.colors.meta
127
+ };">(${this.toPercent(value)})</span>`
128
+ : ""
129
+ }
157
130
  </span>
158
131
  <span style="font-weight: 500; font-size: 0.875em; line-height: 1; color: ${
159
- options.gauge.colors.meta
160
- };">Current status</span>
132
+ options.gauge.colors.meta
133
+ };">Current status</span>
161
134
  </span>`;
162
135
  };
163
136
 
@@ -176,8 +149,8 @@ function DrGaugeChart(pivotData, opts) {
176
149
  : "";
177
150
  const percentage = options.label.show_percentage_in_segments
178
151
  ? `<span style="font-size: 0.75em; color: ${options.gauge.colors.meta}; font-weight: 400;">(${this.toPercent(
179
- value
180
- )})</span>`
152
+ value
153
+ )})</span>`
181
154
  : "";
182
155
 
183
156
  return `<span style="
@@ -194,67 +167,6 @@ function DrGaugeChart(pivotData, opts) {
194
167
  </span>`;
195
168
  };
196
169
 
197
- this.getValue = function (pivotData, opts) {
198
- const lineSeries = this.ptCreateBasicLineSeries(pivotData, null, true, null, null, opts, {});
199
-
200
- let total = _.flatten(lineSeries
201
- .map((s) => s.data.map((v) => v))
202
- .filter((v) => !_.isNaN(v))
203
- );
204
-
205
- let aggfunc = (a, b) => a + b;
206
- let base = 0;
207
- let singleValueAgg = this.getSingleValueAgg(
208
- {
209
- value: {
210
- value: "Sum",
211
- },
212
- },
213
- aggfunc,
214
- base
215
- );
216
-
217
- aggfunc = singleValueAgg.aggfunc;
218
- base = singleValueAgg.base;
219
-
220
- const aggregator = pivotData.getAggregator([], []);
221
- const value = total.length > 0 ? total.reduce(aggfunc, base) : aggregator.value();
222
-
223
- return value;
224
- };
225
-
226
- this.getBorderPosition = function (chart, options, position) {
227
- const { center, size } = chart.pane[0].options;
228
- const {
229
- gauge: { tickLength, tickWidth },
230
- } = options;
231
-
232
- return {
233
- x: position === "start" ? center[0] - size / 2 + tickLength / 2 : center[0] + size / 2 - tickLength / 2,
234
- y: center[1] + tickWidth / 2,
235
- };
236
- };
237
-
238
- this.createBorder = function (chart, options, position) {
239
- return chart.renderer
240
- .arc(
241
- Object.assign(this.getBorderPosition(chart, options, position), {
242
- r: options.gauge.thickness / 2,
243
- innerR: 0,
244
- start: 0,
245
- end: Math.PI,
246
- })
247
- )
248
- .attr({
249
- fill:
250
- position === "start"
251
- ? chart.yAxis[0].options.plotBands[0].color
252
- : chart.yAxis[0].options.plotBands.slice(-1)[0].color,
253
- })
254
- .add()
255
- .toFront();
256
- };
257
-
258
170
  this.getGoalIconPosition = function (chart, options) {
259
171
  const { center, size } = chart.pane[0].options;
260
172
  const radius = size / 2;
@@ -277,20 +189,12 @@ function DrGaugeChart(pivotData, opts) {
277
189
  .toFront();
278
190
  };
279
191
 
280
- this.getValueLabelPosition = function (chart, options) {
281
- const { center } = chart.pane[0].options;
282
- return {
283
- x: center[0],
284
- y: center[1] + options.gauge.valueOffset[0],
285
- };
286
- };
287
-
288
192
  this.createValueLabel = function (chart, options) {
289
193
  const label = chart.renderer.text(this.formatValueLabel(this.value, options), 0, 0, true).add().toFront();
290
194
 
291
195
  helpers.removeSVGTextCorrection(label, "yCorr");
292
196
 
293
- label.attr(this.getValueLabelPosition(chart, options)).css({
197
+ label.attr(DrGaugeChart.getValueLabelPosition(chart, options)).css({
294
198
  transform: "translateX(-50%)",
295
199
  });
296
200
 
@@ -314,12 +218,12 @@ function DrGaugeChart(pivotData, opts) {
314
218
  // depends on label width
315
219
  radiuses.push(
316
220
  (chart.chartWidth / 2 - label.bBox.width - Math.max(offset[1], offset[3])) /
317
- Math.sin(Math.abs(Math.PI / 2 - angle))
221
+ Math.sin(Math.abs(Math.PI / 2 - angle))
318
222
  );
319
223
  // depends on label height
320
224
  radiuses.push(
321
225
  (chart.chartHeight - offsetBottom - label.bBox.height / 2 - offset[0]) /
322
- Math.cos(Math.abs(Math.PI / 2 - angle))
226
+ Math.cos(Math.abs(Math.PI / 2 - angle))
323
227
  );
324
228
  label.destroy();
325
229
  });
@@ -361,7 +265,7 @@ function DrGaugeChart(pivotData, opts) {
361
265
 
362
266
  // If goal is hidden, we need to always show goal and hide the closest visible label before it
363
267
  this.updateLabelsWhenGoalIsHidden(ticks, options);
364
-
268
+
365
269
  };
366
270
 
367
271
  this.updateLabelsWhenGoalIsHidden = function (ticks, options) {
@@ -461,16 +365,41 @@ function DrGaugeChart(pivotData, opts) {
461
365
 
462
366
  this.setCustomElements = function (chart, options) {
463
367
  chart.label = this.createValueLabel(chart, options);
464
- chart.startBorder = this.createBorder(chart, options, "start");
465
- chart.endBorder = this.createBorder(chart, options, "end");
368
+ chart.startBorder = DrGaugeChart.createBorder(chart, options, "start");
369
+ chart.endBorder = DrGaugeChart.createBorder(chart, options, "end");
466
370
  chart.goalIcon = this.createGoalIcon(chart, options);
467
371
  };
468
372
 
469
373
  this.updateCustomElements = function (chart, options) {
470
- chart.startBorder.attr(this.getBorderPosition(chart, options, "start"));
471
- chart.endBorder.attr(this.getBorderPosition(chart, options, "end"));
374
+ chart.startBorder.attr(DrGaugeChart.getBorderPosition(chart, options, "start"));
375
+ chart.endBorder.attr(DrGaugeChart.getBorderPosition(chart, options, "end"));
472
376
  chart.goalIcon.attr(this.getGoalIconPosition(chart, options));
473
- chart.label.attr(this.getValueLabelPosition(chart, options));
377
+ chart.label.attr(DrGaugeChart.getValueLabelPosition(chart, options));
378
+ };
379
+
380
+ this.createPlotBands = function (options) {
381
+ const {
382
+ segments,
383
+ isAbsoluteValue,
384
+ goal: { value: goalValue },
385
+ gauge: { thickness },
386
+ } = options;
387
+
388
+ const bands = segments.map((item, index) => {
389
+ const itemFrom = !!index ? item.from - 1 : item.from;
390
+ return {
391
+ from: isAbsoluteValue ? itemFrom : (itemFrom * goalValue) / 100,
392
+ to: isAbsoluteValue ? item.to : (item.to * goalValue) / 100,
393
+ color: item.color,
394
+ thickness: thickness,
395
+ title: item.title,
396
+ };
397
+ });
398
+
399
+ // clamp last segment
400
+ bands[bands.length - 1].to = Math.max(bands[bands.length - 1].to, goalValue);
401
+
402
+ return bands;
474
403
  };
475
404
 
476
405
  this.moveCustomElementsToFront = function (chart) {
@@ -593,9 +522,98 @@ function DrGaugeChart(pivotData, opts) {
593
522
  this.goal = this.options.goal;
594
523
  this.plotBands = this.createPlotBands(this.options);
595
524
  this.ticks = this.createTicks(this.plotBands, this.options);
596
- this.value = this.getValue(pivotData, opts);
525
+ this.value = DrGaugeChart.getValue(pivotData, opts);
597
526
  this.max = this.ticks[this.ticks.length - 1];
598
527
  this.min = this.ticks[0];
599
528
  }
600
529
 
530
+ DrGaugeChart.createTicks = function (plotBands, options) {
531
+ return _.uniq([plotBands[0].from || 0, ...plotBands.map((b) => b.to), options.goal.value]).sort((a, b) => a - b);
532
+ };
533
+
534
+ DrGaugeChart.getBorderPosition = function (chart, options, position) {
535
+ const { center, size } = chart.pane[0].options;
536
+ const {
537
+ gauge: { tickLength, tickWidth },
538
+ } = options;
539
+
540
+ return {
541
+ x: position === "start" ? center[0] - size / 2 + tickLength / 2 : center[0] + size / 2 - tickLength / 2,
542
+ y: center[1] + tickWidth / 2,
543
+ };
544
+ };
545
+
546
+ DrGaugeChart.createBorder = function (chart, options, position) {
547
+ return chart.renderer
548
+ .arc(
549
+ Object.assign(DrGaugeChart.getBorderPosition(chart, options, position), {
550
+ r: options.gauge.thickness / 2,
551
+ innerR: 0,
552
+ start: 0,
553
+ end: Math.PI,
554
+ })
555
+ )
556
+ .attr({
557
+ fill:
558
+ position === "start"
559
+ ? chart.yAxis[0].options.plotBands[0].color
560
+ : chart.yAxis[0].options.plotBands.slice(-1)[0].color,
561
+ })
562
+ .add()
563
+ .toFront();
564
+ };
565
+
566
+ DrGaugeChart.getValueLabelPosition = function (chart, options) {
567
+ const { center } = chart.pane[0].options;
568
+ return {
569
+ x: center[0],
570
+ y: center[1] + options.gauge.valueOffset[0],
571
+ };
572
+ };
573
+
574
+ DrGaugeChart.ptCreateBasicLineSeries = function (pivotData, colors, onlyNumbers, isUniqueVals, additionOptions, opts, chartOptions) {
575
+ return DrGaugeChart.highchartsRenderer.ptCreateBasicLineSeries(
576
+ pivotData,
577
+ colors,
578
+ onlyNumbers,
579
+ isUniqueVals,
580
+ additionOptions,
581
+ opts,
582
+ chartOptions
583
+ );
584
+ };
585
+
586
+ DrGaugeChart.getSingleValueAgg = function (opts, aggfunc, base) {
587
+ return DrGaugeChart.highchartsRenderer.getSingleValueAgg(opts, aggfunc, base);
588
+ };
589
+
590
+ DrGaugeChart.getValue = function (pivotData, opts) {
591
+ const lineSeries = DrGaugeChart.ptCreateBasicLineSeries(pivotData, null, true, null, null, opts, {});
592
+
593
+ let total = _.flatten(lineSeries
594
+ .map((s) => s.data.map((v) => v))
595
+ .filter((v) => !_.isNaN(v))
596
+ );
597
+
598
+ let aggfunc = (a, b) => a + b;
599
+ let base = 0;
600
+ let singleValueAgg = DrGaugeChart.getSingleValueAgg(
601
+ {
602
+ value: {
603
+ value: "Sum",
604
+ },
605
+ },
606
+ aggfunc,
607
+ base
608
+ );
609
+
610
+ aggfunc = singleValueAgg.aggfunc;
611
+ base = singleValueAgg.base;
612
+
613
+ const aggregator = pivotData.getAggregator([], []);
614
+ const value = total.length > 0 ? total.reduce(aggfunc, base) : aggregator.value();
615
+
616
+ return value;
617
+ };
618
+
601
619
  module.exports = { DrGaugeChart, GAUGE_OPTIONS_DEFAULT };
@@ -514,8 +514,8 @@ let initDRPivotTable = function($, window, document) {
514
514
  isColHideOnExpand = (ref5 = opts.colSubtotalDisplay) != null ? ref5.hideOnExpand : !opts.chartOptions.table_options.show_subtotals_for_columns;
515
515
  isColDisableExpandCollapse = (ref6 = opts.colSubtotalDisplay) != null ? ref6.disableExpandCollapse : void 0;
516
516
  colDisableAfter = (ref7 = opts.colSubtotalDisplay) != null ? ref7.disableAfter != null ? ref7.disableAfter : ref7.disableAfter = 9999 : void 0;
517
- arrowCollapsed = opts.arrowCollapsed != null ? opts.arrowCollapsed : opts.arrowCollapsed = '<i class="fa fa-plus dr-icon-add"></i> ';
518
- arrowExpanded = opts.arrowExpanded != null ? opts.arrowExpanded : opts.arrowExpanded = '<i class="fa fa-minus dr-icon-minus"></i> ';
517
+ arrowCollapsed = opts.arrowCollapsed != null ? opts.arrowCollapsed : opts.arrowCollapsed = '<i class="dr-icon-add"></i> ';
518
+ arrowExpanded = opts.arrowExpanded != null ? opts.arrowExpanded : opts.arrowExpanded = '<i class="dr-icon-minus"></i> ';
519
519
  colAttrs = pivotData.colAttrs;
520
520
  rowAttrs = pivotData.rowAttrs;
521
521
  rowKeys = pivotData.getRowKeys();
@@ -2476,7 +2476,12 @@ let initDRPivotTable = function($, window, document) {
2476
2476
  }
2477
2477
 
2478
2478
  if (tooMuch) {
2479
- const defaultPlaceholder = $('<div class="noData"><i class="fa fa-info"></i> There are too many rows to display in the table.<br>Please filter or change the table type in options.</div>');
2479
+ const defaultPlaceholder = $(`
2480
+ <div class="noData--table-many-rows">
2481
+ <span><i class="noData-icon dr-icon-info"></i> There are too many rows to display in the table.</span>
2482
+ <span>Please filter or change the table type in options.</span>
2483
+ </div>
2484
+ `);
2480
2485
 
2481
2486
  resultsArr.push($.pivotUtilities.errorHandling.getErrorPlaceholder(error_params) || defaultPlaceholder);
2482
2487
  } else {
@@ -2,6 +2,7 @@ const helpers = require('./dr-renderer-helpers');
2
2
  const { DrGaugeChart, GAUGE_OPTIONS_DEFAULT } = require('./charts/dr_gauge_chart');
3
3
  const { DrDonutChart } = require('./charts/dr_donut_chart');
4
4
  const seriesPointStylesHelper= require('./seriesPointStyles-helper');
5
+ const {DrGaugeCategoriesSummaryChart} = require("./charts/dr_gauge_categories_summary_chart");
5
6
 
6
7
  const mobileBrowserRegex = new RegExp([
7
8
  '(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)',
@@ -59,6 +60,7 @@ const CHART_TYPES = {
59
60
  GAUGE_SOLID_CHART: 'gauge-solid-chart',
60
61
  GAUGE_CHART: 'gauge-chart',
61
62
  GAUGE_CHART_ENHANCED: 'gauge-chart-enhanced',
63
+ GAUGE_CHART_CATEGORIES_SUMMARY: 'gauge-chart-categories-summary',
62
64
  KPI_WIDGET: 'kpi-widget',
63
65
  TEXT_WIDGET: 'text-widget',
64
66
  WATERFALL_BREAKDOWN: 'waterfall-chart-breakdown',
@@ -2274,6 +2276,10 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
2274
2276
  return new DrGaugeChart(pivotData, opts).render();
2275
2277
  };
2276
2278
 
2279
+ highchartsRenderer.ptRenderGaugeCategoriesSummary = (pivotData, opts) => {
2280
+ return new DrGaugeCategoriesSummaryChart(pivotData, opts).render();
2281
+ };
2282
+
2277
2283
  highchartsRenderer.ptRenderKpi = function (pivotData, opts) {
2278
2284
  var chartOptions = {};
2279
2285
 
@@ -4294,7 +4300,7 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
4294
4300
  let ret_str = '';
4295
4301
  if (options && options.total_value_options && options.total_value_options.filter_options && options.total_value_options.filter_options.axis == tr_axis) {
4296
4302
  //TODO add tooltip with description of filter
4297
- ret_str += '<i class="fa fa-filter"></i>';
4303
+ ret_str += '<i class="dr-icon-filter-old"></i>';
4298
4304
  }
4299
4305
 
4300
4306
  return ret_str;
@@ -7692,6 +7698,14 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
7692
7698
  legendName: 'Data Series',
7693
7699
  startedMessage: 'To get started, drag one field to the value section. Best practice: Drag one field to the filter section, and filter as required.',
7694
7700
  },
7701
+ [highchartsRenderer.CHART_TYPES.GAUGE_CHART_CATEGORIES_SUMMARY]: {
7702
+ name: 'Gauge chart categories summary',
7703
+ label: 'Gauge',
7704
+ title: 'Gauge chart showing summary sections for different categories.',
7705
+ axisName: 'X-Axis',
7706
+ legendName: 'Data Series',
7707
+ startedMessage: '',
7708
+ },
7695
7709
  'kpi-widget': {
7696
7710
  name: 'Kpi ',
7697
7711
  label: 'KPI',
@@ -8085,6 +8099,24 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
8085
8099
  },
8086
8100
  ]
8087
8101
  },
8102
+ {
8103
+ type: 'gauge-categories-summary',
8104
+ name: 'Gauge Categories Summary',
8105
+ class: 'google-visualization-charteditor-mini-gauge',
8106
+ subtypes: [
8107
+ {
8108
+ type: highchartsRenderer.CHART_TYPES.GAUGE_CHART_CATEGORIES_SUMMARY,
8109
+ name: highchartsRenderer.chartsTypesInfo[highchartsRenderer.CHART_TYPES.GAUGE_CHART_CATEGORIES_SUMMARY].name,
8110
+ class: 'google-visualization-charteditor-thumbs-gauge-solid',
8111
+ render: highchartsRenderer.ptRenderGaugeCategoriesSummary,
8112
+ suboptions: [
8113
+ highchartsRenderer.suboptions["label_gauge"],
8114
+ highchartsRenderer.suboptions["tooltips_gauge"],
8115
+ highchartsRenderer.suboptions["subtitle"]
8116
+ ]
8117
+ },
8118
+ ]
8119
+ },
8088
8120
  {
8089
8121
  type: 'kpi',
8090
8122
  name: 'KPI',
package/src/pivot.css CHANGED
@@ -5,6 +5,17 @@
5
5
  flex-direction: column;
6
6
  }
7
7
 
8
+ .pivot-wrapper .noData--table-many-rows {
9
+ display: flex;
10
+ flex-direction: column;
11
+ }
12
+ .pivot-wrapper .noData--table-many-rows > *:first-child {
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ line-height: 25px;
17
+ }
18
+
8
19
  table.pvtTable {
9
20
  font-size: 8pt;
10
21
  text-align: left;
@@ -228,16 +239,27 @@ table.pvtTable.newPvtTable thead tr th {
228
239
  border-right: 1px solid #fff;
229
240
  }
230
241
 
231
- table.pvtTable.newPvtTable thead tr th .fa,
232
- table.pvtTable.newPvtTable thead tr th .dr-icon-add,
233
- table.pvtTable.newPvtTable thead tr th .dr-icon-minus {
234
- padding: 2px;
235
- background-color: #ffffff;
236
- border-radius: 2px;
237
- margin-right: 2px;
238
- margin-left: 1px;
239
- font-size: 8px;
240
- color: #151a41;
242
+ table.pvtTable.newPvtTable thead tr th i,
243
+ table.pvtTable.newPvtTable tbody tr th i {
244
+ position: relative;
245
+ bottom: -1px;
246
+ background-color: #ffffff;
247
+ border-radius: 2px;
248
+ margin-right: 2px;
249
+ margin-left: 1px;
250
+ font-weight: bold;
251
+ font-size: 10px;
252
+ color: #151a41;
253
+ }
254
+
255
+ table.pvtTable.newPvtTable tbody tr th i {
256
+ bottom: -2px;
257
+ background-color: #dfe6ec;
258
+ }
259
+
260
+ table.pvtTable.newPvtTable thead tr th .dr-icon-filter-old,
261
+ table.pvtTable.newPvtTable tbody tr th .dr-icon-filter-old {
262
+ font-weight: normal;
241
263
  }
242
264
 
243
265
  table.pvtTable.newPvtTable.colorized tr th.colTotal,
@@ -261,14 +283,6 @@ table.pvtTable.newPvtTable tbody tr td.rowTotal {
261
283
  border-color: #ffffff !important;
262
284
  }
263
285
 
264
- table.pvtTable.newPvtTable tbody tr th .fa {
265
- padding: 2px;
266
- background-color: #dfe6ec;
267
- border-radius: 2px;
268
- margin-right: 2px;
269
- font-size: 8px;
270
- }
271
-
272
286
  table.pvtTable.newPvtTable tbody tr th,
273
287
  table.pvtTable.newPvtTable tbody tr td {
274
288
  border: 1px solid #dfe6ec;
@@ -306,7 +306,7 @@ describe("DrGaugeChart", () => {
306
306
  describe("createTicks", () => {
307
307
  it("should create a ticks array", () => {
308
308
  expect(
309
- chart.createTicks(
309
+ DrGaugeChart.createTicks(
310
310
  [
311
311
  {
312
312
  to: 100,
@@ -329,7 +329,7 @@ describe("DrGaugeChart", () => {
329
329
 
330
330
  it("should sort and remove duplicates", () => {
331
331
  expect(
332
- chart.createTicks(
332
+ DrGaugeChart.createTicks(
333
333
  [
334
334
  {
335
335
  to: 100,
@@ -707,12 +707,12 @@ describe("DrGaugeChart", () => {
707
707
  describe("getValue", () => {
708
708
  it("should return aggregator value unledss the total is empty", () => {
709
709
  DrGaugeChart.highchartsRenderer.ptCreateBasicLineSeries.mockReturnValue([]);
710
- expect(chart.getValue(mockPivotData, {})).toBe(mockAggregationValue);
710
+ expect(DrGaugeChart.getValue(mockPivotData, {})).toBe(mockAggregationValue);
711
711
  });
712
712
 
713
713
  it("should return value to display", () => {
714
714
  DrGaugeChart.highchartsRenderer.ptCreateBasicLineSeries.mockReturnValue([{ data: [2000] }]);
715
- expect(chart.getValue(mockPivotData, {})).toBe(2000);
715
+ expect(DrGaugeChart.getValue(mockPivotData, {})).toBe(2000);
716
716
  });
717
717
 
718
718
  it("should calculate total", () => {
@@ -721,7 +721,7 @@ describe("DrGaugeChart", () => {
721
721
  { data: [3000] },
722
722
  { data: [5000] },
723
723
  ]);
724
- expect(chart.getValue(mockPivotData, {})).toBe(10000);
724
+ expect(DrGaugeChart.getValue(mockPivotData, {})).toBe(10000);
725
725
  });
726
726
  });
727
727
 
@@ -745,14 +745,14 @@ describe("DrGaugeChart", () => {
745
745
  };
746
746
 
747
747
  it("return a start border position", () => {
748
- expect(chart.getBorderPosition(mockChart, mockOptions, "start")).toEqual({
748
+ expect(DrGaugeChart.getBorderPosition(mockChart, mockOptions, "start")).toEqual({
749
749
  x: 170,
750
750
  y: 201,
751
751
  });
752
752
  });
753
753
 
754
754
  it("return an end border position", () => {
755
- expect(chart.getBorderPosition(mockChart, mockOptions, "end")).toEqual({
755
+ expect(DrGaugeChart.getBorderPosition(mockChart, mockOptions, "end")).toEqual({
756
756
  x: 230,
757
757
  y: 201,
758
758
  });
@@ -761,7 +761,7 @@ describe("DrGaugeChart", () => {
761
761
 
762
762
  describe("createBorder", () => {
763
763
  beforeEach(() => {
764
- chart.getBorderPosition = jest.fn().mockReturnValue({
764
+ DrGaugeChart.getBorderPosition = jest.fn().mockReturnValue({
765
765
  x: 100,
766
766
  y: 200,
767
767
  });
@@ -805,7 +805,7 @@ describe("DrGaugeChart", () => {
805
805
  };
806
806
 
807
807
  it("should create a start border", () => {
808
- chart.createBorder(
808
+ DrGaugeChart.createBorder(
809
809
  mockChart,
810
810
  {
811
811
  gauge: {
@@ -834,7 +834,7 @@ describe("DrGaugeChart", () => {
834
834
  });
835
835
 
836
836
  it("should create an end border", () => {
837
- chart.createBorder(
837
+ DrGaugeChart.createBorder(
838
838
  mockChart,
839
839
  {
840
840
  gauge: {
@@ -990,7 +990,7 @@ describe("DrGaugeChart", () => {
990
990
  describe("getValueLabelPosition", () => {
991
991
  it("should return a value label position depends on the pane center and offsets", () => {
992
992
  expect(
993
- chart.getValueLabelPosition(
993
+ DrGaugeChart.getValueLabelPosition(
994
994
  {
995
995
  pane: [
996
996
  {
@@ -1012,7 +1012,7 @@ describe("DrGaugeChart", () => {
1012
1012
  });
1013
1013
 
1014
1014
  expect(
1015
- chart.getValueLabelPosition(
1015
+ DrGaugeChart.getValueLabelPosition(
1016
1016
  {
1017
1017
  pane: [
1018
1018
  {
@@ -1044,7 +1044,7 @@ describe("DrGaugeChart", () => {
1044
1044
 
1045
1045
  beforeEach(() => {
1046
1046
  chart.formatValueLabel = jest.fn().mockReturnValue("<div>Mock label</div>");
1047
- chart.getValueLabelPosition = jest.fn().mockReturnValue({
1047
+ DrGaugeChart.getValueLabelPosition = jest.fn().mockReturnValue({
1048
1048
  x: 100,
1049
1049
  y: 200,
1050
1050
  });
@@ -1540,7 +1540,7 @@ describe("DrGaugeChart", () => {
1540
1540
 
1541
1541
  // Spy on class methods
1542
1542
  jest.spyOn(chart, "createValueLabel").mockReturnValue(mockValueLabel);
1543
- jest.spyOn(chart, "createBorder").mockImplementation((chart, options, position) => {
1543
+ jest.spyOn(DrGaugeChart, "createBorder").mockImplementation((chart, options, position) => {
1544
1544
  if (position === "start") return mockStartBorder;
1545
1545
  if (position === "end") return mockEndBorder;
1546
1546
  });
@@ -1561,14 +1561,14 @@ describe("DrGaugeChart", () => {
1561
1561
  it("assigns the start border to chart.startBorder", () => {
1562
1562
  chart.setCustomElements(mockChart, mockOptions);
1563
1563
 
1564
- expect(chart.createBorder).toHaveBeenCalledWith(mockChart, mockOptions, "start");
1564
+ expect(DrGaugeChart.createBorder).toHaveBeenCalledWith(mockChart, mockOptions, "start");
1565
1565
  expect(mockChart.startBorder).toBe(mockStartBorder);
1566
1566
  });
1567
1567
 
1568
1568
  it("assigns the end border to chart.endBorder", () => {
1569
1569
  chart.setCustomElements(mockChart, mockOptions);
1570
1570
 
1571
- expect(chart.createBorder).toHaveBeenCalledWith(mockChart, mockOptions, "end");
1571
+ expect(DrGaugeChart.createBorder).toHaveBeenCalledWith(mockChart, mockOptions, "end");
1572
1572
  expect(mockChart.endBorder).toBe(mockEndBorder);
1573
1573
  });
1574
1574
 
@@ -1609,12 +1609,12 @@ describe("DrGaugeChart", () => {
1609
1609
  mockValueLabelPosition = { x: 70, y: 80 };
1610
1610
 
1611
1611
  // Spy on helper methods
1612
- jest.spyOn(chart, "getBorderPosition").mockImplementation((chart, options, position) => {
1612
+ jest.spyOn(DrGaugeChart, "getBorderPosition").mockImplementation((chart, options, position) => {
1613
1613
  if (position === "start") return mockStartPosition;
1614
1614
  if (position === "end") return mockEndPosition;
1615
1615
  });
1616
1616
  jest.spyOn(chart, "getGoalIconPosition").mockReturnValue(mockGoalIconPosition);
1617
- jest.spyOn(chart, "getValueLabelPosition").mockReturnValue(mockValueLabelPosition);
1617
+ jest.spyOn(DrGaugeChart, "getValueLabelPosition").mockReturnValue(mockValueLabelPosition);
1618
1618
  });
1619
1619
 
1620
1620
  afterEach(() => {
@@ -1624,14 +1624,14 @@ describe("DrGaugeChart", () => {
1624
1624
  it("updates startBorder attributes correctly", () => {
1625
1625
  chart.updateCustomElements(mockChart, mockOptions);
1626
1626
 
1627
- expect(chart.getBorderPosition).toHaveBeenCalledWith(mockChart, mockOptions, "start");
1627
+ expect(DrGaugeChart.getBorderPosition).toHaveBeenCalledWith(mockChart, mockOptions, "start");
1628
1628
  expect(mockChart.startBorder.attr).toHaveBeenCalledWith(mockStartPosition);
1629
1629
  });
1630
1630
 
1631
1631
  it("updates endBorder attributes correctly", () => {
1632
1632
  chart.updateCustomElements(mockChart, mockOptions);
1633
1633
 
1634
- expect(chart.getBorderPosition).toHaveBeenCalledWith(mockChart, mockOptions, "end");
1634
+ expect(DrGaugeChart.getBorderPosition).toHaveBeenCalledWith(mockChart, mockOptions, "end");
1635
1635
  expect(mockChart.endBorder.attr).toHaveBeenCalledWith(mockEndPosition);
1636
1636
  });
1637
1637
 
@@ -1645,7 +1645,7 @@ describe("DrGaugeChart", () => {
1645
1645
  it("updates label attributes correctly", () => {
1646
1646
  chart.updateCustomElements(mockChart, mockOptions);
1647
1647
 
1648
- expect(chart.getValueLabelPosition).toHaveBeenCalledWith(mockChart, mockOptions);
1648
+ expect(DrGaugeChart.getValueLabelPosition).toHaveBeenCalledWith(mockChart, mockOptions);
1649
1649
  expect(mockChart.label.attr).toHaveBeenCalledWith(mockValueLabelPosition);
1650
1650
  });
1651
1651
  });
@@ -917,7 +917,7 @@ describe('highcharts_renderer', () => {
917
917
 
918
918
  it('should return filter icon for matching axis', () => {
919
919
  const axis = 'row'
920
- const expected = '<i class="fa fa-filter"></i>'
920
+ const expected = '<i class="dr-icon-filter-old"></i>'
921
921
  const result = highchartsRenderer.getIconsForTotalOptions(options, axis)
922
922
  expect(result).toEqual(expected)
923
923
  });