@osfarm/itineraire-technique 1.1.8 → 1.1.9
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/js/chart-render.js +240 -184
- package/package.json +1 -1
package/js/chart-render.js
CHANGED
|
@@ -39,17 +39,35 @@ class RotationRenderer {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
fixRotationData(rotationData) {
|
|
42
|
+
if (!rotationData || typeof rotationData !== 'object') return rotationData;
|
|
43
|
+
|
|
42
44
|
if (rotationData.options == undefined)
|
|
43
45
|
rotationData.options = {};
|
|
44
46
|
|
|
45
47
|
if (rotationData.options?.view == undefined || rotationData?.options?.view == '')
|
|
46
48
|
rotationData.options.view = 'horizontal';
|
|
47
49
|
|
|
50
|
+
// Safety check for steps array
|
|
51
|
+
if (!rotationData.steps || !Array.isArray(rotationData.steps)) {
|
|
52
|
+
rotationData.steps = [];
|
|
53
|
+
return rotationData;
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
// Map rotationData items to make sure that the startDate and endDate are proper Date objects
|
|
49
57
|
rotationData.steps.map((item) => {
|
|
58
|
+
if (!item) return item;
|
|
59
|
+
|
|
50
60
|
item.startDate = new Date(item.startDate);
|
|
51
61
|
item.endDate = new Date(item.endDate);
|
|
52
62
|
|
|
63
|
+
// Safety check for invalid dates
|
|
64
|
+
if (isNaN(item.startDate.getTime())) {
|
|
65
|
+
item.startDate = new Date();
|
|
66
|
+
}
|
|
67
|
+
if (isNaN(item.endDate.getTime()) || item.endDate <= item.startDate) {
|
|
68
|
+
item.endDate = new Date(item.startDate.getTime() + (30 * 24 * 60 * 60 * 1000)); // Default to 30 days later
|
|
69
|
+
}
|
|
70
|
+
|
|
53
71
|
// Add a duration in months
|
|
54
72
|
item.duration = Math.round((item.endDate - item.startDate) / (30 * 1000 * 60 * 60 * 24));
|
|
55
73
|
|
|
@@ -340,9 +358,14 @@ class RotationRenderer {
|
|
|
340
358
|
|
|
341
359
|
// Avoid words that are too long
|
|
342
360
|
testWidth = echarts.format.getTextRect(line).width;
|
|
343
|
-
|
|
361
|
+
let trimCount = 0;
|
|
362
|
+
const maxTrimCount = line.length; // Prevent infinite loop
|
|
363
|
+
|
|
364
|
+
while (testWidth > maxWidth && line.length > 0 && trimCount < maxTrimCount) {
|
|
344
365
|
line = line.slice(0, -1);
|
|
366
|
+
if (line.length === 0) break; // Safety check
|
|
345
367
|
testWidth = echarts.format.getTextRect(line).width;
|
|
368
|
+
trimCount++;
|
|
346
369
|
}
|
|
347
370
|
}
|
|
348
371
|
|
|
@@ -376,101 +399,221 @@ class RotationRenderer {
|
|
|
376
399
|
let maxXPositions = new Map();
|
|
377
400
|
|
|
378
401
|
function renderItem(params, api) {
|
|
402
|
+
// Safety checks to prevent crashes
|
|
403
|
+
if (!params || !api) return null;
|
|
404
|
+
|
|
405
|
+
try {
|
|
406
|
+
var categoryIndex = api.value(0);
|
|
407
|
+
var start = api.coord([api.value(1), categoryIndex]);
|
|
408
|
+
var end = api.coord([api.value(2), categoryIndex]);
|
|
409
|
+
var name = api.value(3);
|
|
410
|
+
var type = api.value(4);
|
|
411
|
+
let secondary_crop = api.value(5);
|
|
412
|
+
let bHasSecondaryCrops = api.value(6);
|
|
413
|
+
|
|
414
|
+
// Safety check for invalid coordinates
|
|
415
|
+
if (!start || !end || start.length < 2 || end.length < 2) return null;
|
|
416
|
+
if (isNaN(start[0]) || isNaN(start[1]) || isNaN(end[0]) || isNaN(end[1])) return null;
|
|
417
|
+
|
|
418
|
+
const x = start[0];
|
|
419
|
+
let y = start[1];
|
|
420
|
+
|
|
421
|
+
const style = api.style();
|
|
422
|
+
style.opacity = 0.5;
|
|
423
|
+
|
|
424
|
+
if (params.context.rendered == undefined) {
|
|
425
|
+
// Start of a new rendering round
|
|
426
|
+
maxXPositions = new Map();
|
|
427
|
+
|
|
428
|
+
for (let catIndex = 0; catIndex < 3; catIndex++) {
|
|
429
|
+
for (let track = 0; track < 3; track++) {
|
|
430
|
+
maxXPositions.set('track_left_' + catIndex + '_' + track, params.coordSys.width);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
379
434
|
|
|
380
|
-
|
|
381
|
-
var start = api.coord([api.value(1), categoryIndex]);
|
|
382
|
-
var end = api.coord([api.value(2), categoryIndex]);
|
|
383
|
-
var name = api.value(3);
|
|
384
|
-
var type = api.value(4);
|
|
385
|
-
let secondary_crop = api.value(5);
|
|
386
|
-
let bHasSecondaryCrops = api.value(6);
|
|
435
|
+
params.context.rendered = true;
|
|
387
436
|
|
|
388
|
-
|
|
389
|
-
|
|
437
|
+
// Remove the default emphasis style
|
|
438
|
+
api.styleEmphasis({});
|
|
390
439
|
|
|
391
|
-
|
|
392
|
-
style.opacity = 0.5;
|
|
440
|
+
if (type == 'rotation_item') {
|
|
393
441
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
442
|
+
// start[0] // abscisse gauche de l'élément (après zoom)
|
|
443
|
+
// start[1] // ordonnée gauche de l'élément
|
|
444
|
+
// end[0] // abscisse droite de l'élément (après zoom)
|
|
445
|
+
// end[1] // ordonnée droite de l'élément
|
|
446
|
+
// height // Hauteur de l'élément
|
|
397
447
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
448
|
+
// params.coordSys.x // début du canva
|
|
449
|
+
// params.coordSys.y // début du canva
|
|
450
|
+
// params.coordSys.width, // largeur du canva
|
|
451
|
+
// params.coordSys.height // hauteur du canva
|
|
452
|
+
|
|
453
|
+
let height = self.barHeight - 20; // 20 px margin top and bottom
|
|
454
|
+
let top = y - height / 2;
|
|
455
|
+
let textXMargin = 2;
|
|
456
|
+
let textYMargin = 10;
|
|
457
|
+
|
|
458
|
+
if (bHasSecondaryCrops) {
|
|
459
|
+
height = self.barHeight - 40; // 20 px margin top and bottom
|
|
460
|
+
top = y - height / 2 - 15;
|
|
461
|
+
textXMargin = 2;
|
|
462
|
+
textYMargin = 10;
|
|
401
463
|
}
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
464
|
|
|
405
|
-
|
|
465
|
+
if (secondary_crop) {
|
|
466
|
+
// Move secondary crops a bit down and reduce their size
|
|
467
|
+
top = top + height + 5;
|
|
468
|
+
height = height / 3;
|
|
469
|
+
textXMargin = 5;
|
|
470
|
+
textYMargin = 5;
|
|
471
|
+
}
|
|
406
472
|
|
|
407
|
-
|
|
408
|
-
|
|
473
|
+
const arrowWidth = height / 3;
|
|
474
|
+
const border = 3;
|
|
409
475
|
|
|
410
|
-
|
|
476
|
+
var points = [
|
|
477
|
+
[x, top],
|
|
478
|
+
[end[0] - border, top],
|
|
479
|
+
[end[0] + arrowWidth - border, top + height / 2],
|
|
480
|
+
[end[0] - border, top + height],
|
|
481
|
+
[x, top + height],
|
|
482
|
+
[x + arrowWidth, top + height / 2],
|
|
483
|
+
];
|
|
411
484
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
// end[0] // abscisse droite de l'élément (après zoom)
|
|
415
|
-
// end[1] // ordonnée droite de l'élément
|
|
416
|
-
// height // Hauteur de l'élément
|
|
485
|
+
//const itemLabelWidth = echarts.format.getTextRect(name).width + textMargin * 2;
|
|
486
|
+
const itemWidth = end[0] - x;
|
|
417
487
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
// params.coordSys.width, // largeur du canva
|
|
421
|
-
// params.coordSys.height // hauteur du canva
|
|
488
|
+
// if (itemLabelWidth > itemWidth)
|
|
489
|
+
// name = ''; // Hide the label as we won't have the room to show it
|
|
422
490
|
|
|
423
|
-
|
|
424
|
-
let top = y - height / 2;
|
|
425
|
-
let textXMargin = 2;
|
|
426
|
-
let textYMargin = 10;
|
|
491
|
+
name = wrapText(echarts, name, itemWidth - arrowWidth, height);
|
|
427
492
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
top = y - height / 2 - 15;
|
|
431
|
-
textXMargin = 2;
|
|
432
|
-
textYMargin = 10;
|
|
433
|
-
}
|
|
493
|
+
// See this for clip regions : https://stackoverflow.com/questions/71735038/setting-border-and-label-in-custom-apache-echarts
|
|
494
|
+
// https://stackoverflow.com/questions/73653691/how-to-draw-a-custom-triangle-in-renderitem-in-apache-echarts
|
|
434
495
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
496
|
+
return (
|
|
497
|
+
{
|
|
498
|
+
type: 'polygon',
|
|
499
|
+
transition: ['shape'],
|
|
500
|
+
shape: {
|
|
501
|
+
points: points
|
|
502
|
+
},
|
|
503
|
+
style: style,
|
|
504
|
+
emphasis: {
|
|
505
|
+
style: {
|
|
506
|
+
shadowBlur: 4,
|
|
507
|
+
shadowOffsetX: 1,
|
|
508
|
+
shadowOffsetY: 2,
|
|
509
|
+
shadowColor: 'rgba(0, 0, 0, 0.2)'
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
textConfig: {
|
|
513
|
+
position: [arrowWidth + textXMargin, textYMargin]
|
|
514
|
+
},
|
|
515
|
+
textContent: {
|
|
516
|
+
style: {
|
|
517
|
+
text: name,
|
|
518
|
+
fill: '#000',
|
|
519
|
+
width: 80,
|
|
520
|
+
fontWeight: 'bold'
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
);
|
|
441
525
|
}
|
|
442
526
|
|
|
443
|
-
|
|
444
|
-
|
|
527
|
+
if (type == 'intervention_bottom' || type == 'intervention_top') {
|
|
528
|
+
|
|
529
|
+
const height = 20;
|
|
530
|
+
const margin = 10;
|
|
531
|
+
const textMargin = 5;
|
|
445
532
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
[end[0] - border, top],
|
|
449
|
-
[end[0] + arrowWidth - border, top + height / 2],
|
|
450
|
-
[end[0] - border, top + height],
|
|
451
|
-
[x, top + height],
|
|
452
|
-
[x + arrowWidth, top + height / 2],
|
|
453
|
-
];
|
|
533
|
+
// Maintain a list of max x for each row. If the max x is further right than the label we try to push,
|
|
534
|
+
// use another row. If for all rows the space is taken, just drop this item
|
|
454
535
|
|
|
455
|
-
|
|
456
|
-
|
|
536
|
+
let trackToUse = null;
|
|
537
|
+
const itemLabelWidth = echarts.format.getTextRect(name).width + textMargin * 2;
|
|
457
538
|
|
|
458
|
-
|
|
459
|
-
|
|
539
|
+
for (let track = 0; track < 3; track++) {
|
|
540
|
+
if (!maxXPositions.has('track_right_' + categoryIndex + '_' + track)) {
|
|
541
|
+
// Situation where the track is empty
|
|
542
|
+
trackToUse = track;
|
|
543
|
+
break;
|
|
544
|
+
}
|
|
460
545
|
|
|
461
|
-
|
|
546
|
+
let trackLeft = maxXPositions.get('track_left_' + categoryIndex + '_' + track);
|
|
547
|
+
if (trackLeft > (x + itemLabelWidth)) {
|
|
548
|
+
// Situation where the drawing has started right of the current element
|
|
549
|
+
trackToUse = track;
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
462
552
|
|
|
463
|
-
|
|
464
|
-
|
|
553
|
+
let trackRight = maxXPositions.get('track_right_' + categoryIndex + '_' + track);
|
|
554
|
+
if (trackRight < x) {
|
|
555
|
+
// Situation where the last painted element is sufficiently far on the left
|
|
556
|
+
trackToUse = track;
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
465
560
|
|
|
466
|
-
|
|
467
|
-
|
|
561
|
+
if (trackToUse == null)
|
|
562
|
+
return null;
|
|
563
|
+
|
|
564
|
+
let currentRight = maxXPositions.get('track_right_' + categoryIndex + '_' + trackToUse);
|
|
565
|
+
if (currentRight == undefined || currentRight < x + itemLabelWidth)
|
|
566
|
+
maxXPositions.set('track_right_' + categoryIndex + '_' + trackToUse, x + itemLabelWidth);
|
|
567
|
+
|
|
568
|
+
let currentLeft = maxXPositions.get('track_left_' + categoryIndex + '_' + trackToUse);
|
|
569
|
+
if (currentLeft > x)
|
|
570
|
+
maxXPositions.set('track_left_' + categoryIndex + '_' + trackToUse, x);
|
|
571
|
+
|
|
572
|
+
// A nicer solution could be to draw large items in a reduced format until there is enough space for
|
|
573
|
+
// drawing them fully. Unfortunately that would require a two pass drawing which does not exist with Echarts ?
|
|
574
|
+
|
|
575
|
+
const arrowWidth = 3;
|
|
576
|
+
|
|
577
|
+
let arrowTop = y + 55;
|
|
578
|
+
let arrowBottom = y - 55;
|
|
579
|
+
|
|
580
|
+
y = margin + y + trackToUse * (height + margin) - (self.barHeight / 2);
|
|
581
|
+
|
|
582
|
+
var points = [];
|
|
583
|
+
var textPosition = [];
|
|
584
|
+
|
|
585
|
+
if (type == 'intervention_top') {
|
|
586
|
+
textPosition = [textMargin, textMargin];
|
|
587
|
+
points = [
|
|
588
|
+
[x, y],
|
|
589
|
+
[x + itemLabelWidth, y],
|
|
590
|
+
[x + itemLabelWidth, y + height],
|
|
591
|
+
[x + arrowWidth, y + height],
|
|
592
|
+
[x, arrowTop]
|
|
593
|
+
];
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
textPosition = [textMargin, textMargin + y - arrowBottom];
|
|
597
|
+
points = [
|
|
598
|
+
[x, arrowBottom],
|
|
599
|
+
[x + arrowWidth, y],
|
|
600
|
+
[x + itemLabelWidth, y],
|
|
601
|
+
[x + itemLabelWidth, y + height],
|
|
602
|
+
[x, y + height]
|
|
603
|
+
];
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return ({
|
|
468
607
|
type: 'polygon',
|
|
469
608
|
transition: ['shape'],
|
|
470
609
|
shape: {
|
|
471
610
|
points: points
|
|
472
611
|
},
|
|
473
|
-
style: style
|
|
612
|
+
style: api.style({
|
|
613
|
+
fill: style.fill,
|
|
614
|
+
stroke: style.fill,
|
|
615
|
+
textFill: '#000',
|
|
616
|
+
}),
|
|
474
617
|
emphasis: {
|
|
475
618
|
style: {
|
|
476
619
|
shadowBlur: 4,
|
|
@@ -480,130 +623,21 @@ class RotationRenderer {
|
|
|
480
623
|
},
|
|
481
624
|
},
|
|
482
625
|
textConfig: {
|
|
483
|
-
position:
|
|
626
|
+
position: textPosition
|
|
484
627
|
},
|
|
485
628
|
textContent: {
|
|
486
629
|
style: {
|
|
487
630
|
text: name,
|
|
488
631
|
fill: '#000',
|
|
489
|
-
width: 80,
|
|
490
|
-
fontWeight: 'bold'
|
|
491
632
|
}
|
|
492
633
|
}
|
|
493
634
|
}
|
|
494
|
-
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
if (type == 'intervention_bottom' || type == 'intervention_top') {
|
|
498
|
-
|
|
499
|
-
const height = 20;
|
|
500
|
-
const margin = 10;
|
|
501
|
-
const textMargin = 5;
|
|
502
|
-
|
|
503
|
-
// Maintain a list of max x for each row. If the max x is further right than the label we try to push,
|
|
504
|
-
// use another row. If for all rows the space is taken, just drop this item
|
|
505
|
-
|
|
506
|
-
let trackToUse = null;
|
|
507
|
-
const itemLabelWidth = echarts.format.getTextRect(name).width + textMargin * 2;
|
|
508
|
-
|
|
509
|
-
for (let track = 0; track < 3; track++) {
|
|
510
|
-
if (!maxXPositions.has('track_right_' + categoryIndex + '_' + track)) {
|
|
511
|
-
// Situation where the track is empty
|
|
512
|
-
trackToUse = track;
|
|
513
|
-
break;
|
|
514
|
-
}
|
|
635
|
+
);
|
|
515
636
|
|
|
516
|
-
let trackLeft = maxXPositions.get('track_left_' + categoryIndex + '_' + track);
|
|
517
|
-
if (trackLeft > (x + itemLabelWidth)) {
|
|
518
|
-
// Situation where the drawing has started right of the current element
|
|
519
|
-
trackToUse = track;
|
|
520
|
-
break;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
let trackRight = maxXPositions.get('track_right_' + categoryIndex + '_' + track);
|
|
524
|
-
if (trackRight < x) {
|
|
525
|
-
// Situation where the last painted element is sufficiently far on the left
|
|
526
|
-
trackToUse = track;
|
|
527
|
-
break;
|
|
528
|
-
}
|
|
529
637
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
let currentRight = maxXPositions.get('track_right_' + categoryIndex + '_' + trackToUse);
|
|
535
|
-
if (currentRight == undefined || currentRight < x + itemLabelWidth)
|
|
536
|
-
maxXPositions.set('track_right_' + categoryIndex + '_' + trackToUse, x + itemLabelWidth);
|
|
537
|
-
|
|
538
|
-
let currentLeft = maxXPositions.get('track_left_' + categoryIndex + '_' + trackToUse);
|
|
539
|
-
if (currentLeft > x)
|
|
540
|
-
maxXPositions.set('track_left_' + categoryIndex + '_' + trackToUse, x);
|
|
541
|
-
|
|
542
|
-
// A nicer solution could be to draw large items in a reduced format until there is enough space for
|
|
543
|
-
// drawing them fully. Unfortunately that would require a two pass drawing which does not exist with Echarts ?
|
|
544
|
-
|
|
545
|
-
const arrowWidth = 3;
|
|
546
|
-
|
|
547
|
-
let arrowTop = y + 55;
|
|
548
|
-
let arrowBottom = y - 55;
|
|
549
|
-
|
|
550
|
-
y = margin + y + trackToUse * (height + margin) - (self.barHeight / 2);
|
|
551
|
-
|
|
552
|
-
var points = [];
|
|
553
|
-
var textPosition = [];
|
|
554
|
-
|
|
555
|
-
if (type == 'intervention_top') {
|
|
556
|
-
textPosition = [textMargin, textMargin];
|
|
557
|
-
points = [
|
|
558
|
-
[x, y],
|
|
559
|
-
[x + itemLabelWidth, y],
|
|
560
|
-
[x + itemLabelWidth, y + height],
|
|
561
|
-
[x + arrowWidth, y + height],
|
|
562
|
-
[x, arrowTop]
|
|
563
|
-
];
|
|
564
|
-
}
|
|
565
|
-
else {
|
|
566
|
-
textPosition = [textMargin, textMargin + y - arrowBottom];
|
|
567
|
-
points = [
|
|
568
|
-
[x, arrowBottom],
|
|
569
|
-
[x + arrowWidth, y],
|
|
570
|
-
[x + itemLabelWidth, y],
|
|
571
|
-
[x + itemLabelWidth, y + height],
|
|
572
|
-
[x, y + height]
|
|
573
|
-
];
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
return ({
|
|
577
|
-
type: 'polygon',
|
|
578
|
-
transition: ['shape'],
|
|
579
|
-
shape: {
|
|
580
|
-
points: points
|
|
581
|
-
},
|
|
582
|
-
style: api.style({
|
|
583
|
-
fill: style.fill,
|
|
584
|
-
stroke: style.fill,
|
|
585
|
-
textFill: '#000',
|
|
586
|
-
}),
|
|
587
|
-
emphasis: {
|
|
588
|
-
style: {
|
|
589
|
-
shadowBlur: 4,
|
|
590
|
-
shadowOffsetX: 1,
|
|
591
|
-
shadowOffsetY: 2,
|
|
592
|
-
shadowColor: 'rgba(0, 0, 0, 0.2)'
|
|
593
|
-
},
|
|
594
|
-
},
|
|
595
|
-
textConfig: {
|
|
596
|
-
position: textPosition
|
|
597
|
-
},
|
|
598
|
-
textContent: {
|
|
599
|
-
style: {
|
|
600
|
-
text: name,
|
|
601
|
-
fill: '#000',
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
);
|
|
606
|
-
|
|
638
|
+
} catch (error) {
|
|
639
|
+
console.error('Error in renderItem:', error);
|
|
640
|
+
return null;
|
|
607
641
|
}
|
|
608
642
|
}
|
|
609
643
|
|
|
@@ -823,8 +857,29 @@ class RotationRenderer {
|
|
|
823
857
|
];
|
|
824
858
|
|
|
825
859
|
let monthsPerYear = new Map();
|
|
860
|
+
|
|
861
|
+
// Safety check to prevent infinite loops
|
|
862
|
+
if (!steps || steps.length === 0) {
|
|
863
|
+
series.push(months);
|
|
864
|
+
return series;
|
|
865
|
+
}
|
|
866
|
+
|
|
826
867
|
let startMonth = new Date(steps.at(0).startDate.valueOf());
|
|
827
|
-
|
|
868
|
+
let endDate = steps.at(-1).endDate;
|
|
869
|
+
|
|
870
|
+
// Safety check for valid dates and reasonable duration (max 20 years)
|
|
871
|
+
if (isNaN(startMonth.getTime()) ||
|
|
872
|
+
isNaN(endDate.getTime()) ||
|
|
873
|
+
startMonth >= endDate ||
|
|
874
|
+
(endDate - startMonth) > (20 * 365 * 24 * 60 * 60 * 1000)) {
|
|
875
|
+
series.push(months);
|
|
876
|
+
return series;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
let loopCount = 0;
|
|
880
|
+
const maxLoops = 240; // Max 20 years * 12 months
|
|
881
|
+
|
|
882
|
+
while (startMonth < endDate && loopCount < maxLoops) {
|
|
828
883
|
const monthName = startMonth.toLocaleDateString(undefined, { month: 'short' });
|
|
829
884
|
const year = startMonth.getFullYear();
|
|
830
885
|
|
|
@@ -843,6 +898,7 @@ class RotationRenderer {
|
|
|
843
898
|
|
|
844
899
|
// increment the current month
|
|
845
900
|
startMonth.setMonth(startMonth.getMonth() + 1);
|
|
901
|
+
loopCount++;
|
|
846
902
|
}
|
|
847
903
|
|
|
848
904
|
series.push(months);
|