@@ -106,7 +106,7 @@ onMounted(() => {
106106 error ({
107107 componentName: ' VueUiVerticalBar' ,
108108 type: ' dataset'
109- })
109+ });
110110 }
111111
112112 barCount .value = props .dataset .flatMap (serie => {
@@ -189,15 +189,14 @@ const immutableDataset = computed(() => {
189189 .map ((serie , i ) => {
190190 const id = ` vertical_parent_${ i} _${ uid .value } ` ;
191191 const hasChildren = !! serie .children && serie .children .length > 0 ;
192- if (! [null , undefined ].includes (serie .value ) && serie .value < 0 ) {
193- console .warn (` VueUiVerticalBar is not designed to graph negative values. ${ serie .name || ' serie at index' + i} has the following value: ${ serie .value } ` )
194- }
192+
195193 return {
196194 ... serie,
197195 id,
198196 shape: ' square' ,
199197 opacity: segregated .value .includes (id) ? 0.5 : 1 ,
200- value: hasChildren ? serie .children .map (c => c .value || 0 ).reduce ((a , b ) => a + b, 0 ) : (serie .value || 0 ),
198+ value: hasChildren ? serie .children .map (c => c .value || 0 ).reduce ((a , b ) => a + b, 0 ) : (Math .abs (serie .value ) || 0 ),
199+ sign: serie .value >= 0 ? 1 : - 1 ,
201200 hasChildren,
202201 isChild: false ,
203202 segregate : () => segregate (id),
@@ -206,16 +205,14 @@ const immutableDataset = computed(() => {
206205 children: ! serie .children || ! serie .children .length ? [] : serie .children
207206 .toSorted ((a , b ) => isSortDown .value ? b .value - a .value : a .value - b .value )
208207 .map ((c , j ) => {
209- if (! [null , undefined ].includes (c .value ) && c .value < 0 ) {
210- console .warn (` VueUiVerticalBar is not designed to graph negative values. ${ c .name + ' child serie' || ' child serie at index' + i + ' , ' + j } has the following value: ${ c .value } ` )
211- }
212208 return {
213209 ... c,
214- value: c .value || 0 ,
210+ value: Math .abs (c .value ) || 0 ,
211+ sign: c .value >= 0 ? 1 : - 1 ,
215212 isChild: true ,
216213 parentId: id,
217214 parentName: serie .name ,
218- parentValue: serie .value ,
215+ parentValue: serie .value || hasChildren ? serie . children . map ( c => c . value || 0 ). reduce (( a , b ) => a + b, 0 ) : 0 ,
219216 id: ` vertical_child_${ i} _${ j} _${ uid .value } ` ,
220217 childIndex: j,
221218 color: convertColorToHex (c .color ) || convertColorToHex (serie .color ) || customPalette .value [i] || palette[i] || palette[i % palette .length ]
@@ -302,18 +299,18 @@ const mutableDataset = computed(() => {
302299});
303300
304301const total = computed (() => {
305- return mutableDataset .value .map (serie => serie .value ).reduce ((a ,b ) => a + b);
302+ return mutableDataset .value .map (serie => Math . abs ( serie .value )) .reduce ((a ,b ) => a + b, 0 );
306303});
307304
308305function calcProportionToTotal (val , formatted = false , rounding = 0 ) {
309306 if (formatted) {
310307 return dataLabel ({
311- v: val / total .value * 100 ,
308+ v: Math . abs ( val) / total .value * 100 ,
312309 s: ' %' ,
313310 r: rounding
314311 });
315312 }
316- return val / total .value ;
313+ return Math . abs ( val) / total .value ;
317314}
318315
319316const bars = computed (() => {
@@ -326,6 +323,10 @@ const bars = computed(() => {
326323 })
327324})
328325
326+ const hasNegative = computed (() => {
327+ return bars .value .map (b => b .sign ).includes (- 1 )
328+ });
329+
329330const max = computed (() => {
330331 return Math .max (... mutableDataset .value .flatMap (serie => {
331332 if (serie .children && serie .children .length ) {
@@ -338,7 +339,7 @@ const max = computed(() => {
338339
339340function calcBarWidth (val ) {
340341 const ratio = val / max .value ;
341- return drawableArea .value .width * ratio;
342+ return ( drawableArea .value .width / ( hasNegative . value ? 2 : 1 )) * ratio;
342343}
343344
344345function calcDataLabelX (val ) {
@@ -353,8 +354,9 @@ function getParentData(serie, index) {
353354 return {
354355 y: start + (height / 2 ) - (FINAL_CONFIG .value .style .chart .layout .bars .parentLabels .fontSize ),
355356 name: parent .name ,
356- value: [undefined , NaN , null ].includes (parent .value ) ? ' ' : parent .value .toFixed (FINAL_CONFIG .value .style .chart .layout .bars .dataLabels .value .roundingValue ),
357- percentageToTotal: isNaN (parent .value / total .value ) ? ' ' : calcProportionToTotal (parent .value , true , FINAL_CONFIG .value .style .chart .layout .bars .dataLabels .percentage .roundingPercentage )
357+ value: [undefined , NaN , null ].includes (parent .value ) ? ' ' : parent .sign === 1 ? parent .value : - parent .value ,
358+ percentageToTotal: isNaN (parent .value / total .value ) ? ' ' : calcProportionToTotal (parent .value , true , FINAL_CONFIG .value .style .chart .layout .bars .dataLabels .percentage .roundingPercentage ),
359+ sign: parent .sign
358360 }
359361}
360362
@@ -403,10 +405,10 @@ function useTooltip(bar, seriesIndex) {
403405 if (FINAL_CONFIG .value .style .chart .tooltip .showValue ) {
404406 html += ` <div>${ FINAL_CONFIG .value .translations .value } : <b>${ applyDataLabel (
405407 FINAL_CONFIG .value .style .chart .layout .bars .dataLabels .value .formatter ,
406- bar .value ,
408+ bar .sign === 1 ? bar . value : - bar . value ,
407409 dataLabel ({
408410 p: FINAL_CONFIG .value .style .chart .tooltip .prefix ,
409- v: bar .value ,
411+ v: bar .sign === 1 ? bar . value : - bar . value ,
410412 s: FINAL_CONFIG .value .style .chart .tooltip .suffix ,
411413 r: FINAL_CONFIG .value .style .chart .tooltip .roundingValue
412414 }),
@@ -416,13 +418,13 @@ function useTooltip(bar, seriesIndex) {
416418
417419 if (FINAL_CONFIG .value .style .chart .tooltip .showPercentage ) {
418420 html += ` <div>${ FINAL_CONFIG .value .translations .percentageToTotal } : <b>${ dataLabel ({
419- v: bar .value / total .value * 100 ,
421+ v: Math . abs ( bar .value ) / total .value * 100 ,
420422 s: ' %' ,
421423 r: FINAL_CONFIG .value .style .chart .tooltip .roundingPercentage
422424 })} </b></div>` ;
423425 if (bar .isChild ) {
424426 html += ` <div>${ FINAL_CONFIG .value .translations .percentageToSerie } : <b>${ dataLabel ({
425- v: bar .value / bar .parentValue * 100 ,
427+ v: Math . abs ( bar .value ) / Math . abs ( bar .parentValue ) * 100 ,
426428 s: ' %' ,
427429 r: FINAL_CONFIG .value .style .chart .tooltip .roundingPercentage
428430 })} </b></div>` ;
@@ -432,16 +434,16 @@ function useTooltip(bar, seriesIndex) {
432434 }
433435}
434436
435- function makeDataLabel (value , datapoint , seriesIndex ) {
437+ function makeDataLabel (value , datapoint , seriesIndex , sign ) {
436438 if (! FINAL_CONFIG .value .style .chart .layout .bars .dataLabels .value .show ) {
437439 return ' ' ;
438440 }
439441 const label = applyDataLabel (
440442 FINAL_CONFIG .value .style .chart .layout .bars .dataLabels .value .formatter ,
441- value,
443+ sign === 1 ? value : - value,
442444 dataLabel ({
443445 p: FINAL_CONFIG .value .style .chart .layout .bars .dataLabels .value .prefix ,
444- v: value,
446+ v: sign === 1 ? value : - value,
445447 s: FINAL_CONFIG .value .style .chart .layout .bars .dataLabels .value .suffix ,
446448 r: FINAL_CONFIG .value .style .chart .layout .bars .dataLabels .value .roundingValue
447449 }),
@@ -469,8 +471,8 @@ const table = computed(() => {
469471 return {
470472 color: bar .color ,
471473 parentName: bar .name ,
472- parentValue: bar .value ,
473- percentageToTotal: bar .value / total .value ,
474+ parentValue: bar .sign === 1 ? bar . value : - bar . value ,
475+ percentageToTotal: Math . abs ( bar .value ) / total .value ,
474476 childName: " " ,
475477 childValue: " " ,
476478 childPercentageToParent: " " ,
@@ -484,9 +486,9 @@ const table = computed(() => {
484486 parentValue: bar .parentValue ,
485487 percentageToTotal: bar .parentValue / total .value ,
486488 childName: bar .name ,
487- childValue: bar .value ,
488- childPercentageToParent: bar .value / bar .parentValue ,
489- childPercentageToTotal: bar .value / total .value
489+ childValue: bar .sign === 1 ? bar . value : - bar . value ,
490+ childPercentageToParent: Math . abs ( bar .value ) / Math . abs ( bar .parentValue ) ,
491+ childPercentageToTotal: Math . abs ( bar .value ) / total .value
490492 }
491493 }else {
492494 return {
@@ -495,9 +497,9 @@ const table = computed(() => {
495497 parentValue: " " ,
496498 percentageToTotal: " " ,
497499 childName: bar .name ,
498- childValue: bar .value ,
499- childPercentageToParent: bar .value / bar .parentValue ,
500- childPercentageToTotal: bar .value / total .value
500+ childValue: bar .sign === 1 ? bar . value : - bar . value ,
501+ childPercentageToParent: Math . abs ( bar .value ) / Math . abs ( bar .parentValue ) ,
502+ childPercentageToTotal: Math . abs ( bar .value ) / total .value
501503 }
502504 }
503505 }
@@ -674,7 +676,7 @@ defineExpose({
674676 <!-- UNDERLAYER -->
675677 <rect
676678 :data-cy =" `vertical-bar-rect-underlayer-${i}`"
677- :x =" drawableArea.left"
679+ :x =" hasNegative ? drawableArea.left + (drawableArea.width / 2) - (serie.sign === 1 ? 0 : calcBarWidth(serie.value) <= 0 ? 0.0001 : calcBarWidth(serie.value)) : drawableArea.left"
678680 :y =" drawableArea.top + ((barGap + barHeight) * i)"
679681 :width =" calcBarWidth(serie.value) <= 0 ? 0.0001 : calcBarWidth(serie.value)"
680682 :height =" barHeight <= 0 ? 0.0001 : barHeight"
@@ -686,7 +688,7 @@ defineExpose({
686688 <g v-for =" (serie, i) in bars" >
687689 <!-- BARS -->
688690 <rect
689- :x =" drawableArea.left"
691+ :x =" hasNegative ? drawableArea.left + (drawableArea.width / 2) - (serie.sign === 1 ? 0 : calcBarWidth(serie.value) <= 0 ? 0.0001 : calcBarWidth(serie.value)) : drawableArea.left"
690692 :y =" drawableArea.top + ((barGap + barHeight) * i)"
691693 :width =" calcBarWidth(serie.value) <= 0 ? 0.0001 : calcBarWidth(serie.value)"
692694 :height =" barHeight <= 0 ? 0.0001 : barHeight"
@@ -707,19 +709,30 @@ defineExpose({
707709 :stroke =" FINAL_CONFIG.style.chart.layout.separators.color"
708710 :stroke-width =" FINAL_CONFIG.style.chart.layout.separators.strokeWidth"
709711 stroke-linecap =" round"
712+ />
713+
714+ <line
715+ v-if =" hasNegative && FINAL_CONFIG.style.chart.layout.separators.show"
716+ :x1 =" drawableArea.left + drawableArea.width / 2"
717+ :x2 =" drawableArea.left + drawableArea.width / 2"
718+ :y1 =" drawableArea.top"
719+ :y2 =" drawableArea.bottom"
720+ :stroke =" FINAL_CONFIG.style.chart.layout.separators.color"
721+ :stroke-width =" FINAL_CONFIG.style.chart.layout.separators.strokeWidth"
722+ stroke-linecap =" round"
710723 />
711724
712725 <!-- DATALABELS -->
713726 <text
714727 :data-cy =" `vertical-bar-datalabel-${i}`"
715- :x =" calcDataLabelX(serie.value) + 3 + FINAL_CONFIG.style.chart.layout.bars.dataLabels.offsetX"
728+ :x =" !hasNegative ? calcDataLabelX(serie.value) + 3 + FINAL_CONFIG.style.chart.layout.bars.dataLabels.offsetX : (drawableArea.left + (drawableArea.width / 2) + (serie.sign === 1 ? -12: 12) + (serie.sign === 1 ? -FINAL_CONFIG.style.chart.layout.bars.dataLabels.offsetX : FINAL_CONFIG.style.chart.layout.bars.dataLabels.offsetX)) "
716729 :y =" drawableArea.top + ((barGap + barHeight) * i) + (barHeight / 2) + FINAL_CONFIG.style.chart.layout.bars.dataLabels.fontSize / 2"
717- text-anchor =" start"
730+ : text-anchor =" !hasNegative || serie.sign === - 1 ? ' start' : 'end' "
718731 :font-size =" FINAL_CONFIG.style.chart.layout.bars.dataLabels.fontSize"
719732 :fill =" FINAL_CONFIG.style.chart.layout.bars.dataLabels.color"
720733 :font-weight =" FINAL_CONFIG.style.chart.layout.bars.dataLabels.bold ? 'bold' : 'normal'"
721734 >
722- {{ makeDataLabel(serie.value, serie, i) }}
735+ {{ makeDataLabel(serie.value, serie, i, serie.sign ) }}
723736 </text >
724737
725738 <!-- CHILDREN | LONELY PARENTS NAMES -->
@@ -756,7 +769,7 @@ defineExpose({
756769 :font-weight =" FINAL_CONFIG.style.chart.layout.bars.dataLabels.bold ? 'bold' : 'normal'"
757770 text-anchor =" start"
758771 >
759- {{ makeDataLabel(getParentData(serie, i).value), getParentData(serie, i), i }}
772+ {{ makeDataLabel(getParentData(serie, i).value), getParentData(serie, i), i, getParentData(serie, i).sign }}
760773 </text >
761774
762775 <!-- TOOLTIP TRAPS -->
0 commit comments