@@ -238,7 +238,12 @@ function refreshSlicer() {
238
238
}
239
239
240
240
const barSlot = computed (() => {
241
- const bs = drawingArea .value .width / (slicer .value .end - slicer .value .start );
241
+ let bs;
242
+ if (FINAL_CONFIG .value .orientation === ' vertical' ) {
243
+ bs = drawingArea .value .width / (slicer .value .end - slicer .value .start );
244
+ } else {
245
+ bs = drawingArea .value .height / (slicer .value .end - slicer .value .start );
246
+ }
242
247
return bs <= 0 ? 0 : bs;
243
248
});
244
249
@@ -285,6 +290,9 @@ const yLabels = computed(() => {
285
290
zero: drawingArea .value .bottom - (drawingArea .value .height * ((Math .abs (scale .min )) / (scale .max + Math .abs (scale .min )))),
286
291
y: drawingArea .value .bottom - (drawingArea .value .height * ((t + Math .abs (scale .min )) / ((scale .max ) + Math .abs (scale .min )))),
287
292
x: drawingArea .value .left - 8 ,
293
+ horizontal_zero: drawingArea .value .left + (drawingArea .value .width * ((Math .abs (scale .min )) / (scale .max + Math .abs (scale .min )))),
294
+ horizontal_x: drawingArea .value .left + (drawingArea .value .width * ((t + Math .abs (scale .min )) / ((scale .max ) + Math .abs (scale .min )))),
295
+ horizontal_y: drawingArea .value .bottom - 8 ,
288
296
value: t
289
297
}
290
298
});
@@ -299,7 +307,9 @@ const formattedDataset = computed(() => {
299
307
if (! isDataset .value ) return [];
300
308
301
309
let cumulativeY = Array (maxSeries .value ).fill (0 );
310
+ let cumulativeX = Array (maxSeries .value ).fill (0 );
302
311
let cumulativeNegY = Array (maxSeries .value ).fill (0 );
312
+ let cumulativeNegX = Array (maxSeries .value ).fill (0 );
303
313
304
314
const premax = Math .max (... datasetSignedTotals .value .positive ) || 0 ;
305
315
const workingMin = Math .min (... datasetSignedTotals .value .negative );
@@ -311,7 +321,9 @@ const formattedDataset = computed(() => {
311
321
const maxTotal = (MAX + (MIN >= 0 ? 0 : Math .abs (MIN ))) || 1
312
322
313
323
const totalHeight = drawingArea .value .height ;
324
+ const totalWidth = drawingArea .value .width ;
314
325
const ZERO_POSITION = yLabels .value [0 ] ? yLabels .value [0 ].zero : drawingArea .value .bottom ;
326
+ const HORIZONTAL_ZERO_POSITION = yLabels .value [0 ] ? yLabels .value [0 ].horizontal_zero : drawingArea .value .left ;
315
327
316
328
return unmutableDataset .value
317
329
.filter (ds => ! segregated .value .includes (ds .id ))
@@ -323,6 +335,10 @@ const formattedDataset = computed(() => {
323
335
return drawingArea .value .left + (barSlot .value * i) + (barSlot .value * FINAL_CONFIG .value .style .chart .bars .gapRatio / 4 );
324
336
});
325
337
338
+ const horizontal_y = slicedSeries .map ((_dp , i ) => {
339
+ return drawingArea .value .top + (barSlot .value * i) + (barSlot .value * FINAL_CONFIG .value .style .chart .bars .gapRatio / 4 );
340
+ })
341
+
326
342
const y = slicedSeries .map ((dp , i ) => {
327
343
const proportion = FINAL_CONFIG .value .style .chart .bars .distributed
328
344
? (dp || 0 ) / datasetTotals .value [i]
@@ -341,6 +357,24 @@ const formattedDataset = computed(() => {
341
357
return currentY;
342
358
});
343
359
360
+ const horizontal_x = slicedSeries .map ((dp , i ) => {
361
+ const proportion = FINAL_CONFIG .value .style .chart .bars .distributed
362
+ ? (dp || 0 ) / datasetTotals .value [i]
363
+ : (dp || 0 ) / maxTotal;
364
+
365
+ let currentX, hw;
366
+ if (dp > 0 ) {
367
+ hw = totalWidth * proportion;
368
+ currentX = HORIZONTAL_ZERO_POSITION + cumulativeX[i];
369
+ cumulativeX[i] += hw;
370
+ } else {
371
+ hw = totalWidth * proportion;
372
+ currentX = HORIZONTAL_ZERO_POSITION - Math .abs (hw) - cumulativeNegX[i]
373
+ cumulativeNegX[i] += Math .abs (hw)
374
+ }
375
+ return currentX;
376
+ });
377
+
344
378
const height = slicedSeries .map ((dp , i ) => {
345
379
const proportion = FINAL_CONFIG .value .style .chart .bars .distributed
346
380
? (dp || 0 ) / datasetTotals .value [i]
@@ -353,6 +387,18 @@ const formattedDataset = computed(() => {
353
387
}
354
388
});
355
389
390
+ const horizontal_width = slicedSeries .map ((dp , i ) => {
391
+ const proportion = FINAL_CONFIG .value .style .chart .bars .distributed
392
+ ? (dp || 0 ) / datasetTotals .value [i]
393
+ : (dp || 0 ) / maxTotal;
394
+
395
+ if (dp > 0 ) {
396
+ return totalWidth * proportion
397
+ } else {
398
+ return totalWidth * Math .abs (proportion)
399
+ }
400
+ });
401
+
356
402
const absoluteTotal = slicedSeries .map (v => Math .abs (v)).reduce ((a , b ) => a + b, 0 );
357
403
358
404
return {
@@ -369,6 +415,9 @@ const formattedDataset = computed(() => {
369
415
x,
370
416
y,
371
417
height,
418
+ horizontal_width,
419
+ horizontal_y,
420
+ horizontal_x
372
421
};
373
422
});
374
423
});
@@ -719,7 +768,8 @@ defineExpose({
719
768
< / linearGradient>
720
769
< / defs>
721
770
722
- < template v- if = " FINAL_CONFIG.style.chart.grid.x.showHorizontalLines" >
771
+ <!-- HORIZONTAL LINES (vertical mode) -->
772
+ < template v- if = " FINAL_CONFIG.style.chart.grid.x.showHorizontalLines && FINAL_CONFIG.orientation === 'vertical'" >
723
773
< line
724
774
v- for = " (yLabel, i) in yLabels"
725
775
: x1= " drawingArea.left"
@@ -728,10 +778,26 @@ defineExpose({
728
778
: y2= " yLabel.y"
729
779
: stroke= " FINAL_CONFIG.style.chart.grid.x.axisColor"
730
780
: stroke- width= " 1"
781
+ stroke- linecap= " round"
782
+ / >
783
+ < / template>
784
+
785
+ <!-- HORIZONTAL LINES (horizontal mode) -->
786
+ < template v- if = " FINAL_CONFIG.style.chart.grid.x.showHorizontalLines && FINAL_CONFIG.orientation === 'horizontal'" >
787
+ < line
788
+ v- for = " (_, i) in (slicer.end - slicer.start + 1)"
789
+ : x1= " drawingArea.left"
790
+ : x2= " drawingArea.right"
791
+ : y1= " drawingArea.top + (barSlot * i)"
792
+ : y2= " drawingArea.top + (barSlot * i)"
793
+ : stroke= " FINAL_CONFIG.style.chart.grid.y.axisColor"
794
+ : stroke- width= " 1"
795
+ stroke- linecap= " round"
731
796
/ >
732
797
< / template>
733
798
734
- < template v- if = " FINAL_CONFIG.style.chart.grid.y.showVerticalLines" >
799
+ <!-- VERTICAL LINES (vertical mode) -->
800
+ < template v- if = " FINAL_CONFIG.style.chart.grid.y.showVerticalLines && FINAL_CONFIG.orientation === 'vertical'" >
735
801
< line
736
802
v- for = " (_, i) in (slicer.end - slicer.start + 1)"
737
803
: x1= " drawingArea.left + (barSlot * i)"
@@ -740,25 +806,60 @@ defineExpose({
740
806
: y2= " drawingArea.bottom"
741
807
: stroke= " FINAL_CONFIG.style.chart.grid.y.axisColor"
742
808
: stroke- width= " 1"
809
+ stroke- linecap= " round"
743
810
/ >
744
811
< / template>
745
812
746
- <!-- STACKED BARS -->
747
- < g v- for = " (dp, i) in formattedDataset" >
748
- < rect
749
- v- for = " (rect, j) in dp.x"
750
- : x= " rect"
751
- : y= " dp.y[j] < 0 ? 0 : dp.y[j]"
752
- : height= " dp.height[j] < 0 ? 0.0001 : dp.height[j]"
753
- : rx= " FINAL_CONFIG.style.chart.bars.borderRadius > dp.height[j] / 2 ? (dp.height[j] < 0 ? 0 : dp.height[j]) / 2 : FINAL_CONFIG.style.chart.bars.borderRadius "
754
- : width= " barSlot * (1 - FINAL_CONFIG.style.chart.bars.gapRatio / 2)"
755
- : fill= " FINAL_CONFIG.style.chart.bars.gradient.show ? `url(#gradient_${dp.id})` : dp.color"
756
- : stroke= " FINAL_CONFIG.style.chart.backgroundColor"
757
- : stroke- width= " FINAL_CONFIG.style.chart.bars.strokeWidth"
813
+ <!-- VERTICAL LINES (horizontal mode) -->
814
+ < template v- if = " FINAL_CONFIG.style.chart.grid.x.showHorizontalLines && FINAL_CONFIG.orientation === 'horizontal'" >
815
+ < line
816
+ v- for = " (yLabel, i) in yLabels"
817
+ : x1= " yLabel.horizontal_x"
818
+ : x2= " yLabel.horizontal_x"
819
+ : y1= " drawingArea.top"
820
+ : y2= " drawingArea.bottom"
821
+ : stroke= " FINAL_CONFIG.style.chart.grid.x.axisColor"
822
+ : stroke- width= " 1"
758
823
stroke- linecap= " round"
759
- stroke- linejoin= " round"
760
- : class = " { 'vue-data-ui-bar-animated': FINAL_CONFIG.useCssAnimation, 'vue-data-ui-bar-transition': isLoaded }"
761
- / >
824
+ / >
825
+ < / template>
826
+
827
+ < g v- for = " (dp, i) in formattedDataset" >
828
+ <!-- STACKED BARS (vertical mode) -->
829
+ < template v- if = " FINAL_CONFIG.orientation === 'vertical'" >
830
+ < rect
831
+ v- for = " (rect, j) in dp.x"
832
+ : x= " rect"
833
+ : y= " dp.y[j] < 0 ? 0 : dp.y[j]"
834
+ : height= " dp.height[j] < 0 ? 0.0001 : dp.height[j]"
835
+ : rx= " FINAL_CONFIG.style.chart.bars.borderRadius > dp.height[j] / 2 ? (dp.height[j] < 0 ? 0 : dp.height[j]) / 2 : FINAL_CONFIG.style.chart.bars.borderRadius "
836
+ : width= " barSlot * (1 - FINAL_CONFIG.style.chart.bars.gapRatio / 2)"
837
+ : fill= " FINAL_CONFIG.style.chart.bars.gradient.show ? `url(#gradient_${dp.id})` : dp.color"
838
+ : stroke= " FINAL_CONFIG.style.chart.backgroundColor"
839
+ : stroke- width= " FINAL_CONFIG.style.chart.bars.strokeWidth"
840
+ stroke- linecap= " round"
841
+ stroke- linejoin= " round"
842
+ : class = " { 'vue-data-ui-bar-animated': FINAL_CONFIG.useCssAnimation, 'vue-data-ui-bar-transition': isLoaded }"
843
+ / >
844
+ < / template>
845
+
846
+ <!-- STACKED BARS (horizontal mode) -->
847
+ < template v- else >
848
+ < rect
849
+ v- for = " (rect, j) in dp.horizontal_x"
850
+ : x= " rect"
851
+ : y= " dp.horizontal_y[j] < 0 ? 0 : dp.horizontal_y[j]"
852
+ : width= " dp.horizontal_width[j] < 0 ? 0.0001 : dp.horizontal_width[j]"
853
+ : rx= " FINAL_CONFIG.style.chart.bars.borderRadius > dp.height[j] / 2 ? (dp.height[j] < 0 ? 0 : dp.height[j]) / 2 : FINAL_CONFIG.style.chart.bars.borderRadius "
854
+ : height= " barSlot * (1 - FINAL_CONFIG.style.chart.bars.gapRatio / 2)"
855
+ : fill= " FINAL_CONFIG.style.chart.bars.gradient.show ? `url(#gradient_${dp.id})` : dp.color"
856
+ : stroke= " FINAL_CONFIG.style.chart.backgroundColor"
857
+ : stroke- width= " FINAL_CONFIG.style.chart.bars.strokeWidth"
858
+ stroke- linecap= " round"
859
+ stroke- linejoin= " round"
860
+ : class = " { 'vue-data-ui-bar-animated': FINAL_CONFIG.useCssAnimation, 'vue-data-ui-bar-transition': isLoaded }"
861
+ / >
862
+ < / template>
762
863
< / g>
763
864
764
865
<!-- X AXIS -->
@@ -812,7 +913,8 @@ defineExpose({
812
913
{{ FINAL_CONFIG .style .chart .grid .y .axisName .text }}
813
914
< / text>
814
915
815
- < template v- if = " mutableConfig.dataLabels.show" >
916
+ <!-- RECT DATA LABELS (vertical mode) -->
917
+ < template v- if = " mutableConfig.dataLabels.show && FINAL_CONFIG.orientation === 'vertical'" >
816
918
< g v- for = " (dp, i) in formattedDataset" >
817
919
<!-- RECT LABELS -->
818
920
< text
@@ -830,7 +932,7 @@ defineExpose({
830
932
< / text>
831
933
< / g>
832
934
833
- <!-- RECT TOTAL LABEL -->
935
+ <!-- RECT TOTAL LABELS -->
834
936
< g v- if = " FINAL_CONFIG.style.chart.bars.totalValues.show && formattedDataset.length > 1" >
835
937
< text
836
938
v- for = " (total, i) in totalLabels"
@@ -846,8 +948,42 @@ defineExpose({
846
948
< / g>
847
949
< / template>
848
950
849
- <!-- Y LABELS -->
850
- < template v- if = " FINAL_CONFIG.style.chart.grid.y.axisLabels.show && !FINAL_CONFIG.style.chart.bars.distributed" >
951
+ <!-- RECT DATA LABELS (horizontal mode) -->
952
+ < template v- if = " mutableConfig.dataLabels.show && FINAL_CONFIG.orientation === 'horizontal'" >
953
+ < g v- for = " (dp, i) in formattedDataset" >
954
+ <!-- RECT LABELS -->
955
+ < text
956
+ v- for = " (rect, j) in dp.horizontal_x"
957
+ : x= " rect + ((dp.horizontal_width[j] < 0 ? 0.0001 : dp.horizontal_width[j]) / 2)"
958
+ : y= " dp.horizontal_y[j] + (barSlot * (1 - FINAL_CONFIG.style.chart.bars.gapRatio / 2) / 2) + (FINAL_CONFIG.style.chart.bars.dataLabels.fontSize /3)"
959
+ : font- size= " FINAL_CONFIG.style.chart.bars.dataLabels.fontSize"
960
+ : fill= " FINAL_CONFIG.style.chart.bars.dataLabels.adaptColorToBackground ? adaptColorToBackground(dp.color) : FINAL_CONFIG.style.chart.bars.dataLabels.color"
961
+ : font- weight= " FINAL_CONFIG.style.chart.bars.dataLabels.bold ? 'bold' : 'normal'"
962
+ text- anchor= " middle"
963
+ >
964
+ {{ FINAL_CONFIG .style .chart .bars .showDistributedPercentage && FINAL_CONFIG .style .chart .bars .distributed ?
965
+ barDataLabelPercentage (dp .proportions [j] * 100 , dp, i, j) :
966
+ barDataLabel (dp .series [j], dp, i, j, dp .signedSeries [j]) }}
967
+ < / text>
968
+ < / g>
969
+ <!-- RECT TOTAL LABELS -->
970
+ < g v- if = " FINAL_CONFIG.style.chart.bars.totalValues.show && formattedDataset.length > 1" >
971
+ < text
972
+ v- for = " (total, i) in totalLabels"
973
+ : x= " drawingArea.right + FINAL_CONFIG.style.chart.bars.totalValues.fontSize / 3"
974
+ : y= " drawingArea.top + (barSlot * i) + barSlot / 2"
975
+ text- anchor= " start"
976
+ : font- size= " FINAL_CONFIG.style.chart.bars.totalValues.fontSize"
977
+ : font- weight= " FINAL_CONFIG.style.chart.bars.totalValues.bold ? 'bold' : 'normal'"
978
+ : fill= " FINAL_CONFIG.style.chart.bars.totalValues.color"
979
+ >
980
+ {{ barDataLabel (total .value , total, i, total .sign ) }}
981
+ < / text>
982
+ < / g>
983
+ < / template>
984
+
985
+ <!-- SCALE LABELS (vertical mode) -->
986
+ < template v- if = " FINAL_CONFIG.style.chart.grid.y.axisLabels.show && !FINAL_CONFIG.style.chart.bars.distributed && FINAL_CONFIG.orientation === 'vertical'" >
851
987
< line
852
988
v- for = " (yLabel, i) in yLabels"
853
989
: x1= " drawingArea.left"
@@ -875,8 +1011,37 @@ defineExpose({
875
1011
< / text>
876
1012
< / template>
877
1013
878
- <!-- TIME LABELS -->
879
- < template v- if = " FINAL_CONFIG.style.chart.grid.x.timeLabels.show" >
1014
+ <!-- SCALE LABELS (horizontal mode) -->
1015
+ < template v- if = " FINAL_CONFIG.style.chart.grid.y.axisLabels.show && !FINAL_CONFIG.style.chart.bars.distributed && FINAL_CONFIG.orientation === 'horizontal'" >
1016
+ < line
1017
+ v- for = " (yLabel, i) in yLabels"
1018
+ : x1= " yLabel.horizontal_x"
1019
+ : x2= " yLabel.horizontal_x"
1020
+ : y1= " drawingArea.bottom"
1021
+ : y2= " drawingArea.bottom + 6"
1022
+ : stroke= " FINAL_CONFIG.style.chart.grid.x.axisColor"
1023
+ : stroke- width= " 1"
1024
+ stroke- linecap= " round"
1025
+ / >
1026
+ < text
1027
+ v- for = " (yLabel, i) in yLabels"
1028
+ : font- size= " FINAL_CONFIG.style.chart.grid.x.timeLabels.fontSize"
1029
+ : font- weight= " FINAL_CONFIG.style.chart.grid.y.axisLabels.bold ? 'bold' : 'normal'"
1030
+ : fill= " FINAL_CONFIG.style.chart.grid.y.axisLabels.color"
1031
+ : text- anchor= " FINAL_CONFIG.style.chart.grid.x.timeLabels.rotation > 0 ? 'start' : FINAL_CONFIG.style.chart.grid.x.timeLabels.rotation < 0 ? 'end' : 'middle'"
1032
+ : transform= " `translate(${yLabel.horizontal_x}, ${drawingArea.bottom + FINAL_CONFIG.style.chart.grid.x.timeLabels.fontSize * 1.3 + FINAL_CONFIG.style.chart.grid.x.timeLabels.offsetY}), rotate(${FINAL_CONFIG.style.chart.grid.x.timeLabels.rotation})`"
1033
+ >
1034
+ {{ dataLabel ({
1035
+ p: FINAL_CONFIG .style .chart .bars .dataLabels .prefix ,
1036
+ v: yLabel .value ,
1037
+ s: FINAL_CONFIG .style .chart .bars .dataLabels .suffix ,
1038
+ r: FINAL_CONFIG .style .chart .grid .y .axisLabels .rounding ,
1039
+ }) }}
1040
+ < / text>
1041
+ < / template>
1042
+
1043
+ <!-- TIME LABELS VERTICAL -->
1044
+ < template v- if = " FINAL_CONFIG.style.chart.grid.x.timeLabels.show && FINAL_CONFIG.orientation === 'vertical'" >
880
1045
< text
881
1046
v- for = " (timeLabel, i) in timeLabels"
882
1047
: text- anchor= " FINAL_CONFIG.style.chart.grid.x.timeLabels.rotation > 0 ? 'start' : FINAL_CONFIG.style.chart.grid.x.timeLabels.rotation < 0 ? 'end' : 'middle'"
@@ -889,8 +1054,23 @@ defineExpose({
889
1054
< / text>
890
1055
< / template>
891
1056
892
- <!-- TOOLTIP TRAPS -->
893
- < template v- if = " mutableConfig.showTooltip" >
1057
+ <!-- TIME LABELS HORIZONTAL -->
1058
+ < template v- if = " FINAL_CONFIG.style.chart.grid.x.timeLabels.show && FINAL_CONFIG.orientation === 'horizontal'" >
1059
+ < text
1060
+ v- for = " (timeLabel, i) in timeLabels"
1061
+ text- anchor= " end"
1062
+ : font- size= " FINAL_CONFIG.style.chart.grid.y.axisLabels.fontSize"
1063
+ : font- weight= " FINAL_CONFIG.style.chart.grid.y.axisLabels.bold ? 'bold' : 'normal'"
1064
+ : fill= " FINAL_CONFIG.style.chart.grid.y.axisLabels.color"
1065
+ : x= " drawingArea.left - 8"
1066
+ : y= " drawingArea.top + (barSlot * i ) + (barSlot / 2) + FINAL_CONFIG.style.chart.grid.y.axisLabels.fontSize / 3"
1067
+ >
1068
+ {{ timeLabel }}
1069
+ < / text>
1070
+ < / template>
1071
+
1072
+ <!-- TOOLTIP TRAPS (vertical mode) -->
1073
+ < template v- if = " mutableConfig.showTooltip && FINAL_CONFIG.orientation === 'vertical'" >
894
1074
< rect
895
1075
v- for = " (_, i) in (slicer.end - slicer.start)"
896
1076
: x= " drawingArea.left + (i * barSlot)"
@@ -904,6 +1084,21 @@ defineExpose({
904
1084
/ >
905
1085
< / template>
906
1086
1087
+ <!-- TOOLTIP TRAPS (vertical mode) -->
1088
+ < template v- if = " mutableConfig.showTooltip && FINAL_CONFIG.orientation === 'horizontal'" >
1089
+ < rect
1090
+ v- for = " (_, i) in (slicer.end - slicer.start)"
1091
+ : x= " drawingArea.left"
1092
+ : y= " drawingArea.top + (i * barSlot)"
1093
+ : width= " drawingArea.width < 0 ? 0 : drawingArea.width"
1094
+ : height= " barSlot"
1095
+ @click= " selectDatapoint(i)"
1096
+ @mouseenter= " useTooltip(i)"
1097
+ @mouseleave= " trapIndex = null; isTooltip = false"
1098
+ : fill= " i === trapIndex ? FINAL_CONFIG.style.chart.highlighter.color + opacity[FINAL_CONFIG.style.chart.highlighter.opacity] : 'transparent'"
1099
+ / >
1100
+ < / template>
1101
+
907
1102
< slot name= " svg" v- bind= " { ...drawingArea }" / >
908
1103
< / svg>
909
1104
0 commit comments