@datarailsshared/dr_renderer 1.2.453 → 1.2.455
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/charts/dr_gauge_chart.js +563 -0
- package/src/dr-renderer-helpers.js +45 -0
- package/src/dr_chart_tooltip.js +277 -0
- package/src/highcharts_renderer.js +210 -4
- package/tests/dr-renderer-helpers.test.js +98 -0
- package/tests/dr_chart_tooltip.test.js +739 -0
- package/tests/dr_gauge_chart.test.js +1931 -0
- package/tests/highcharts_renderer.test.js +195 -0
@@ -0,0 +1,1931 @@
|
|
1
|
+
const { DrGaugeChart, GAUGE_OPTIONS_DEFAULT } = require("../src/charts/dr_gauge_chart");
|
2
|
+
const helpers = require("../src/dr-renderer-helpers");
|
3
|
+
const { DrChartTooltip } = require("../src/dr_chart_tooltip");
|
4
|
+
|
5
|
+
jest.mock("../src/dr_chart_tooltip"); // Mock the tooltip class
|
6
|
+
|
7
|
+
const mockFormattedValue = "16,549";
|
8
|
+
|
9
|
+
DrGaugeChart.highchartsRenderer = {
|
10
|
+
CHART_TYPES: {
|
11
|
+
GAUGE_CHART_ENHANCE: "gauge-chart-enhanced",
|
12
|
+
},
|
13
|
+
getDefaultValueForChart: jest.fn(),
|
14
|
+
ptCreateElementAndDraw: jest.fn(),
|
15
|
+
ptCreateBasicLineSeries: jest.fn().mockReturnValue([{ data: [1] }, { data: [2] }]),
|
16
|
+
getSingleValueAgg: jest.fn().mockReturnValue({
|
17
|
+
aggfunc: (a, b) => a + b,
|
18
|
+
base: 0,
|
19
|
+
}),
|
20
|
+
formatValue: jest.fn().mockReturnValue({
|
21
|
+
value: mockFormattedValue,
|
22
|
+
}),
|
23
|
+
};
|
24
|
+
|
25
|
+
const mockAggregationValue = 1000;
|
26
|
+
|
27
|
+
const mockAggregation = {
|
28
|
+
widget_values_format: "###",
|
29
|
+
value: jest.fn().mockReturnValue(mockAggregationValue),
|
30
|
+
};
|
31
|
+
|
32
|
+
const mockPivotData = {
|
33
|
+
getAggregator: jest.fn().mockImplementation().mockReturnValue(mockAggregation),
|
34
|
+
};
|
35
|
+
|
36
|
+
const mockChartOptionsPercentage = {
|
37
|
+
segments: [
|
38
|
+
{
|
39
|
+
from: 0,
|
40
|
+
to: 60,
|
41
|
+
title: "Low",
|
42
|
+
color: "#BF1D30",
|
43
|
+
},
|
44
|
+
{
|
45
|
+
from: 61,
|
46
|
+
to: 80,
|
47
|
+
title: "Medium",
|
48
|
+
color: "#FFA310",
|
49
|
+
},
|
50
|
+
{
|
51
|
+
from: 81,
|
52
|
+
to: 100,
|
53
|
+
title: "High",
|
54
|
+
color: "#037C5A",
|
55
|
+
},
|
56
|
+
],
|
57
|
+
goal: {
|
58
|
+
name: "Goal",
|
59
|
+
value: 180,
|
60
|
+
},
|
61
|
+
isAbsoluteValue: false,
|
62
|
+
label: {},
|
63
|
+
gauge: {
|
64
|
+
background: "white",
|
65
|
+
},
|
66
|
+
};
|
67
|
+
|
68
|
+
const mockChartOptionsAbsolute = {
|
69
|
+
segments: [
|
70
|
+
{
|
71
|
+
from: 0,
|
72
|
+
to: 100,
|
73
|
+
title: "Low",
|
74
|
+
color: "#BF1D30",
|
75
|
+
},
|
76
|
+
{
|
77
|
+
from: 101,
|
78
|
+
to: 200,
|
79
|
+
title: "Medium",
|
80
|
+
color: "#FFA310",
|
81
|
+
},
|
82
|
+
{
|
83
|
+
from: 201,
|
84
|
+
to: 500,
|
85
|
+
title: "High",
|
86
|
+
color: "#037C5A",
|
87
|
+
},
|
88
|
+
],
|
89
|
+
goal: {
|
90
|
+
name: "Goal",
|
91
|
+
value: 180,
|
92
|
+
},
|
93
|
+
isAbsoluteValue: true,
|
94
|
+
};
|
95
|
+
|
96
|
+
let chart;
|
97
|
+
|
98
|
+
describe("DrGaugeChart", () => {
|
99
|
+
beforeEach(() => {
|
100
|
+
chart = new DrGaugeChart(mockPivotData, {
|
101
|
+
chartOptions: mockChartOptionsPercentage,
|
102
|
+
});
|
103
|
+
});
|
104
|
+
|
105
|
+
describe("render", () => {
|
106
|
+
it("calls configChart", () => {
|
107
|
+
chart.configChart = jest.fn().mockReturnValue({
|
108
|
+
options: "Option",
|
109
|
+
});
|
110
|
+
|
111
|
+
chart.render();
|
112
|
+
expect(chart.configChart).toHaveBeenCalled();
|
113
|
+
});
|
114
|
+
});
|
115
|
+
|
116
|
+
describe("isLeftQuarter", () => {
|
117
|
+
it("should check in which quarter the chart value is", () => {
|
118
|
+
expect(chart.isLeftQuarter(20, 100)).toBe(true);
|
119
|
+
expect(chart.isLeftQuarter(20, 30)).toBe(false);
|
120
|
+
expect(chart.isLeftQuarter(20, 20)).toBe(false);
|
121
|
+
expect(chart.isLeftQuarter(100, 200)).toBe(false);
|
122
|
+
expect(chart.isLeftQuarter(99, 200)).toBe(true);
|
123
|
+
});
|
124
|
+
|
125
|
+
it("should use default #max parameter", () => {
|
126
|
+
// Max = 180
|
127
|
+
expect(chart.isLeftQuarter(20)).toBe(true);
|
128
|
+
expect(chart.isLeftQuarter(120)).toBe(false);
|
129
|
+
});
|
130
|
+
});
|
131
|
+
|
132
|
+
describe("createPlotBands", () => {
|
133
|
+
it("should create plots for absolute values", () => {
|
134
|
+
expect(
|
135
|
+
chart.createPlotBands({
|
136
|
+
isAbsoluteValue: true,
|
137
|
+
gauge: {
|
138
|
+
thickness: 10,
|
139
|
+
},
|
140
|
+
goal: {
|
141
|
+
value: 180,
|
142
|
+
},
|
143
|
+
segments: [
|
144
|
+
{
|
145
|
+
from: 0,
|
146
|
+
to: 200,
|
147
|
+
color: "red",
|
148
|
+
title: "Title 1",
|
149
|
+
},
|
150
|
+
{
|
151
|
+
from: 201,
|
152
|
+
to: 400,
|
153
|
+
color: "blue",
|
154
|
+
title: "Title 2",
|
155
|
+
},
|
156
|
+
{
|
157
|
+
from: 401,
|
158
|
+
to: 800,
|
159
|
+
color: "blue",
|
160
|
+
title: "Title 3",
|
161
|
+
},
|
162
|
+
],
|
163
|
+
})
|
164
|
+
).toEqual([
|
165
|
+
{
|
166
|
+
from: 0,
|
167
|
+
to: 200,
|
168
|
+
color: "red",
|
169
|
+
thickness: 10,
|
170
|
+
title: "Title 1",
|
171
|
+
},
|
172
|
+
{
|
173
|
+
from: 200,
|
174
|
+
to: 400,
|
175
|
+
color: "blue",
|
176
|
+
thickness: 10,
|
177
|
+
title: "Title 2",
|
178
|
+
},
|
179
|
+
{
|
180
|
+
from: 400,
|
181
|
+
to: 800,
|
182
|
+
color: "blue",
|
183
|
+
thickness: 10,
|
184
|
+
title: "Title 3",
|
185
|
+
},
|
186
|
+
]);
|
187
|
+
});
|
188
|
+
|
189
|
+
it("should clamp values (min is always 0, max of goal and last segment)", () => {
|
190
|
+
expect(
|
191
|
+
chart.createPlotBands({
|
192
|
+
isAbsoluteValue: true,
|
193
|
+
gauge: {
|
194
|
+
thickness: 10,
|
195
|
+
},
|
196
|
+
goal: {
|
197
|
+
value: 1800,
|
198
|
+
},
|
199
|
+
segments: [
|
200
|
+
{
|
201
|
+
from: 100,
|
202
|
+
to: 200,
|
203
|
+
color: "red",
|
204
|
+
title: "Title 1",
|
205
|
+
},
|
206
|
+
{
|
207
|
+
from: 201,
|
208
|
+
to: 400,
|
209
|
+
color: "blue",
|
210
|
+
title: "Title 2",
|
211
|
+
},
|
212
|
+
{
|
213
|
+
from: 401,
|
214
|
+
to: 800,
|
215
|
+
color: "blue",
|
216
|
+
title: "Title 3",
|
217
|
+
},
|
218
|
+
],
|
219
|
+
})
|
220
|
+
).toEqual([
|
221
|
+
{
|
222
|
+
from: 0,
|
223
|
+
to: 200,
|
224
|
+
color: "red",
|
225
|
+
thickness: 10,
|
226
|
+
title: "Title 1",
|
227
|
+
},
|
228
|
+
{
|
229
|
+
from: 200,
|
230
|
+
to: 400,
|
231
|
+
color: "blue",
|
232
|
+
thickness: 10,
|
233
|
+
title: "Title 2",
|
234
|
+
},
|
235
|
+
{
|
236
|
+
from: 400,
|
237
|
+
to: 1800,
|
238
|
+
color: "blue",
|
239
|
+
thickness: 10,
|
240
|
+
title: "Title 3",
|
241
|
+
},
|
242
|
+
]);
|
243
|
+
});
|
244
|
+
|
245
|
+
it("should create plots for percentage values", () => {
|
246
|
+
expect(
|
247
|
+
chart.createPlotBands({
|
248
|
+
isAbsoluteValue: false,
|
249
|
+
gauge: {
|
250
|
+
thickness: 10,
|
251
|
+
},
|
252
|
+
goal: {
|
253
|
+
value: 1000,
|
254
|
+
},
|
255
|
+
segments: [
|
256
|
+
{
|
257
|
+
from: 0,
|
258
|
+
to: 50,
|
259
|
+
color: "red",
|
260
|
+
title: "Title 1",
|
261
|
+
},
|
262
|
+
{
|
263
|
+
from: 51,
|
264
|
+
to: 100,
|
265
|
+
color: "blue",
|
266
|
+
title: "Title 2",
|
267
|
+
},
|
268
|
+
{
|
269
|
+
from: 101,
|
270
|
+
to: 175,
|
271
|
+
color: "blue",
|
272
|
+
title: "Title 3",
|
273
|
+
},
|
274
|
+
],
|
275
|
+
})
|
276
|
+
).toEqual([
|
277
|
+
{
|
278
|
+
from: 0,
|
279
|
+
to: 500,
|
280
|
+
color: "red",
|
281
|
+
thickness: 10,
|
282
|
+
title: "Title 1",
|
283
|
+
},
|
284
|
+
{
|
285
|
+
from: 500,
|
286
|
+
to: 1000,
|
287
|
+
color: "blue",
|
288
|
+
thickness: 10,
|
289
|
+
title: "Title 2",
|
290
|
+
},
|
291
|
+
{
|
292
|
+
from: 1000,
|
293
|
+
to: 1750,
|
294
|
+
color: "blue",
|
295
|
+
thickness: 10,
|
296
|
+
title: "Title 3",
|
297
|
+
},
|
298
|
+
]);
|
299
|
+
});
|
300
|
+
});
|
301
|
+
|
302
|
+
describe("createTicks", () => {
|
303
|
+
it("should create a ticks array", () => {
|
304
|
+
expect(
|
305
|
+
chart.createTicks(
|
306
|
+
[
|
307
|
+
{
|
308
|
+
to: 100,
|
309
|
+
},
|
310
|
+
{
|
311
|
+
to: 150,
|
312
|
+
},
|
313
|
+
{
|
314
|
+
to: 200,
|
315
|
+
},
|
316
|
+
],
|
317
|
+
{
|
318
|
+
goal: {
|
319
|
+
value: 180,
|
320
|
+
},
|
321
|
+
}
|
322
|
+
)
|
323
|
+
).toEqual([0, 100, 150, 180, 200]);
|
324
|
+
});
|
325
|
+
|
326
|
+
it("should sort and remove duplicates", () => {
|
327
|
+
expect(
|
328
|
+
chart.createTicks(
|
329
|
+
[
|
330
|
+
{
|
331
|
+
to: 100,
|
332
|
+
},
|
333
|
+
{
|
334
|
+
to: 100,
|
335
|
+
},
|
336
|
+
{
|
337
|
+
to: 50,
|
338
|
+
},
|
339
|
+
{
|
340
|
+
to: 180,
|
341
|
+
},
|
342
|
+
],
|
343
|
+
{
|
344
|
+
goal: {
|
345
|
+
value: 180,
|
346
|
+
},
|
347
|
+
}
|
348
|
+
)
|
349
|
+
).toEqual([0, 50, 100, 180]);
|
350
|
+
});
|
351
|
+
});
|
352
|
+
|
353
|
+
describe("mergeOptions", () => {
|
354
|
+
it("should merge provided options with default one", () => {
|
355
|
+
chart.getDefaultValueForChart = jest.fn().mockReturnValue({
|
356
|
+
option1: 1,
|
357
|
+
option2: 2,
|
358
|
+
});
|
359
|
+
const mockRes = {
|
360
|
+
option1: 1,
|
361
|
+
option2: 2,
|
362
|
+
};
|
363
|
+
spyOn(helpers, "mergeDeep").and.returnValue(mockRes);
|
364
|
+
expect(
|
365
|
+
chart.mergeOptions({
|
366
|
+
options3: 3,
|
367
|
+
options4: 4,
|
368
|
+
})
|
369
|
+
).toEqual(mockRes);
|
370
|
+
expect(helpers.mergeDeep).toHaveBeenCalledWith(
|
371
|
+
GAUGE_OPTIONS_DEFAULT,
|
372
|
+
{
|
373
|
+
option1: 1,
|
374
|
+
option2: 2,
|
375
|
+
},
|
376
|
+
{
|
377
|
+
options3: 3,
|
378
|
+
options4: 4,
|
379
|
+
}
|
380
|
+
);
|
381
|
+
helpers.mergeDeep.re;
|
382
|
+
});
|
383
|
+
});
|
384
|
+
|
385
|
+
describe("getAngleForValue", () => {
|
386
|
+
it("should return an angle in radians", () => {
|
387
|
+
expect(chart.getAngleForValue(100, 0, 200, -90, 90)).toBe(Math.PI / 2);
|
388
|
+
expect(chart.getAngleForValue(50, 0, 200, -90, 90)).toBe(Math.PI / 4);
|
389
|
+
expect(chart.getAngleForValue(200, 0, 200, -90, 90)).toBe(Math.PI);
|
390
|
+
});
|
391
|
+
|
392
|
+
it("should use default value", () => {
|
393
|
+
// min = 0;
|
394
|
+
// max = 180 goal
|
395
|
+
// angle -90/ 90
|
396
|
+
expect(chart.getAngleForValue(90)).toBe(Math.PI / 2);
|
397
|
+
});
|
398
|
+
});
|
399
|
+
|
400
|
+
describe("formatValue", () => {
|
401
|
+
it("should format number to provided format", () => {
|
402
|
+
expect(chart.formatValue(16549.1234, "#,###")).toBe(mockFormattedValue);
|
403
|
+
expect(DrGaugeChart.highchartsRenderer.formatValue).toHaveBeenCalledWith("n", "#,###", 16549.1234);
|
404
|
+
});
|
405
|
+
|
406
|
+
it("should not format value unless it is a number", () => {
|
407
|
+
expect(chart.formatValue("one", "#,###")).toBe("one");
|
408
|
+
expect(DrGaugeChart.highchartsRenderer.formatValue).not.toHaveBeenCalled();
|
409
|
+
});
|
410
|
+
|
411
|
+
it("should use default value for format", () => {
|
412
|
+
expect(chart.formatValue(16549.1234)).toBe(mockFormattedValue);
|
413
|
+
expect(DrGaugeChart.highchartsRenderer.formatValue).toHaveBeenCalledWith(
|
414
|
+
"n",
|
415
|
+
mockAggregation.widget_values_format,
|
416
|
+
16549.1234
|
417
|
+
);
|
418
|
+
});
|
419
|
+
});
|
420
|
+
|
421
|
+
describe("toPercent", () => {
|
422
|
+
it("should format absolute values", () => {
|
423
|
+
chart = new DrGaugeChart(mockPivotData, {
|
424
|
+
chartOptions: { ...mockChartOptionsAbsolute },
|
425
|
+
});
|
426
|
+
expect(chart.toPercent(100)).toBe("20%");
|
427
|
+
expect(chart.toPercent(250)).toBe("50%");
|
428
|
+
expect(chart.toPercent(500)).toBe("100%");
|
429
|
+
// rounding
|
430
|
+
expect(chart.toPercent(2)).toBe("0%");
|
431
|
+
expect(chart.toPercent(3)).toBe("1%");
|
432
|
+
});
|
433
|
+
|
434
|
+
it("should format percentage values", () => {
|
435
|
+
chart = new DrGaugeChart(mockPivotData, {
|
436
|
+
chartOptions: { ...mockChartOptionsPercentage },
|
437
|
+
});
|
438
|
+
expect(chart.toPercent(180)).toBe("100%");
|
439
|
+
expect(chart.toPercent(90)).toBe("50%");
|
440
|
+
expect(chart.toPercent(18)).toBe("10%");
|
441
|
+
// rounding
|
442
|
+
expect(chart.toPercent(0.5)).toBe("0%");
|
443
|
+
expect(chart.toPercent(2)).toBe("1%");
|
444
|
+
});
|
445
|
+
});
|
446
|
+
|
447
|
+
describe("formatValueLabel", () => {
|
448
|
+
it("should return the label html", () => {
|
449
|
+
const label = chart.formatValueLabel(100, {
|
450
|
+
label: {
|
451
|
+
font_size: 16,
|
452
|
+
font_color: "#000",
|
453
|
+
show_percentage_in_value: false,
|
454
|
+
},
|
455
|
+
gauge: {
|
456
|
+
colors: {
|
457
|
+
meta: "#808080",
|
458
|
+
},
|
459
|
+
},
|
460
|
+
});
|
461
|
+
expect(simplifyString(label)).toBe(
|
462
|
+
simplifyString(
|
463
|
+
`<span style="display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: 16px;">
|
464
|
+
<span style="font-weight: 600; font-size: 1.5em; line-height: 1; color: #000">
|
465
|
+
${mockFormattedValue}
|
466
|
+
</span>
|
467
|
+
<span style="font-weight: 500; font-size: 0.875em; line-height: 1; color: #808080;">Current status</span>
|
468
|
+
</span>`
|
469
|
+
)
|
470
|
+
);
|
471
|
+
});
|
472
|
+
|
473
|
+
it("should add percentage", () => {
|
474
|
+
const label = chart.formatValueLabel(100, {
|
475
|
+
label: {
|
476
|
+
font_size: 24,
|
477
|
+
font_color: "#000",
|
478
|
+
show_percentage_in_value: true,
|
479
|
+
},
|
480
|
+
gauge: {
|
481
|
+
colors: {
|
482
|
+
meta: "#929292",
|
483
|
+
},
|
484
|
+
},
|
485
|
+
});
|
486
|
+
expect(simplifyString(label)).toBe(
|
487
|
+
simplifyString(
|
488
|
+
`<span style="display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: 24px;">
|
489
|
+
<span style="font-weight: 600; font-size: 1.5em; line-height: 1; color: #000">
|
490
|
+
${mockFormattedValue}
|
491
|
+
<span style="font-size: 0.5833em; font-weight: 600; color: #929292;">(56%)</span>
|
492
|
+
</span>
|
493
|
+
<span style="font-weight: 500; font-size: 0.875em; line-height: 1; color: #929292;">Current status</span>
|
494
|
+
</span>`
|
495
|
+
)
|
496
|
+
);
|
497
|
+
});
|
498
|
+
});
|
499
|
+
|
500
|
+
describe("formatTickLabel", () => {
|
501
|
+
it("should return the tick label html", () => {
|
502
|
+
const label = chart.formatTickLabel(100, {
|
503
|
+
label: {
|
504
|
+
font_size: 16,
|
505
|
+
font_color: "#000",
|
506
|
+
show_percentage_in_segments: false,
|
507
|
+
},
|
508
|
+
goal: {
|
509
|
+
value: 180,
|
510
|
+
name: "Goal",
|
511
|
+
},
|
512
|
+
gauge: {
|
513
|
+
colors: {
|
514
|
+
meta: "#808080",
|
515
|
+
},
|
516
|
+
},
|
517
|
+
});
|
518
|
+
|
519
|
+
expect(simplifyString(label)).toBe(
|
520
|
+
simplifyString(`<span style="
|
521
|
+
display: flex;
|
522
|
+
align-items: center;
|
523
|
+
gap: 4px;
|
524
|
+
font-weight: 600;
|
525
|
+
font-size: 16px;
|
526
|
+
">
|
527
|
+
<span style="color: #000;">${mockFormattedValue}</span>
|
528
|
+
</span>`)
|
529
|
+
);
|
530
|
+
});
|
531
|
+
|
532
|
+
it("should add repcentage", () => {
|
533
|
+
const label = chart.formatTickLabel(100, {
|
534
|
+
label: {
|
535
|
+
font_size: 16,
|
536
|
+
font_color: "#000",
|
537
|
+
show_percentage_in_segments: true,
|
538
|
+
},
|
539
|
+
goal: {
|
540
|
+
value: 180,
|
541
|
+
name: "Goal",
|
542
|
+
},
|
543
|
+
gauge: {
|
544
|
+
colors: {
|
545
|
+
meta: "#808080",
|
546
|
+
},
|
547
|
+
},
|
548
|
+
});
|
549
|
+
|
550
|
+
expect(simplifyString(label)).toBe(
|
551
|
+
simplifyString(`<span style="
|
552
|
+
display: flex;
|
553
|
+
align-items: center;
|
554
|
+
gap: 4px;
|
555
|
+
font-weight: 600;
|
556
|
+
font-size: 16px;
|
557
|
+
">
|
558
|
+
<span style="color: #000;">${mockFormattedValue}</span>
|
559
|
+
<span style="font-size: 0.75em; color: #808080; font-weight: 400;">(56%)</span>
|
560
|
+
</span>`)
|
561
|
+
);
|
562
|
+
});
|
563
|
+
|
564
|
+
it("should apply extra styles for goal", () => {
|
565
|
+
const label = chart.formatTickLabel(180, {
|
566
|
+
label: {
|
567
|
+
font_size: 16,
|
568
|
+
font_color: "#000",
|
569
|
+
show_percentage_in_segments: true,
|
570
|
+
},
|
571
|
+
goal: {
|
572
|
+
value: 180,
|
573
|
+
name: "Goal",
|
574
|
+
},
|
575
|
+
gauge: {
|
576
|
+
colors: {
|
577
|
+
meta: "#808080",
|
578
|
+
goal: "#ff0",
|
579
|
+
},
|
580
|
+
},
|
581
|
+
});
|
582
|
+
|
583
|
+
expect(simplifyString(label)).toBe(
|
584
|
+
simplifyString(`<span style="
|
585
|
+
display: flex;
|
586
|
+
align-items: center;
|
587
|
+
gap: 4px;
|
588
|
+
font-weight: 600;
|
589
|
+
font-size: 16px;
|
590
|
+
padding-left: 12px;
|
591
|
+
">
|
592
|
+
<span style="font-size: 1.125em; color: #ff0;">${mockFormattedValue}</span>
|
593
|
+
<span style="font-size: 0.75em; color: #808080; font-weight: 400;">(100%)</span>
|
594
|
+
</span>`)
|
595
|
+
);
|
596
|
+
});
|
597
|
+
|
598
|
+
it("should add goal title", () => {
|
599
|
+
const label = chart.formatTickLabel(180, {
|
600
|
+
label: {
|
601
|
+
font_size: 16,
|
602
|
+
font_color: "#000",
|
603
|
+
show_percentage_in_segments: true,
|
604
|
+
show_goal_name: true,
|
605
|
+
},
|
606
|
+
goal: {
|
607
|
+
value: 180,
|
608
|
+
title: "Goal",
|
609
|
+
},
|
610
|
+
gauge: {
|
611
|
+
colors: {
|
612
|
+
meta: "#808080",
|
613
|
+
goal: "#ff0",
|
614
|
+
},
|
615
|
+
},
|
616
|
+
});
|
617
|
+
|
618
|
+
expect(simplifyString(label)).toBe(
|
619
|
+
simplifyString(`<span style="
|
620
|
+
display: flex;
|
621
|
+
align-items: center;
|
622
|
+
gap: 4px;
|
623
|
+
font-weight: 600;
|
624
|
+
font-size: 16px;
|
625
|
+
padding-left: 12px;
|
626
|
+
">
|
627
|
+
<span style="font-size: 1.125em; color: #ff0;">${mockFormattedValue}</span>
|
628
|
+
<span style="font-size: 0.75em; color: #ff0;">Goal</span>
|
629
|
+
<span style="font-size: 0.75em; color: #808080; font-weight: 400;">(100%)</span>
|
630
|
+
</span>`)
|
631
|
+
);
|
632
|
+
});
|
633
|
+
|
634
|
+
it("should add paddings", () => {
|
635
|
+
spyOn(chart, "isLeftQuarter").and.returnValues(true, false);
|
636
|
+
|
637
|
+
const labelLeft = chart.formatTickLabel(180, {
|
638
|
+
label: {
|
639
|
+
font_size: 16,
|
640
|
+
font_color: "#000",
|
641
|
+
show_percentage_in_segments: false,
|
642
|
+
show_goal_name: false,
|
643
|
+
},
|
644
|
+
goal: {
|
645
|
+
value: 180,
|
646
|
+
title: "Goal",
|
647
|
+
},
|
648
|
+
gauge: {
|
649
|
+
colors: {
|
650
|
+
meta: "#808080",
|
651
|
+
goal: "#ff0",
|
652
|
+
},
|
653
|
+
},
|
654
|
+
});
|
655
|
+
|
656
|
+
expect(simplifyString(labelLeft)).toBe(
|
657
|
+
simplifyString(`<span style="
|
658
|
+
display: flex;
|
659
|
+
align-items: center;
|
660
|
+
gap: 4px;
|
661
|
+
font-weight: 600;
|
662
|
+
font-size: 16px;
|
663
|
+
padding-right: 12px;
|
664
|
+
">
|
665
|
+
<span style="font-size: 1.125em; color: #ff0;">${mockFormattedValue}</span>
|
666
|
+
</span>`)
|
667
|
+
);
|
668
|
+
|
669
|
+
const labelRight = chart.formatTickLabel(180, {
|
670
|
+
label: {
|
671
|
+
font_size: 16,
|
672
|
+
font_color: "#000",
|
673
|
+
show_percentage_in_segments: false,
|
674
|
+
show_goal_name: false,
|
675
|
+
},
|
676
|
+
goal: {
|
677
|
+
value: 180,
|
678
|
+
title: "Goal",
|
679
|
+
},
|
680
|
+
gauge: {
|
681
|
+
colors: {
|
682
|
+
meta: "#808080",
|
683
|
+
goal: "#ff0",
|
684
|
+
},
|
685
|
+
},
|
686
|
+
});
|
687
|
+
|
688
|
+
expect(simplifyString(labelRight)).toBe(
|
689
|
+
simplifyString(`<span style="
|
690
|
+
display: flex;
|
691
|
+
align-items: center;
|
692
|
+
gap: 4px;
|
693
|
+
font-weight: 600;
|
694
|
+
font-size: 16px;
|
695
|
+
padding-left: 12px;
|
696
|
+
">
|
697
|
+
<span style="font-size: 1.125em; color: #ff0;">${mockFormattedValue}</span>
|
698
|
+
</span>`)
|
699
|
+
);
|
700
|
+
});
|
701
|
+
});
|
702
|
+
|
703
|
+
describe("getValue", () => {
|
704
|
+
it("should return aggregator value unledss the total is empty", () => {
|
705
|
+
DrGaugeChart.highchartsRenderer.ptCreateBasicLineSeries.mockReturnValue([]);
|
706
|
+
expect(chart.getValue(mockPivotData, {})).toBe(mockAggregationValue);
|
707
|
+
});
|
708
|
+
|
709
|
+
it("should return value to display", () => {
|
710
|
+
DrGaugeChart.highchartsRenderer.ptCreateBasicLineSeries.mockReturnValue([{ data: [2000] }]);
|
711
|
+
expect(chart.getValue(mockPivotData, {})).toBe(2000);
|
712
|
+
});
|
713
|
+
|
714
|
+
it("should calculate total", () => {
|
715
|
+
DrGaugeChart.highchartsRenderer.ptCreateBasicLineSeries.mockReturnValue([
|
716
|
+
{ data: [2000] },
|
717
|
+
{ data: [3000] },
|
718
|
+
{ data: [5000] },
|
719
|
+
]);
|
720
|
+
expect(chart.getValue(mockPivotData, {})).toBe(10000);
|
721
|
+
});
|
722
|
+
});
|
723
|
+
|
724
|
+
describe("getBorderPosition", () => {
|
725
|
+
const mockChart = {
|
726
|
+
pane: [
|
727
|
+
{
|
728
|
+
options: {
|
729
|
+
center: [200, 200],
|
730
|
+
size: 100,
|
731
|
+
},
|
732
|
+
},
|
733
|
+
],
|
734
|
+
};
|
735
|
+
|
736
|
+
const mockOptions = {
|
737
|
+
gauge: {
|
738
|
+
tickLength: 40,
|
739
|
+
tickWidth: 2,
|
740
|
+
},
|
741
|
+
};
|
742
|
+
|
743
|
+
it("return a start border position", () => {
|
744
|
+
expect(chart.getBorderPosition(mockChart, mockOptions, "start")).toEqual({
|
745
|
+
x: 170,
|
746
|
+
y: 201,
|
747
|
+
});
|
748
|
+
});
|
749
|
+
|
750
|
+
it("return an end border position", () => {
|
751
|
+
expect(chart.getBorderPosition(mockChart, mockOptions, "end")).toEqual({
|
752
|
+
x: 230,
|
753
|
+
y: 201,
|
754
|
+
});
|
755
|
+
});
|
756
|
+
});
|
757
|
+
|
758
|
+
describe("createBorder", () => {
|
759
|
+
beforeEach(() => {
|
760
|
+
chart.getBorderPosition = jest.fn().mockReturnValue({
|
761
|
+
x: 100,
|
762
|
+
y: 200,
|
763
|
+
});
|
764
|
+
});
|
765
|
+
|
766
|
+
const toFrontMock = jest.fn();
|
767
|
+
|
768
|
+
const addMock = jest.fn().mockReturnValue({
|
769
|
+
toFront: toFrontMock,
|
770
|
+
});
|
771
|
+
|
772
|
+
const attrMock = jest.fn().mockReturnValue({
|
773
|
+
add: addMock,
|
774
|
+
});
|
775
|
+
|
776
|
+
const arcMock = jest.fn().mockReturnValue({
|
777
|
+
attr: attrMock,
|
778
|
+
});
|
779
|
+
|
780
|
+
const mockChart = {
|
781
|
+
renderer: {
|
782
|
+
arc: arcMock,
|
783
|
+
},
|
784
|
+
yAxis: [
|
785
|
+
{
|
786
|
+
options: {
|
787
|
+
plotBands: [
|
788
|
+
{
|
789
|
+
color: "red",
|
790
|
+
},
|
791
|
+
{
|
792
|
+
color: "blue",
|
793
|
+
},
|
794
|
+
{
|
795
|
+
color: "green",
|
796
|
+
},
|
797
|
+
],
|
798
|
+
},
|
799
|
+
},
|
800
|
+
],
|
801
|
+
};
|
802
|
+
|
803
|
+
it("should create a start border", () => {
|
804
|
+
chart.createBorder(
|
805
|
+
mockChart,
|
806
|
+
{
|
807
|
+
gauge: {
|
808
|
+
thickness: 10,
|
809
|
+
},
|
810
|
+
},
|
811
|
+
"start"
|
812
|
+
);
|
813
|
+
// draw an arc
|
814
|
+
expect(arcMock).toHaveBeenCalledWith({
|
815
|
+
x: 100,
|
816
|
+
y: 200,
|
817
|
+
r: 5,
|
818
|
+
innerR: 0,
|
819
|
+
start: 0,
|
820
|
+
end: Math.PI,
|
821
|
+
});
|
822
|
+
// set color of first segment
|
823
|
+
expect(attrMock).toHaveBeenCalledWith({
|
824
|
+
fill: "red",
|
825
|
+
});
|
826
|
+
//add to pane
|
827
|
+
expect(addMock).toHaveBeenCalled();
|
828
|
+
// move to front
|
829
|
+
expect(toFrontMock).toHaveBeenCalled();
|
830
|
+
});
|
831
|
+
|
832
|
+
it("should create an end border", () => {
|
833
|
+
chart.createBorder(
|
834
|
+
mockChart,
|
835
|
+
{
|
836
|
+
gauge: {
|
837
|
+
thickness: 20,
|
838
|
+
},
|
839
|
+
},
|
840
|
+
"end"
|
841
|
+
);
|
842
|
+
// draw an arc
|
843
|
+
expect(arcMock).toHaveBeenCalledWith({
|
844
|
+
x: 100,
|
845
|
+
y: 200,
|
846
|
+
r: 10,
|
847
|
+
innerR: 0,
|
848
|
+
start: 0,
|
849
|
+
end: Math.PI,
|
850
|
+
});
|
851
|
+
// set color of last segment
|
852
|
+
expect(attrMock).toHaveBeenCalledWith({
|
853
|
+
fill: "green",
|
854
|
+
});
|
855
|
+
//add to pane
|
856
|
+
expect(addMock).toHaveBeenCalled();
|
857
|
+
// move to front
|
858
|
+
expect(toFrontMock).toHaveBeenCalled();
|
859
|
+
});
|
860
|
+
});
|
861
|
+
|
862
|
+
describe("getGoalIconPosition", () => {
|
863
|
+
it("should return an icon position", () => {
|
864
|
+
chart.getAngleForValue = jest.fn().mockReturnValue(0);
|
865
|
+
expect(
|
866
|
+
chart.getGoalIconPosition(
|
867
|
+
{
|
868
|
+
pane: [
|
869
|
+
{
|
870
|
+
options: {
|
871
|
+
center: [100, 100],
|
872
|
+
size: 100,
|
873
|
+
},
|
874
|
+
},
|
875
|
+
],
|
876
|
+
},
|
877
|
+
{
|
878
|
+
gauge: {
|
879
|
+
goalIconSize: [16, 16],
|
880
|
+
},
|
881
|
+
goal: {
|
882
|
+
value: 0,
|
883
|
+
},
|
884
|
+
}
|
885
|
+
)
|
886
|
+
).toEqual({
|
887
|
+
x: 42,
|
888
|
+
y: 92,
|
889
|
+
});
|
890
|
+
expect(chart.getAngleForValue).toHaveBeenCalledWith(0);
|
891
|
+
chart.getAngleForValue = jest.fn().mockReturnValue(Math.PI / 2);
|
892
|
+
expect(
|
893
|
+
chart.getGoalIconPosition(
|
894
|
+
{
|
895
|
+
pane: [
|
896
|
+
{
|
897
|
+
options: {
|
898
|
+
center: [200, 200],
|
899
|
+
size: 200,
|
900
|
+
},
|
901
|
+
},
|
902
|
+
],
|
903
|
+
},
|
904
|
+
{
|
905
|
+
gauge: {
|
906
|
+
goalIconSize: [24, 24],
|
907
|
+
},
|
908
|
+
goal: {
|
909
|
+
value: 200,
|
910
|
+
},
|
911
|
+
}
|
912
|
+
)
|
913
|
+
).toEqual({
|
914
|
+
x: 188,
|
915
|
+
y: 88,
|
916
|
+
});
|
917
|
+
expect(chart.getAngleForValue).toHaveBeenCalledWith(200);
|
918
|
+
expect(
|
919
|
+
chart.getGoalIconPosition(
|
920
|
+
{
|
921
|
+
pane: [
|
922
|
+
{
|
923
|
+
options: {
|
924
|
+
center: [500, 500],
|
925
|
+
size: 500,
|
926
|
+
},
|
927
|
+
},
|
928
|
+
],
|
929
|
+
},
|
930
|
+
{
|
931
|
+
gauge: {
|
932
|
+
goalIconSize: [50, 50],
|
933
|
+
},
|
934
|
+
goal: {
|
935
|
+
value: 500,
|
936
|
+
},
|
937
|
+
}
|
938
|
+
)
|
939
|
+
).toEqual({
|
940
|
+
x: 475,
|
941
|
+
y: 225,
|
942
|
+
});
|
943
|
+
expect(chart.getAngleForValue).toHaveBeenCalledWith(500);
|
944
|
+
});
|
945
|
+
});
|
946
|
+
|
947
|
+
describe("createGoalIcon", () => {
|
948
|
+
const toFront = jest.fn();
|
949
|
+
const add = jest.fn().mockReturnValue({ toFront });
|
950
|
+
const image = jest.fn().mockReturnValue({ add });
|
951
|
+
|
952
|
+
beforeEach(() => {
|
953
|
+
chart.getGoalIconPosition = jest.fn().mockReturnValue({
|
954
|
+
x: 100,
|
955
|
+
y: 200,
|
956
|
+
});
|
957
|
+
|
958
|
+
chart.createGoalIcon(
|
959
|
+
{
|
960
|
+
renderer: {
|
961
|
+
image,
|
962
|
+
},
|
963
|
+
},
|
964
|
+
{
|
965
|
+
gauge: {
|
966
|
+
goalIcon: "base64hash",
|
967
|
+
goalIconSize: [16, 16],
|
968
|
+
},
|
969
|
+
}
|
970
|
+
);
|
971
|
+
});
|
972
|
+
|
973
|
+
it("should create an goal icon", () => {
|
974
|
+
expect(image).toHaveBeenCalledWith("base64hash", 100, 200, 16, 16);
|
975
|
+
});
|
976
|
+
|
977
|
+
it("should add icon to the plot", () => {
|
978
|
+
expect(add).toHaveBeenCalled();
|
979
|
+
});
|
980
|
+
|
981
|
+
it("should move icon to front", () => {
|
982
|
+
expect(toFront).toHaveBeenCalled();
|
983
|
+
});
|
984
|
+
});
|
985
|
+
|
986
|
+
describe("getValueLabelPosition", () => {
|
987
|
+
it("should return a value label position depends on the pane center and offsets", () => {
|
988
|
+
expect(
|
989
|
+
chart.getValueLabelPosition(
|
990
|
+
{
|
991
|
+
pane: [
|
992
|
+
{
|
993
|
+
options: {
|
994
|
+
center: [500, 300],
|
995
|
+
},
|
996
|
+
},
|
997
|
+
],
|
998
|
+
},
|
999
|
+
{
|
1000
|
+
gauge: {
|
1001
|
+
valueOffset: [20, 30, 40, 30],
|
1002
|
+
},
|
1003
|
+
}
|
1004
|
+
)
|
1005
|
+
).toEqual({
|
1006
|
+
x: 500,
|
1007
|
+
y: 320,
|
1008
|
+
});
|
1009
|
+
|
1010
|
+
expect(
|
1011
|
+
chart.getValueLabelPosition(
|
1012
|
+
{
|
1013
|
+
pane: [
|
1014
|
+
{
|
1015
|
+
options: {
|
1016
|
+
center: [200, 100],
|
1017
|
+
},
|
1018
|
+
},
|
1019
|
+
],
|
1020
|
+
},
|
1021
|
+
{
|
1022
|
+
gauge: {
|
1023
|
+
valueOffset: [40, 30, 40, 30],
|
1024
|
+
},
|
1025
|
+
}
|
1026
|
+
)
|
1027
|
+
).toEqual({
|
1028
|
+
x: 200,
|
1029
|
+
y: 140,
|
1030
|
+
});
|
1031
|
+
});
|
1032
|
+
});
|
1033
|
+
|
1034
|
+
describe("createValueLabel", () => {
|
1035
|
+
const css = jest.fn().mockReturnValue({});
|
1036
|
+
const attr = jest.fn().mockReturnValue({ css });
|
1037
|
+
const toFront = jest.fn().mockReturnValue({ attr });
|
1038
|
+
const add = jest.fn().mockReturnValue({ toFront });
|
1039
|
+
const text = jest.fn().mockReturnValue({ add });
|
1040
|
+
|
1041
|
+
beforeEach(() => {
|
1042
|
+
chart.formatValueLabel = jest.fn().mockReturnValue("<div>Mock label</div>");
|
1043
|
+
chart.getValueLabelPosition = jest.fn().mockReturnValue({
|
1044
|
+
x: 100,
|
1045
|
+
y: 200,
|
1046
|
+
});
|
1047
|
+
chart.createValueLabel({
|
1048
|
+
renderer: {
|
1049
|
+
text,
|
1050
|
+
},
|
1051
|
+
});
|
1052
|
+
});
|
1053
|
+
|
1054
|
+
it("should create a value label", () => {
|
1055
|
+
// create label
|
1056
|
+
expect(text).toHaveBeenCalledWith("<div>Mock label</div>", 0, 0, true);
|
1057
|
+
// set position
|
1058
|
+
expect(attr).toHaveBeenCalledWith({
|
1059
|
+
x: 100,
|
1060
|
+
y: 200,
|
1061
|
+
});
|
1062
|
+
// centering
|
1063
|
+
expect(css).toHaveBeenCalledWith({ transform: "translateX(-50%)" });
|
1064
|
+
});
|
1065
|
+
});
|
1066
|
+
|
1067
|
+
describe("getPaneDimensions", () => {
|
1068
|
+
const mockChart = {
|
1069
|
+
chartWidth: 500,
|
1070
|
+
chartHeight: 500,
|
1071
|
+
renderer: {
|
1072
|
+
label: jest.fn().mockReturnValue({
|
1073
|
+
add: jest.fn().mockReturnValue({
|
1074
|
+
destroy: jest.fn(),
|
1075
|
+
bBox: {
|
1076
|
+
width: 50,
|
1077
|
+
height: 25,
|
1078
|
+
},
|
1079
|
+
}),
|
1080
|
+
}),
|
1081
|
+
},
|
1082
|
+
};
|
1083
|
+
|
1084
|
+
const mockOptions = {
|
1085
|
+
gauge: {
|
1086
|
+
offset: [30, 30, 30, 30],
|
1087
|
+
valueOffset: [20, 20, 20, 20],
|
1088
|
+
goalIconSize: [16, 16],
|
1089
|
+
},
|
1090
|
+
label: {
|
1091
|
+
show: true,
|
1092
|
+
},
|
1093
|
+
goal: {
|
1094
|
+
value: 100,
|
1095
|
+
},
|
1096
|
+
};
|
1097
|
+
|
1098
|
+
beforeEach(() => {
|
1099
|
+
chart.createValueLabel = jest.fn().mockReturnValue({
|
1100
|
+
getBBox: jest.fn().mockReturnValue({
|
1101
|
+
height: 50,
|
1102
|
+
}),
|
1103
|
+
destroy: jest.fn(),
|
1104
|
+
});
|
1105
|
+
});
|
1106
|
+
|
1107
|
+
it("should calculate a pane dimensions (labels - reserve space - horizontal)", () => {
|
1108
|
+
chart.getAngleForValue = jest.fn().mockReturnValue(0);
|
1109
|
+
expect(chart.getPaneDimensions(mockChart, mockOptions)).toEqual({
|
1110
|
+
center: [250, 380],
|
1111
|
+
radius: 170,
|
1112
|
+
});
|
1113
|
+
});
|
1114
|
+
|
1115
|
+
it("should calculate a pane dimensions (labels - reserve space - )", () => {
|
1116
|
+
chart.getAngleForValue = jest.fn().mockReturnValue(Math.PI / 4);
|
1117
|
+
|
1118
|
+
expect(chart.getPaneDimensions(mockChart, mockOptions)).toEqual({
|
1119
|
+
center: [250, 380],
|
1120
|
+
radius: 220,
|
1121
|
+
});
|
1122
|
+
});
|
1123
|
+
|
1124
|
+
it("should calculate a pane dimensions (labels - not reserve space - vertical)", () => {
|
1125
|
+
chart.getAngleForValue = jest.fn().mockReturnValue(Math.PI / 2);
|
1126
|
+
|
1127
|
+
expect(chart.getPaneDimensions({ ...mockChart, ...{ chartWidth: 1000 } }, mockOptions)).toEqual({
|
1128
|
+
center: [500, 380],
|
1129
|
+
radius: 337.5,
|
1130
|
+
});
|
1131
|
+
});
|
1132
|
+
|
1133
|
+
it("should calculate a pane dimensions (goal - reserve space - horizontal)", () => {
|
1134
|
+
chart.getAngleForValue = jest.fn().mockReturnValue(0);
|
1135
|
+
expect(
|
1136
|
+
chart.getPaneDimensions(mockChart, {
|
1137
|
+
...mockOptions,
|
1138
|
+
...{
|
1139
|
+
label: {
|
1140
|
+
show: false,
|
1141
|
+
},
|
1142
|
+
},
|
1143
|
+
})
|
1144
|
+
).toEqual({
|
1145
|
+
center: [250, 380],
|
1146
|
+
radius: 212,
|
1147
|
+
});
|
1148
|
+
});
|
1149
|
+
|
1150
|
+
it("should calculate a pane dimensions (goal - not reserve space)", () => {
|
1151
|
+
chart.getAngleForValue = jest.fn().mockReturnValue(Math.PI / 4);
|
1152
|
+
expect(
|
1153
|
+
chart.getPaneDimensions(mockChart, {
|
1154
|
+
...mockOptions,
|
1155
|
+
...{
|
1156
|
+
label: {
|
1157
|
+
show: false,
|
1158
|
+
},
|
1159
|
+
},
|
1160
|
+
})
|
1161
|
+
).toEqual({
|
1162
|
+
center: [250, 380],
|
1163
|
+
radius: 220,
|
1164
|
+
});
|
1165
|
+
});
|
1166
|
+
|
1167
|
+
it("should calculate a pane dimensions (goal - reserve space - vertical)", () => {
|
1168
|
+
chart.getAngleForValue = jest.fn().mockReturnValue(Math.PI / 2);
|
1169
|
+
expect(
|
1170
|
+
chart.getPaneDimensions(
|
1171
|
+
{ ...mockChart, ...{ chartWidth: 1000 } },
|
1172
|
+
{
|
1173
|
+
...mockOptions,
|
1174
|
+
...{
|
1175
|
+
label: {
|
1176
|
+
show: false,
|
1177
|
+
},
|
1178
|
+
},
|
1179
|
+
}
|
1180
|
+
)
|
1181
|
+
).toEqual({
|
1182
|
+
center: [500, 380],
|
1183
|
+
radius: 342,
|
1184
|
+
});
|
1185
|
+
});
|
1186
|
+
});
|
1187
|
+
|
1188
|
+
describe("setTicksStyles", () => {
|
1189
|
+
it("should align ticks on the left", () => {
|
1190
|
+
const mockChart = {
|
1191
|
+
yAxis: [
|
1192
|
+
{
|
1193
|
+
ticks: {
|
1194
|
+
0: {
|
1195
|
+
pos: 30,
|
1196
|
+
css: jest.fn(),
|
1197
|
+
label: {
|
1198
|
+
css: jest.fn(),
|
1199
|
+
},
|
1200
|
+
},
|
1201
|
+
1: {
|
1202
|
+
pos: 120,
|
1203
|
+
label: {
|
1204
|
+
css: jest.fn(),
|
1205
|
+
},
|
1206
|
+
},
|
1207
|
+
},
|
1208
|
+
},
|
1209
|
+
],
|
1210
|
+
};
|
1211
|
+
|
1212
|
+
chart.setTicksStyles(mockChart, {
|
1213
|
+
gauge: {
|
1214
|
+
colors: {
|
1215
|
+
goal: "blue",
|
1216
|
+
},
|
1217
|
+
},
|
1218
|
+
goal: {
|
1219
|
+
value: 180,
|
1220
|
+
},
|
1221
|
+
});
|
1222
|
+
// move tick on the left
|
1223
|
+
expect(mockChart.yAxis[0].ticks[0].label.css).toHaveBeenCalledWith({
|
1224
|
+
transform: "translate(-100%, 0)",
|
1225
|
+
});
|
1226
|
+
// do not move tick on the right
|
1227
|
+
expect(mockChart.yAxis[0].ticks[1].label.css).toHaveBeenCalledWith({
|
1228
|
+
transform: "translate(0, 0)",
|
1229
|
+
});
|
1230
|
+
});
|
1231
|
+
|
1232
|
+
it("should align ticks on the left", () => {
|
1233
|
+
const mockChart = {
|
1234
|
+
yAxis: [
|
1235
|
+
{
|
1236
|
+
ticks: {
|
1237
|
+
0: {
|
1238
|
+
pos: 180,
|
1239
|
+
mark: {
|
1240
|
+
attr: jest.fn(),
|
1241
|
+
},
|
1242
|
+
},
|
1243
|
+
},
|
1244
|
+
},
|
1245
|
+
],
|
1246
|
+
};
|
1247
|
+
|
1248
|
+
chart.setTicksStyles(mockChart, {
|
1249
|
+
gauge: {
|
1250
|
+
colors: {
|
1251
|
+
goal: "blue",
|
1252
|
+
},
|
1253
|
+
},
|
1254
|
+
goal: {
|
1255
|
+
value: 180,
|
1256
|
+
},
|
1257
|
+
});
|
1258
|
+
// add a goal tick styles
|
1259
|
+
expect(mockChart.yAxis[0].ticks[0].mark.attr).toHaveBeenCalledWith({
|
1260
|
+
"pointer-events": "none",
|
1261
|
+
stroke: "blue",
|
1262
|
+
"stroke-dasharray": 2,
|
1263
|
+
});
|
1264
|
+
});
|
1265
|
+
});
|
1266
|
+
|
1267
|
+
describe("addTooltips", () => {
|
1268
|
+
let mockChart;
|
1269
|
+
let mockOptions;
|
1270
|
+
let mockInstance;
|
1271
|
+
|
1272
|
+
beforeEach(() => {
|
1273
|
+
mockChart = {
|
1274
|
+
yAxis: [
|
1275
|
+
{
|
1276
|
+
ticks: {
|
1277
|
+
0: { pos: 0, label: { element: "label0" } },
|
1278
|
+
50: { pos: 50, label: { element: "label50" } },
|
1279
|
+
100: { pos: 100, label: { element: "label100" } },
|
1280
|
+
},
|
1281
|
+
plotLinesAndBands: [
|
1282
|
+
{
|
1283
|
+
options: { title: "Segment 1" },
|
1284
|
+
svgElem: { element: "bandElement1" },
|
1285
|
+
},
|
1286
|
+
{
|
1287
|
+
options: { title: "Segment 2" },
|
1288
|
+
svgElem: { element: "bandElement2" },
|
1289
|
+
},
|
1290
|
+
],
|
1291
|
+
},
|
1292
|
+
],
|
1293
|
+
label: { element: "labelElement" },
|
1294
|
+
goalIcon: { element: "goalIconElement" },
|
1295
|
+
};
|
1296
|
+
|
1297
|
+
mockOptions = {
|
1298
|
+
tooltips: {
|
1299
|
+
show: true,
|
1300
|
+
font_size: 16,
|
1301
|
+
font_color: "black",
|
1302
|
+
font_style: "Poppins",
|
1303
|
+
},
|
1304
|
+
label: {
|
1305
|
+
show: true,
|
1306
|
+
},
|
1307
|
+
goal: { value: 100, title: "Goal" },
|
1308
|
+
};
|
1309
|
+
|
1310
|
+
// Mock DrChartTooltip instance
|
1311
|
+
mockInstance = {
|
1312
|
+
add: jest.fn(),
|
1313
|
+
};
|
1314
|
+
DrChartTooltip.mockImplementation(() => mockInstance);
|
1315
|
+
|
1316
|
+
// Reset mocks
|
1317
|
+
jest.clearAllMocks();
|
1318
|
+
});
|
1319
|
+
|
1320
|
+
afterEach(() => {
|
1321
|
+
jest.restoreAllMocks();
|
1322
|
+
});
|
1323
|
+
|
1324
|
+
it("should return false unless tooltips is on", () => {
|
1325
|
+
mockOptions.tooltips.show = false;
|
1326
|
+
expect(chart.addTooltips(mockChart, mockOptions)).toBe(false);
|
1327
|
+
});
|
1328
|
+
|
1329
|
+
it("should initialize DrChartTooltip with correct options", () => {
|
1330
|
+
chart.addTooltips(mockChart, mockOptions);
|
1331
|
+
|
1332
|
+
expect(DrChartTooltip).toHaveBeenCalledWith(mockChart, {
|
1333
|
+
fontSize: 16,
|
1334
|
+
fontFamily: "Poppins",
|
1335
|
+
color: "black",
|
1336
|
+
});
|
1337
|
+
});
|
1338
|
+
|
1339
|
+
it("adds tooltips to plotLinesAndBands when show_segment_name is true", () => {
|
1340
|
+
mockOptions.tooltips.show_segment_name = true;
|
1341
|
+
|
1342
|
+
chart.addTooltips(mockChart, mockOptions);
|
1343
|
+
|
1344
|
+
expect(mockInstance.add).toHaveBeenCalledWith("Segment 1", "bandElement1", { direction: "top", followPointer: true });
|
1345
|
+
expect(mockInstance.add).toHaveBeenCalledWith("Segment 2", "bandElement2", { direction: "top", followPointer: true });
|
1346
|
+
});
|
1347
|
+
|
1348
|
+
it("adds percentage tooltip to chart label when show_percentage_in_value is true", () => {
|
1349
|
+
mockOptions.tooltips.show_percentage_in_value = true;
|
1350
|
+
const toPercentSpy = jest.spyOn(chart, "toPercent").mockReturnValue("50%");
|
1351
|
+
|
1352
|
+
chart.addTooltips(mockChart, mockOptions);
|
1353
|
+
|
1354
|
+
expect(mockInstance.add).toHaveBeenCalledWith("50%", "labelElement", { direction: "top" });
|
1355
|
+
|
1356
|
+
toPercentSpy.mockRestore();
|
1357
|
+
});
|
1358
|
+
|
1359
|
+
it("does not add percentage tooltip to chart label when it is shown in label", () => {
|
1360
|
+
mockOptions.tooltips.show_percentage_in_value = true;
|
1361
|
+
mockOptions.label.show_percentage_in_value = true;
|
1362
|
+
|
1363
|
+
chart.addTooltips(mockChart, mockOptions);
|
1364
|
+
|
1365
|
+
expect(mockInstance.add).not.toHaveBeenCalled();
|
1366
|
+
});
|
1367
|
+
|
1368
|
+
it("adds goal tooltip when goal value matches tick position and labels are hidden", () => {
|
1369
|
+
mockOptions.label.show_goal_name = true;
|
1370
|
+
mockOptions.label.show = false;
|
1371
|
+
jest.spyOn(chart, "formatValue").mockReturnValue("100%");
|
1372
|
+
|
1373
|
+
chart.addTooltips(mockChart, mockOptions);
|
1374
|
+
|
1375
|
+
expect(mockInstance.add).toHaveBeenCalledWith('Goal<span style="font-weight: 600">100%</span>', "goalIconElement", {
|
1376
|
+
direction: "right",
|
1377
|
+
});
|
1378
|
+
});
|
1379
|
+
|
1380
|
+
it("adds goal tooltip when goal value matches tick position and labels are hidden (without goal title)", () => {
|
1381
|
+
mockOptions.label.show_goal_name = false;
|
1382
|
+
mockOptions.label.show = false;
|
1383
|
+
jest.spyOn(chart, "formatValue").mockReturnValue("100%");
|
1384
|
+
|
1385
|
+
chart.addTooltips(mockChart, mockOptions);
|
1386
|
+
|
1387
|
+
expect(mockInstance.add).toHaveBeenCalledWith('<span style="font-weight: 600">100%</span>', "goalIconElement", {
|
1388
|
+
direction: "right",
|
1389
|
+
});
|
1390
|
+
});
|
1391
|
+
|
1392
|
+
it("adds goal tooltip when goal value matches tick position and labels are hidden (undefined goal title)", () => {
|
1393
|
+
mockOptions.label.show_goal_name = true;
|
1394
|
+
mockOptions.goal.title = undefined;
|
1395
|
+
mockOptions.label.show = false;
|
1396
|
+
jest.spyOn(chart, "formatValue").mockReturnValue("100%");
|
1397
|
+
|
1398
|
+
chart.addTooltips(mockChart, mockOptions);
|
1399
|
+
|
1400
|
+
expect(mockInstance.add).toHaveBeenCalledWith('<span style="font-weight: 600">100%</span>', "goalIconElement", {
|
1401
|
+
direction: "right",
|
1402
|
+
});
|
1403
|
+
});
|
1404
|
+
|
1405
|
+
it("adds goal tooltip when goal value matches tick position and labels are hidden (left direction)", () => {
|
1406
|
+
mockOptions.label.show_goal_name = true;
|
1407
|
+
mockOptions.label.show = false;
|
1408
|
+
jest.spyOn(chart, "isLeftQuarter").mockReturnValue(true);
|
1409
|
+
jest.spyOn(chart, "formatValue").mockReturnValue("100%");
|
1410
|
+
|
1411
|
+
chart.addTooltips(mockChart, mockOptions);
|
1412
|
+
|
1413
|
+
expect(mockInstance.add).toHaveBeenCalledWith('Goal<span style="font-weight: 600">100%</span>', "goalIconElement", {
|
1414
|
+
direction: "left",
|
1415
|
+
});
|
1416
|
+
});
|
1417
|
+
|
1418
|
+
it("adds percentage tooltip to segment labels when show_percentage_in_segments is true", () => {
|
1419
|
+
jest.spyOn(chart, "toPercent").mockReturnValue("100%");
|
1420
|
+
mockOptions.tooltips.show_percentage_in_segments = true;
|
1421
|
+
mockOptions.label.show_percentage_in_segments = false;
|
1422
|
+
chart.addTooltips(mockChart, mockOptions);
|
1423
|
+
|
1424
|
+
expect(mockInstance.add).toHaveBeenCalledWith("100%", "label0", { direction: "left" });
|
1425
|
+
expect(mockInstance.add).toHaveBeenCalledWith("100%", "label50", { direction: "left" });
|
1426
|
+
expect(mockInstance.add).toHaveBeenCalledWith("100%", "label100", { direction: "right" });
|
1427
|
+
});
|
1428
|
+
});
|
1429
|
+
|
1430
|
+
describe("setPane", () => {
|
1431
|
+
let mockChart;
|
1432
|
+
let mockOptions;
|
1433
|
+
|
1434
|
+
beforeEach(() => {
|
1435
|
+
// Mock the chart object
|
1436
|
+
mockChart = {
|
1437
|
+
pane: [{ options: { size: null, center: null } }],
|
1438
|
+
yAxis: [
|
1439
|
+
{
|
1440
|
+
options: {
|
1441
|
+
plotBands: [{ outerRadius: null }, { outerRadius: null }],
|
1442
|
+
},
|
1443
|
+
},
|
1444
|
+
],
|
1445
|
+
series: [{
|
1446
|
+
options: {
|
1447
|
+
dial: {
|
1448
|
+
radius: '80%'
|
1449
|
+
}
|
1450
|
+
}
|
1451
|
+
}]
|
1452
|
+
};
|
1453
|
+
|
1454
|
+
// Mock options
|
1455
|
+
mockOptions = {
|
1456
|
+
gauge: { tickLength: 20, thickness: 10 },
|
1457
|
+
};
|
1458
|
+
|
1459
|
+
// Mock getPaneDimensions to return specific values
|
1460
|
+
jest.spyOn(chart, "getPaneDimensions").mockReturnValue({
|
1461
|
+
radius: 100,
|
1462
|
+
center: ["50%", "50%"],
|
1463
|
+
});
|
1464
|
+
});
|
1465
|
+
|
1466
|
+
it("calls getPaneDimensions with correct arguments", () => {
|
1467
|
+
const getPaneDimensionsSpy = jest.spyOn(chart, "getPaneDimensions");
|
1468
|
+
|
1469
|
+
chart.setPane(mockChart, mockOptions);
|
1470
|
+
|
1471
|
+
expect(getPaneDimensionsSpy).toHaveBeenCalledWith(mockChart, mockOptions);
|
1472
|
+
});
|
1473
|
+
|
1474
|
+
it("updates the pane size and center based on dimensions", () => {
|
1475
|
+
chart.setPane(mockChart, mockOptions);
|
1476
|
+
|
1477
|
+
expect(mockChart.pane[0].options.size).toBe(200); // 2 * radius
|
1478
|
+
expect(mockChart.pane[0].options.center).toEqual(["50%", "50%"]);
|
1479
|
+
});
|
1480
|
+
|
1481
|
+
it("updates the outerRadius of plot bands correctly", () => {
|
1482
|
+
chart.setPane(mockChart, mockOptions);
|
1483
|
+
|
1484
|
+
const expectedOuterRadius = 100 - (20 - 10) / 2; // radius - (tickLength - thickness) / 2
|
1485
|
+
mockChart.yAxis[0].options.plotBands.forEach((band) => {
|
1486
|
+
expect(band.outerRadius).toBe(expectedOuterRadius);
|
1487
|
+
});
|
1488
|
+
});
|
1489
|
+
|
1490
|
+
it("updates the dial radius", () => {
|
1491
|
+
chart.setPane(mockChart, mockOptions);
|
1492
|
+
|
1493
|
+
const expectedDialRadius = Math.round(100 * (100 - 20 - 10) / 100) + '%'; // radius - tickLength - offset) / radius
|
1494
|
+
expect(mockChart.series[0].options.dial.radius).toBe(expectedDialRadius);
|
1495
|
+
});
|
1496
|
+
|
1497
|
+
afterEach(() => {
|
1498
|
+
jest.restoreAllMocks();
|
1499
|
+
});
|
1500
|
+
});
|
1501
|
+
|
1502
|
+
describe("setCustomElements", () => {
|
1503
|
+
let mockChart;
|
1504
|
+
let mockOptions;
|
1505
|
+
let mockValueLabel;
|
1506
|
+
let mockStartBorder;
|
1507
|
+
let mockEndBorder;
|
1508
|
+
let mockGoalIcon;
|
1509
|
+
|
1510
|
+
beforeEach(() => {
|
1511
|
+
// Mock chart object
|
1512
|
+
mockChart = {};
|
1513
|
+
|
1514
|
+
// Mock options
|
1515
|
+
mockOptions = {
|
1516
|
+
someOption: "value", // Add relevant options here
|
1517
|
+
};
|
1518
|
+
|
1519
|
+
// Mock custom elements
|
1520
|
+
mockValueLabel = { type: "valueLabel" };
|
1521
|
+
mockStartBorder = { type: "startBorder" };
|
1522
|
+
mockEndBorder = { type: "endBorder" };
|
1523
|
+
mockGoalIcon = { type: "goalIcon" };
|
1524
|
+
|
1525
|
+
// Spy on class methods
|
1526
|
+
jest.spyOn(chart, "createValueLabel").mockReturnValue(mockValueLabel);
|
1527
|
+
jest.spyOn(chart, "createBorder").mockImplementation((chart, options, position) => {
|
1528
|
+
if (position === "start") return mockStartBorder;
|
1529
|
+
if (position === "end") return mockEndBorder;
|
1530
|
+
});
|
1531
|
+
jest.spyOn(chart, "createGoalIcon").mockReturnValue(mockGoalIcon);
|
1532
|
+
});
|
1533
|
+
|
1534
|
+
afterEach(() => {
|
1535
|
+
jest.restoreAllMocks();
|
1536
|
+
});
|
1537
|
+
|
1538
|
+
it("assigns the value label to chart.label", () => {
|
1539
|
+
chart.setCustomElements(mockChart, mockOptions);
|
1540
|
+
|
1541
|
+
expect(chart.createValueLabel).toHaveBeenCalledWith(mockChart, mockOptions);
|
1542
|
+
expect(mockChart.label).toBe(mockValueLabel);
|
1543
|
+
});
|
1544
|
+
|
1545
|
+
it("assigns the start border to chart.startBorder", () => {
|
1546
|
+
chart.setCustomElements(mockChart, mockOptions);
|
1547
|
+
|
1548
|
+
expect(chart.createBorder).toHaveBeenCalledWith(mockChart, mockOptions, "start");
|
1549
|
+
expect(mockChart.startBorder).toBe(mockStartBorder);
|
1550
|
+
});
|
1551
|
+
|
1552
|
+
it("assigns the end border to chart.endBorder", () => {
|
1553
|
+
chart.setCustomElements(mockChart, mockOptions);
|
1554
|
+
|
1555
|
+
expect(chart.createBorder).toHaveBeenCalledWith(mockChart, mockOptions, "end");
|
1556
|
+
expect(mockChart.endBorder).toBe(mockEndBorder);
|
1557
|
+
});
|
1558
|
+
|
1559
|
+
it("assigns the goal icon to chart.goalIcon", () => {
|
1560
|
+
chart.setCustomElements(mockChart, mockOptions);
|
1561
|
+
|
1562
|
+
expect(chart.createGoalIcon).toHaveBeenCalledWith(mockChart, mockOptions);
|
1563
|
+
expect(mockChart.goalIcon).toBe(mockGoalIcon);
|
1564
|
+
});
|
1565
|
+
});
|
1566
|
+
|
1567
|
+
describe("updateCustomElements", () => {
|
1568
|
+
let mockChart;
|
1569
|
+
let mockOptions;
|
1570
|
+
let mockStartPosition;
|
1571
|
+
let mockEndPosition;
|
1572
|
+
let mockGoalIconPosition;
|
1573
|
+
let mockValueLabelPosition;
|
1574
|
+
|
1575
|
+
beforeEach(() => {
|
1576
|
+
// Mock chart object with elements having .attr method
|
1577
|
+
mockChart = {
|
1578
|
+
startBorder: { attr: jest.fn() },
|
1579
|
+
endBorder: { attr: jest.fn() },
|
1580
|
+
goalIcon: { attr: jest.fn() },
|
1581
|
+
label: { attr: jest.fn() },
|
1582
|
+
};
|
1583
|
+
|
1584
|
+
// Mock options
|
1585
|
+
mockOptions = {
|
1586
|
+
someOption: "value", // Add relevant options here
|
1587
|
+
};
|
1588
|
+
|
1589
|
+
// Mock positions returned by helper methods
|
1590
|
+
mockStartPosition = { x: 10, y: 20 };
|
1591
|
+
mockEndPosition = { x: 30, y: 40 };
|
1592
|
+
mockGoalIconPosition = { x: 50, y: 60 };
|
1593
|
+
mockValueLabelPosition = { x: 70, y: 80 };
|
1594
|
+
|
1595
|
+
// Spy on helper methods
|
1596
|
+
jest.spyOn(chart, "getBorderPosition").mockImplementation((chart, options, position) => {
|
1597
|
+
if (position === "start") return mockStartPosition;
|
1598
|
+
if (position === "end") return mockEndPosition;
|
1599
|
+
});
|
1600
|
+
jest.spyOn(chart, "getGoalIconPosition").mockReturnValue(mockGoalIconPosition);
|
1601
|
+
jest.spyOn(chart, "getValueLabelPosition").mockReturnValue(mockValueLabelPosition);
|
1602
|
+
});
|
1603
|
+
|
1604
|
+
afterEach(() => {
|
1605
|
+
jest.restoreAllMocks();
|
1606
|
+
});
|
1607
|
+
|
1608
|
+
it("updates startBorder attributes correctly", () => {
|
1609
|
+
chart.updateCustomElements(mockChart, mockOptions);
|
1610
|
+
|
1611
|
+
expect(chart.getBorderPosition).toHaveBeenCalledWith(mockChart, mockOptions, "start");
|
1612
|
+
expect(mockChart.startBorder.attr).toHaveBeenCalledWith(mockStartPosition);
|
1613
|
+
});
|
1614
|
+
|
1615
|
+
it("updates endBorder attributes correctly", () => {
|
1616
|
+
chart.updateCustomElements(mockChart, mockOptions);
|
1617
|
+
|
1618
|
+
expect(chart.getBorderPosition).toHaveBeenCalledWith(mockChart, mockOptions, "end");
|
1619
|
+
expect(mockChart.endBorder.attr).toHaveBeenCalledWith(mockEndPosition);
|
1620
|
+
});
|
1621
|
+
|
1622
|
+
it("updates goalIcon attributes correctly", () => {
|
1623
|
+
chart.updateCustomElements(mockChart, mockOptions);
|
1624
|
+
|
1625
|
+
expect(chart.getGoalIconPosition).toHaveBeenCalledWith(mockChart, mockOptions);
|
1626
|
+
expect(mockChart.goalIcon.attr).toHaveBeenCalledWith(mockGoalIconPosition);
|
1627
|
+
});
|
1628
|
+
|
1629
|
+
it("updates label attributes correctly", () => {
|
1630
|
+
chart.updateCustomElements(mockChart, mockOptions);
|
1631
|
+
|
1632
|
+
expect(chart.getValueLabelPosition).toHaveBeenCalledWith(mockChart, mockOptions);
|
1633
|
+
expect(mockChart.label.attr).toHaveBeenCalledWith(mockValueLabelPosition);
|
1634
|
+
});
|
1635
|
+
});
|
1636
|
+
|
1637
|
+
describe("moveCustomElementsToFront", () => {
|
1638
|
+
let mockChart;
|
1639
|
+
|
1640
|
+
beforeEach(() => {
|
1641
|
+
// Mock chart object with elements having .toFront method
|
1642
|
+
mockChart = {
|
1643
|
+
startBorder: { toFront: jest.fn() },
|
1644
|
+
endBorder: { toFront: jest.fn() },
|
1645
|
+
goalIcon: { toFront: jest.fn() },
|
1646
|
+
};
|
1647
|
+
});
|
1648
|
+
|
1649
|
+
afterEach(() => {
|
1650
|
+
jest.clearAllMocks();
|
1651
|
+
});
|
1652
|
+
|
1653
|
+
it("calls toFront on startBorder", () => {
|
1654
|
+
chart.moveCustomElementsToFront(mockChart);
|
1655
|
+
expect(mockChart.startBorder.toFront).toHaveBeenCalled();
|
1656
|
+
});
|
1657
|
+
|
1658
|
+
it("calls toFront on endBorder", () => {
|
1659
|
+
chart.moveCustomElementsToFront(mockChart);
|
1660
|
+
expect(mockChart.endBorder.toFront).toHaveBeenCalled();
|
1661
|
+
});
|
1662
|
+
|
1663
|
+
it("calls toFront on goalIcon", () => {
|
1664
|
+
chart.moveCustomElementsToFront(mockChart);
|
1665
|
+
expect(mockChart.goalIcon.toFront).toHaveBeenCalled();
|
1666
|
+
});
|
1667
|
+
});
|
1668
|
+
|
1669
|
+
describe("clampValueToPane", () => {
|
1670
|
+
let mockMax;
|
1671
|
+
|
1672
|
+
beforeEach(() => {
|
1673
|
+
// Mock max value
|
1674
|
+
mockMax = 100;
|
1675
|
+
|
1676
|
+
// Spy on helpers.clamp
|
1677
|
+
jest.spyOn(helpers, "clamp").mockImplementation((min, value, max) => {
|
1678
|
+
if (value < min) return min;
|
1679
|
+
if (value > max) return max;
|
1680
|
+
return value;
|
1681
|
+
});
|
1682
|
+
});
|
1683
|
+
|
1684
|
+
afterEach(() => {
|
1685
|
+
jest.restoreAllMocks();
|
1686
|
+
});
|
1687
|
+
|
1688
|
+
it("calls helpers.clamp with correct bounds and value", () => {
|
1689
|
+
const value = 50;
|
1690
|
+
const result = chart.clampValueToPane(value, 100);
|
1691
|
+
|
1692
|
+
expect(helpers.clamp).toHaveBeenCalledWith(-2, value, 102);
|
1693
|
+
expect(result).toBe(value); // Value is within range
|
1694
|
+
});
|
1695
|
+
|
1696
|
+
it("returns clamped value when below range", () => {
|
1697
|
+
const value = -10;
|
1698
|
+
const result = chart.clampValueToPane(value, 100);
|
1699
|
+
|
1700
|
+
expect(helpers.clamp).toHaveBeenCalledWith(-2, value, 102);
|
1701
|
+
expect(result).toBe(-2); // Clamped to minimum
|
1702
|
+
});
|
1703
|
+
|
1704
|
+
it("returns clamped value when above range", () => {
|
1705
|
+
const value = 200;
|
1706
|
+
const result = chart.clampValueToPane(value, 100);
|
1707
|
+
|
1708
|
+
expect(helpers.clamp).toHaveBeenCalledWith(-2, value, 102);
|
1709
|
+
expect(result).toBe(102); // Clamped to maximum
|
1710
|
+
});
|
1711
|
+
|
1712
|
+
it("uses the deafult max umless it is provided", () => {
|
1713
|
+
const value = 50;
|
1714
|
+
const result = chart.clampValueToPane(value);
|
1715
|
+
|
1716
|
+
expect(helpers.clamp).toHaveBeenCalledWith(-3.6, value, 183.6);
|
1717
|
+
expect(result).toBe(value); // Value is within range
|
1718
|
+
});
|
1719
|
+
});
|
1720
|
+
|
1721
|
+
describe("configChart", () => {
|
1722
|
+
const mockChart = {};
|
1723
|
+
const mockOptions = {
|
1724
|
+
segments: [
|
1725
|
+
{
|
1726
|
+
from: 0,
|
1727
|
+
to: 50,
|
1728
|
+
title: "Low",
|
1729
|
+
color: "#BF1D30",
|
1730
|
+
},
|
1731
|
+
{
|
1732
|
+
from: 51,
|
1733
|
+
to: 160,
|
1734
|
+
title: "Medium",
|
1735
|
+
color: "#FFA310",
|
1736
|
+
},
|
1737
|
+
{
|
1738
|
+
from: 161,
|
1739
|
+
to: 200,
|
1740
|
+
title: "High",
|
1741
|
+
color: "#037C5A",
|
1742
|
+
},
|
1743
|
+
],
|
1744
|
+
goal: {
|
1745
|
+
name: "Goal",
|
1746
|
+
value: 180,
|
1747
|
+
},
|
1748
|
+
isAbsoluteValue: true,
|
1749
|
+
label: {
|
1750
|
+
show: true,
|
1751
|
+
},
|
1752
|
+
gauge: {
|
1753
|
+
background: "white",
|
1754
|
+
tickLength: 40,
|
1755
|
+
tickWidth: 20,
|
1756
|
+
pivot: {
|
1757
|
+
color: "black",
|
1758
|
+
radius: 10,
|
1759
|
+
},
|
1760
|
+
},
|
1761
|
+
};
|
1762
|
+
|
1763
|
+
beforeEach(() => {
|
1764
|
+
chart = new DrGaugeChart(mockPivotData, {
|
1765
|
+
chartOptions: mockOptions,
|
1766
|
+
});
|
1767
|
+
});
|
1768
|
+
|
1769
|
+
it("returns a configuration object with the correct structure", () => {
|
1770
|
+
const config = chart.configChart();
|
1771
|
+
|
1772
|
+
expect(config).toBeInstanceOf(Object);
|
1773
|
+
expect(config).toHaveProperty("title");
|
1774
|
+
expect(config).toHaveProperty("subtitle");
|
1775
|
+
expect(config).toHaveProperty("chart");
|
1776
|
+
expect(config).toHaveProperty("pane");
|
1777
|
+
expect(config).toHaveProperty("yAxis");
|
1778
|
+
expect(config).toHaveProperty("series");
|
1779
|
+
});
|
1780
|
+
|
1781
|
+
it("hides title", () => {
|
1782
|
+
const config = chart.configChart();
|
1783
|
+
expect(config.title).toEqual({
|
1784
|
+
text: null,
|
1785
|
+
});
|
1786
|
+
});
|
1787
|
+
|
1788
|
+
it("hides subtitle", () => {
|
1789
|
+
const config = chart.configChart();
|
1790
|
+
expect(config.subtitle).toBe(null);
|
1791
|
+
});
|
1792
|
+
|
1793
|
+
it("alllows HTML on export", () => {
|
1794
|
+
const config = chart.configChart();
|
1795
|
+
expect(config.exporting).toEqual({
|
1796
|
+
allowHTML: true,
|
1797
|
+
});
|
1798
|
+
});
|
1799
|
+
|
1800
|
+
it("sets chart type", () => {
|
1801
|
+
const config = chart.configChart();
|
1802
|
+
expect(config.chart.type).toBe("gauge");
|
1803
|
+
});
|
1804
|
+
|
1805
|
+
it("sets default chart options", () => {
|
1806
|
+
const config = chart.configChart();
|
1807
|
+
|
1808
|
+
expect(config.chart.backgroundColor).toBe(mockOptions.gauge.background);
|
1809
|
+
expect(config.chart.plotBackgroundColor).toBe(null);
|
1810
|
+
expect(config.chart.plotBackgroundImage).toBe(null);
|
1811
|
+
expect(config.chart.plotBorderWidth).toBe(0);
|
1812
|
+
expect(config.chart.plotShadow).toBe(false);
|
1813
|
+
});
|
1814
|
+
|
1815
|
+
it("removes default offsets", () => {
|
1816
|
+
const config = chart.configChart();
|
1817
|
+
|
1818
|
+
expect(config.chart.margin).toEqual([0, 0, 0, 0]);
|
1819
|
+
expect(config.chart.spacing).toEqual([0, 0, 0, 0]);
|
1820
|
+
});
|
1821
|
+
|
1822
|
+
it("sets load event handler", () => {
|
1823
|
+
const config = chart.configChart();
|
1824
|
+
chart.addTooltips = jest.fn();
|
1825
|
+
config.chart.events.load({ target: mockChart });
|
1826
|
+
expect(chart.addTooltips).toHaveBeenCalled();
|
1827
|
+
});
|
1828
|
+
|
1829
|
+
it("sets render event handler", () => {
|
1830
|
+
const config = chart.configChart();
|
1831
|
+
chart.moveCustomElementsToFront = jest.fn();
|
1832
|
+
chart.setTicksStyles = jest.fn();
|
1833
|
+
config.chart.events.render({ target: mockChart });
|
1834
|
+
expect(chart.moveCustomElementsToFront).toHaveBeenCalled();
|
1835
|
+
expect(chart.setTicksStyles).toHaveBeenCalled();
|
1836
|
+
});
|
1837
|
+
|
1838
|
+
it("sets beforeRedraw event handler", () => {
|
1839
|
+
const config = chart.configChart();
|
1840
|
+
chart.setPane = jest.fn();
|
1841
|
+
chart.updateCustomElements = jest.fn();
|
1842
|
+
config.chart.events.beforeRedraw({ target: mockChart });
|
1843
|
+
expect(chart.setPane).toHaveBeenCalled();
|
1844
|
+
expect(chart.updateCustomElements).toHaveBeenCalled();
|
1845
|
+
});
|
1846
|
+
|
1847
|
+
it("sets beforeRender event handler", () => {
|
1848
|
+
const config = chart.configChart();
|
1849
|
+
chart.setPane = jest.fn();
|
1850
|
+
chart.setCustomElements = jest.fn();
|
1851
|
+
config.chart.events.beforeRender({ target: mockChart });
|
1852
|
+
expect(chart.setPane).toHaveBeenCalled();
|
1853
|
+
expect(chart.setCustomElements).toHaveBeenCalled();
|
1854
|
+
});
|
1855
|
+
|
1856
|
+
it("sets pane options", () => {
|
1857
|
+
const config = chart.configChart();
|
1858
|
+
|
1859
|
+
expect(config.pane).toEqual({
|
1860
|
+
startAngle: -90,
|
1861
|
+
endAngle: 90,
|
1862
|
+
background: null,
|
1863
|
+
center: [0, 0],
|
1864
|
+
});
|
1865
|
+
});
|
1866
|
+
|
1867
|
+
it("sets yAxis default options", () => {
|
1868
|
+
const config = chart.configChart();
|
1869
|
+
|
1870
|
+
expect(config.yAxis.min).toBe(0);
|
1871
|
+
expect(config.yAxis.max).toBe(200);
|
1872
|
+
expect(config.yAxis.tickPositions).toEqual([0, 50, 160, 180, 200]);
|
1873
|
+
expect(config.yAxis.tickColor).toBe(mockOptions.gauge.background);
|
1874
|
+
expect(config.yAxis.tickLength).toBe(40);
|
1875
|
+
expect(config.yAxis.tickWidth).toBe(20);
|
1876
|
+
expect(config.yAxis.minorTickInterval).toBe(null);
|
1877
|
+
expect(config.yAxis.lineWidth).toBe(0);
|
1878
|
+
expect(config.yAxis.plotBands).toEqual([
|
1879
|
+
{ color: "#BF1D30", from: 0, thickness: 16, title: "Low", to: 50 },
|
1880
|
+
{ color: "#FFA310", from: 50, thickness: 16, title: "Medium", to: 160 },
|
1881
|
+
{ color: "#037C5A", from: 160, thickness: 16, title: "High", to: 200 },
|
1882
|
+
]);
|
1883
|
+
});
|
1884
|
+
|
1885
|
+
it("sets yAxis labels options", () => {
|
1886
|
+
const config = chart.configChart();
|
1887
|
+
|
1888
|
+
expect(config.yAxis.labels.enabled).toBe(mockOptions.label.show);
|
1889
|
+
expect(config.yAxis.labels.enabled).toBe(mockOptions.label.show);
|
1890
|
+
expect(config.yAxis.labels.distance).toBe(0),
|
1891
|
+
expect(config.yAxis.labels.verticalAlign).toBe("middle"),
|
1892
|
+
expect(config.yAxis.labels.allowOverlap).toBe(true),
|
1893
|
+
expect(config.yAxis.labels.align).toBe("left");
|
1894
|
+
expect(config.yAxis.labels.style).toEqual({
|
1895
|
+
whiteSpace: "nowrap",
|
1896
|
+
width: "auto",
|
1897
|
+
});
|
1898
|
+
expect(config.yAxis.labels.useHTML).toBe(true);
|
1899
|
+
chart.formatTickLabel = jest.fn().mockReturnValue("<span>100.00</span>");
|
1900
|
+
expect(config.yAxis.labels.formatter({ value: 100 })).toBe("<span>100.00</span>");
|
1901
|
+
});
|
1902
|
+
|
1903
|
+
it("sets series", () => {
|
1904
|
+
chart.value = 204;
|
1905
|
+
const series = chart.configChart().series[0];
|
1906
|
+
|
1907
|
+
expect(series.name).toBe(null);
|
1908
|
+
expect(series.data).toEqual([204]);
|
1909
|
+
expect(series.dataLabels).toEqual([
|
1910
|
+
{
|
1911
|
+
enabled: false,
|
1912
|
+
},
|
1913
|
+
]);
|
1914
|
+
expect(series.dial).toEqual({
|
1915
|
+
radius: "70%",
|
1916
|
+
backgroundColor: mockOptions.gauge.pivot.color,
|
1917
|
+
baseWidth: 2 * mockOptions.gauge.pivot.radius,
|
1918
|
+
baseLength: "0%",
|
1919
|
+
rearLength: "0%",
|
1920
|
+
});
|
1921
|
+
expect(series.pivot).toEqual({
|
1922
|
+
backgroundColor: mockOptions.gauge.pivot.color,
|
1923
|
+
radius: mockOptions.gauge.pivot.radius,
|
1924
|
+
});
|
1925
|
+
});
|
1926
|
+
});
|
1927
|
+
});
|
1928
|
+
|
1929
|
+
function simplifyString(str) {
|
1930
|
+
return str.replace(/[\s\n\t]/g, "");
|
1931
|
+
}
|