@@ -224,8 +224,37 @@ const cellSize = computed(() => {
224
224
225
225
const dataLabels = computed (() => {
226
226
const yLabels = FINAL_CONFIG .value .style .layout .dataLabels .yAxis .values .length ? FINAL_CONFIG .value .style .layout .dataLabels .yAxis .values : props .dataset .map (ds => ds .name );
227
- const xLabels = FINAL_CONFIG .value .style .layout .dataLabels .xAxis .values
227
+ const xLabels = FINAL_CONFIG .value .style .layout .dataLabels .xAxis .values ;
228
+ const _yTotals = props .dataset .map (ds => ds .values .reduce ((a , b ) => a + b, 0 ))
229
+ const maxYTotal = Math .max (... _yTotals);
230
+ const minYTotal = Math .min (... _yTotals);
231
+
232
+ const _xTotals = []
233
+
234
+ for (let i = 0 ; i < maxX .value ; i += 1 ) {
235
+ _xTotals .push (props .dataset .map (ds => ds .values [i] || 0 ).reduce ((a , b ) => a + b, 0 ))
236
+ }
237
+
238
+ const maxXTotal = Math .max (... _xTotals);
239
+ const minXTotal = Math .min (... _xTotals);
240
+
228
241
return {
242
+ yTotals: _yTotals .map (rowTotal => {
243
+ const proportion = isNaN (rowTotal / maxYTotal) ? 0 : rowTotal / maxYTotal;
244
+ return {
245
+ total: rowTotal,
246
+ proportion,
247
+ color: interpolateColorHex (FINAL_CONFIG .value .style .layout .cells .colors .cold , FINAL_CONFIG .value .style .layout .cells .colors .hot , minYTotal, maxYTotal, rowTotal)
248
+ }
249
+ }),
250
+ xTotals: _xTotals .map (columnTotal => {
251
+ const proportion = isNaN (columnTotal / maxXTotal) ? 0 : columnTotal / maxXTotal;
252
+ return {
253
+ total: columnTotal,
254
+ proportion,
255
+ color: interpolateColorHex (FINAL_CONFIG .value .style .layout .cells .colors .cold , FINAL_CONFIG .value .style .layout .cells .colors .hot , minXTotal, maxXTotal, columnTotal)
256
+ }
257
+ }),
229
258
yLabels,
230
259
xLabels: xLabels .slice (0 , maxX .value )
231
260
}
@@ -334,6 +363,34 @@ const bottomLegendIndicatorX = computed(() => {
334
363
return drawingArea .value .left + ((svg .value .width - drawingArea .value .left - FINAL_CONFIG .value .style .layout .padding .right ) * (hoveredValue .value / maxValue .value ))
335
364
});
336
365
366
+ function getRowTotal (index ) {
367
+ return applyDataLabel (
368
+ FINAL_CONFIG .value .style .layout .cells .value .formatter ,
369
+ dataLabels .value .yTotals [index].total ,
370
+ dataLabel ({
371
+ p: FINAL_CONFIG .value .style .layout .dataLabels .prefix ,
372
+ v: dataLabels .value .yTotals [index].total ,
373
+ s: FINAL_CONFIG .value .style .layout .dataLabels .suffix ,
374
+ r: FINAL_CONFIG .value .style .layout .cells .value .roundingValue
375
+ }),
376
+ { datapoint: dataLabels .value .yTotals [index], rowIndex: index }
377
+ )
378
+ }
379
+
380
+ function getcolumnTotal (index ) {
381
+ return applyDataLabel (
382
+ FINAL_CONFIG .value .style .layout .cells .value .formatter ,
383
+ dataLabels .value .xTotals [index].total ,
384
+ dataLabel ({
385
+ p: FINAL_CONFIG .value .style .layout .dataLabels .prefix ,
386
+ v: dataLabels .value .xTotals [index].total ,
387
+ s: FINAL_CONFIG .value .style .layout .dataLabels .suffix ,
388
+ r: FINAL_CONFIG .value .style .layout .cells .value .roundingValue
389
+ }),
390
+ { datapoint: dataLabels .value .xTotals [index], colIndex: index }
391
+ )
392
+ }
393
+
337
394
const table = computed (() => {
338
395
const head = props .dataset .map (ds => {
339
396
return {
@@ -387,6 +444,7 @@ function toggleAnnotator() {
387
444
isAnnotator .value = ! isAnnotator .value ;
388
445
}
389
446
447
+
390
448
defineExpose ({
391
449
generatePdf,
392
450
generateCsv,
@@ -516,11 +574,34 @@ defineExpose({
516
574
<slot name =" chart-background" />
517
575
</foreignObject >
518
576
577
+ <template v-if =" FINAL_CONFIG .style .layout .cells .columnTotal .color .show " >
578
+ <rect
579
+ v-for =" (col, i) in dataLabels.xTotals"
580
+ :x =" drawingArea.left + cellSize.width * i + (FINAL_CONFIG.style.layout.cells.spacing / 2) + (FINAL_CONFIG.style.layout.cells.rowTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0)"
581
+ :y =" drawingArea.top - cellSize.height / 3 - FINAL_CONFIG.style.layout.cells.spacing"
582
+ :height =" cellSize.height / 3"
583
+ :width =" cellSize.width - FINAL_CONFIG.style.layout.cells.spacing"
584
+ :fill =" FINAL_CONFIG.style.layout.cells.colors.underlayer"
585
+ :stroke =" FINAL_CONFIG.style.backgroundColor"
586
+ :stroke-width =" FINAL_CONFIG.style.layout.cells.spacing"
587
+ />
588
+ <rect
589
+ v-for =" (col, i) in dataLabels.xTotals"
590
+ :x =" drawingArea.left + cellSize.width * i + (FINAL_CONFIG.style.layout.cells.spacing / 2) + (FINAL_CONFIG.style.layout.cells.rowTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0)"
591
+ :y =" drawingArea.top - cellSize.height / 3 - FINAL_CONFIG.style.layout.cells.spacing"
592
+ :height =" cellSize.height / 3"
593
+ :width =" cellSize.width - FINAL_CONFIG.style.layout.cells.spacing"
594
+ :fill =" col.color"
595
+ :stroke =" FINAL_CONFIG.style.backgroundColor"
596
+ :stroke-width =" FINAL_CONFIG.style.layout.cells.spacing"
597
+ />
598
+ </template >
599
+
519
600
<g v-for =" (serie, i) in mutableDataset" >
520
601
<g v-for =" (cell, j) in serie.temperatures" >
521
602
<rect
522
603
data-cy =" cell-underlayer"
523
- :x =" drawingArea.left + cellSize.width * j + (FINAL_CONFIG.style.layout.cells.spacing / 2)"
604
+ :x =" drawingArea.left + cellSize.width * j + (FINAL_CONFIG.style.layout.cells.spacing / 2) + (FINAL_CONFIG.style.layout.cells.rowTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0) "
524
605
:y =" drawingArea.top + cellSize.height * i + (FINAL_CONFIG.style.layout.cells.spacing / 2)"
525
606
:width =" cellSize.width - FINAL_CONFIG.style.layout.cells.spacing"
526
607
:height =" cellSize.height - FINAL_CONFIG.style.layout.cells.spacing"
@@ -530,7 +611,7 @@ defineExpose({
530
611
/>
531
612
<rect
532
613
data-cy =" cell"
533
- :x =" drawingArea.left + cellSize.width * j + (FINAL_CONFIG.style.layout.cells.spacing / 2)"
614
+ :x =" drawingArea.left + cellSize.width * j + (FINAL_CONFIG.style.layout.cells.spacing / 2) + (FINAL_CONFIG.style.layout.cells.rowTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0) "
534
615
:y =" drawingArea.top + cellSize.height * i + (FINAL_CONFIG.style.layout.cells.spacing / 2)"
535
616
:width =" cellSize.width - FINAL_CONFIG.style.layout.cells.spacing"
536
617
:height =" cellSize.height - FINAL_CONFIG.style.layout.cells.spacing"
@@ -545,7 +626,7 @@ defineExpose({
545
626
:font-size =" FINAL_CONFIG.style.layout.cells.value.fontSize"
546
627
:font-weight =" FINAL_CONFIG.style.layout.cells.value.bold ? 'bold': 'normal'"
547
628
:fill =" adaptColorToBackground(cell.color)"
548
- :x =" (drawingArea.left + cellSize.width * j) + (cellSize.width / 2)"
629
+ :x =" (drawingArea.left + cellSize.width * j) + (cellSize.width / 2) + + (FINAL_CONFIG.style.layout.cells.rowTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0) "
549
630
:y =" (drawingArea.top + cellSize.height * i) + (cellSize.height / 2) + FINAL_CONFIG.style.layout.cells.value.fontSize / 3"
550
631
>
551
632
{{ applyDataLabel(
@@ -566,7 +647,7 @@ defineExpose({
566
647
<!-- TOOLTIP TRAPS -->
567
648
<rect
568
649
data-cy =" tooltip-trap"
569
- :x =" drawingArea.left + cellSize.width * j"
650
+ :x =" drawingArea.left + cellSize.width * j + (FINAL_CONFIG.style.layout.cells.rowTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0) "
570
651
:y =" drawingArea.top + cellSize.height * i"
571
652
:width =" cellSize.width"
572
653
:height =" cellSize.height"
@@ -579,39 +660,90 @@ defineExpose({
579
660
<g v-if =" FINAL_CONFIG.style.layout.dataLabels.yAxis.show" >
580
661
<text
581
662
data-cy =" axis-y-label"
663
+ class =" vue-ui-heatmap-row-name"
582
664
:font-size =" FINAL_CONFIG.style.layout.dataLabels.yAxis.fontSize"
583
665
:fill =" FINAL_CONFIG.style.layout.dataLabels.yAxis.color"
584
666
:x =" drawingArea.left + FINAL_CONFIG.style.layout.dataLabels.yAxis.offsetX - 6"
585
- :y =" drawingArea.top + (cellSize.height * i) + cellSize.height / 2 + FINAL_CONFIG.style.layout.dataLabels.yAxis.fontSize / 3 + FINAL_CONFIG.style.layout.dataLabels.yAxis.offsetY"
667
+ :y =" drawingArea.top + (cellSize.height * i) + cellSize.height / 2 + FINAL_CONFIG.style.layout.dataLabels.yAxis.fontSize / 3 + FINAL_CONFIG.style.layout.dataLabels.yAxis.offsetY - (FINAL_CONFIG.style.layout.cells.rowTotal.value.show ? FINAL_CONFIG.style.layout.dataLabels.yAxis.fontSize / 1.5 : 0) "
586
668
text-anchor =" end"
587
669
:font-weight =" FINAL_CONFIG.style.layout.dataLabels.yAxis.bold ? 'bold' : 'normal'"
588
670
>
589
671
{{ dataLabels.yLabels[i] }}
590
672
</text >
673
+ <text
674
+ class =" vue-ui-heatmap-row-total"
675
+ v-if =" FINAL_CONFIG.style.layout.cells.rowTotal.value.show"
676
+ data-cy =" axis-y-label"
677
+ :font-size =" FINAL_CONFIG.style.layout.dataLabels.yAxis.fontSize"
678
+ :fill =" FINAL_CONFIG.style.layout.dataLabels.yAxis.color"
679
+ :x =" drawingArea.left + FINAL_CONFIG.style.layout.dataLabels.yAxis.offsetX - 6"
680
+ :y =" drawingArea.top + (cellSize.height * i) + cellSize.height / 2 + FINAL_CONFIG.style.layout.dataLabels.yAxis.fontSize + FINAL_CONFIG.style.layout.dataLabels.yAxis.offsetY"
681
+ text-anchor =" end"
682
+ :font-weight =" FINAL_CONFIG.style.layout.dataLabels.yAxis.bold ? 'bold' : 'normal'"
683
+ >
684
+ {{ getRowTotal(i) }}
685
+ </text >
591
686
</g >
687
+
688
+ <g v-if =" FINAL_CONFIG.style.layout.cells.rowTotal.color.show" >
689
+ <rect
690
+ :x =" drawingArea.left"
691
+ :y =" drawingArea.top + (cellSize.height * i)"
692
+ :width =" cellSize.height / 3"
693
+ :height =" cellSize.height - FINAL_CONFIG.style.layout.cells.spacing"
694
+ :fill =" FINAL_CONFIG.style.layout.cells.colors.underlayer"
695
+ :stroke =" FINAL_CONFIG.style.backgroundColor"
696
+ :stroke-width =" FINAL_CONFIG.style.layout.cells.spacing"
697
+ />
698
+ <rect
699
+ :x =" drawingArea.left"
700
+ :y =" drawingArea.top + (cellSize.height * i) + FINAL_CONFIG.style.layout.cells.spacing / 2"
701
+ :width =" cellSize.height / 3"
702
+ :height =" cellSize.height - FINAL_CONFIG.style.layout.cells.spacing"
703
+ :fill =" dataLabels.yTotals[i].color"
704
+ :stroke =" FINAL_CONFIG.style.backgroundColor"
705
+ :stroke-width =" FINAL_CONFIG.style.layout.cells.spacing"
706
+ />
707
+ </g >
708
+
592
709
</g >
593
710
<g v-if =" FINAL_CONFIG.style.layout.dataLabels.xAxis.show" >
594
711
<template v-for =" (label , i ) in dataLabels .xLabels " >
595
712
<text
713
+ class =" vue-ui-heatmap-col-name"
596
714
data-cy =" axis-x-label"
597
715
v-if =" !FINAL_CONFIG.style.layout.dataLabels.xAxis.showOnlyAtModulo || (FINAL_CONFIG.style.layout.dataLabels.xAxis.showOnlyAtModulo && i % FINAL_CONFIG.style.layout.dataLabels.xAxis.showOnlyAtModulo === 0)"
598
716
:text-anchor =" FINAL_CONFIG.style.layout.dataLabels.xAxis.rotation === 0 ? 'middle' : FINAL_CONFIG.style.layout.dataLabels.xAxis.rotation < 0 ? 'start' : 'end'"
599
717
:font-size =" FINAL_CONFIG.style.layout.dataLabels.xAxis.fontSize"
600
718
:fill =" FINAL_CONFIG.style.layout.dataLabels.xAxis.color"
601
719
:font-weight =" FINAL_CONFIG.style.layout.dataLabels.xAxis.bold ? 'bold' : 'normal'"
602
- :transform =" `translate(${drawingArea.left + cellSize.width / 2 + (drawingArea.width / dataLabels.xLabels.length * i) + FINAL_CONFIG.style.layout.dataLabels.xAxis.offsetX}, ${drawingArea.top + FINAL_CONFIG.style.layout.dataLabels.xAxis.offsetY - 6}), rotate(${FINAL_CONFIG.style.layout.dataLabels.xAxis.rotation})`"
720
+ :transform =" `translate(${drawingArea.left + cellSize.width / 2 + (drawingArea.width / dataLabels.xLabels.length * i) + FINAL_CONFIG.style.layout.dataLabels.xAxis.offsetX + (FINAL_CONFIG.style.layout.cells.rowTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0) }, ${drawingArea.top + FINAL_CONFIG.style.layout.dataLabels.xAxis.offsetY - 6 - (FINAL_CONFIG.style.layout.cells.columnTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0) }), rotate(${FINAL_CONFIG.style.layout.dataLabels.xAxis.rotation})`"
603
721
>
604
722
{{ label }}
605
723
</text >
606
724
</template >
607
725
</g >
608
726
727
+ <template v-if =" FINAL_CONFIG .style .layout .cells .columnTotal .value .show " >
728
+ <text
729
+ class =" vue-ui-heatmap-col-total"
730
+ v-for =" (_, i) in dataLabels.xLabels"
731
+ :text-anchor =" FINAL_CONFIG.style.layout.cells.columnTotal.value.rotation === 0 ? 'middle' : FINAL_CONFIG.style.layout.cells.columnTotal.value.rotation < 0 ? 'end' : 'start'"
732
+ :font-size =" FINAL_CONFIG.style.layout.dataLabels.xAxis.fontSize"
733
+ :fill =" FINAL_CONFIG.style.layout.dataLabels.xAxis.color"
734
+ :font-weight =" FINAL_CONFIG.style.layout.dataLabels.xAxis.bold ? 'bold' : 'normal'"
735
+ :transform =" `translate(${drawingArea.left + cellSize.width / 2 + (drawingArea.width / dataLabels.xLabels.length * i) + FINAL_CONFIG.style.layout.dataLabels.xAxis.offsetX + FINAL_CONFIG.style.layout.cells.columnTotal.value.offsetX + (FINAL_CONFIG.style.layout.cells.rowTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0)}, ${drawingArea.bottom - FINAL_CONFIG.style.layout.dataLabels.xAxis.fontSize + FINAL_CONFIG.style.layout.cells.columnTotal.value.offsetY}), rotate(${FINAL_CONFIG.style.layout.cells.columnTotal.value.rotation})`"
736
+ >
737
+ {{ getcolumnTotal(i) }}
738
+ </text >
739
+ </template >
740
+
609
741
<!-- BORDER FOR SELECTED RECT, PAINTED LAST -->
610
742
<g v-if =" selectedClone" >
611
743
<rect
612
744
data-cy =" cell-selected"
613
745
style =" pointer-events : none ;"
614
- :x =" selectedClone.x - ((FINAL_CONFIG.style.layout.cells.selected.border) / 2) + FINAL_CONFIG.style.layout.cells.spacing"
746
+ :x =" selectedClone.x - ((FINAL_CONFIG.style.layout.cells.selected.border) / 2) + FINAL_CONFIG.style.layout.cells.spacing + (FINAL_CONFIG.style.layout.cells.rowTotal.color.show ? (cellSize.height / 3 + FINAL_CONFIG.style.layout.cells.spacing) : 0) "
615
747
:y =" selectedClone.y - (FINAL_CONFIG.style.layout.cells.selected.border / 2) + FINAL_CONFIG.style.layout.cells.spacing"
616
748
:width =" cellSize.width - FINAL_CONFIG.style.layout.cells.spacing + FINAL_CONFIG.style.layout.cells.selected.border - (FINAL_CONFIG.style.layout.cells.spacing)"
617
749
:height =" cellSize.height - FINAL_CONFIG.style.layout.cells.spacing + FINAL_CONFIG.style.layout.cells.selected.border - (FINAL_CONFIG.style.layout.cells.spacing)"
0 commit comments