Skip to content

Commit 5a0603d

Browse files
committed
VueUiDonut improve datalabels
1 parent 4a72ece commit 5a0603d

File tree

4 files changed

+92
-54
lines changed

4 files changed

+92
-54
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vue-data-ui",
33
"private": false,
4-
"version": "1.9.27",
4+
"version": "1.9.28",
55
"type": "module",
66
"description": "A user-empowering data visualization Vue components library",
77
"keywords": [

src/components/vue-ui-chestnut.vue

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script setup>
22
import { ref, computed, onMounted, nextTick } from "vue";
3-
import { palette, opacity, shiftHue, adaptColorToBackground, makeDonut, convertColorToHex, makeXls } from "../lib";
3+
import { calcMarkerOffsetX, calcMarkerOffsetY, calcNutArrowPath, palette, opacity, shiftHue, adaptColorToBackground, makeDonut, convertColorToHex, makeXls } from "../lib";
44
import pdf from "../pdf";
55
import img from "../img";
66
import mainConfig from "../default_configs.json";
@@ -274,33 +274,6 @@ function pickRoot(root) {
274274
}
275275
}
276276
277-
function calcMarkerOffsetX(arc, isTitle = false) {
278-
let x = 0;
279-
let offsetX = isTitle ? 16 : 0;
280-
let anchor="middle";
281-
if(arc.center.endX > arc.cx) {
282-
x = arc.center.endX + 16 + offsetX;
283-
anchor = "start";
284-
} else if (arc.center.endX < arc.cx) {
285-
x = arc.center.endX - 16 - offsetX;
286-
anchor = "end";
287-
} else {
288-
x = arc.centerX + offsetX;
289-
anchor = "middle";
290-
}
291-
return {x, anchor}
292-
}
293-
294-
function calcMarkerOffsetY(arc) {
295-
if (arc.center.endY > arc.cy) {
296-
return arc.center.endY + 16;
297-
} else if (arc.center.endY < arc.cy) {
298-
return arc.center.endY - 32;
299-
} else {
300-
return arc.center.endY;
301-
}
302-
}
303-
304277
function placeLegendTopOrBottom() {
305278
const overflowsBottom = drawableArea.value.bottom - (selectedNut.value.y1 + 180) < 0;
306279
if(overflowsBottom) {
@@ -310,20 +283,6 @@ function placeLegendTopOrBottom() {
310283
}
311284
}
312285
313-
function calcNutArrowPath(arc) {
314-
const start = `M${calcMarkerOffsetX(arc).x},${calcMarkerOffsetY(arc) - 4} `;
315-
const end = ` ${arc.center.endX},${arc.center.endY}`;
316-
let mid = "";
317-
if (arc.center.endX > arc.cx) {
318-
mid = `${calcMarkerOffsetX(arc).x - 12},${calcMarkerOffsetY(arc) - 4}`;
319-
} else if(arc.center.endX < arc.cx) {
320-
mid = `${calcMarkerOffsetX(arc).x + 12},${calcMarkerOffsetY(arc) - 4}`;
321-
} else {
322-
mid = `${calcMarkerOffsetX(arc).x + 12},${calcMarkerOffsetY(arc) - 4}`;
323-
}
324-
return `${start}${mid}${end}`;
325-
}
326-
327286
function isArcBigEnough(arc) {
328287
return arc.proportion * 100 > chestnutConfig.value.style.chart.layout.nuts.selected.labels.dataLabels.hideUnderValue;
329288
}

src/components/vue-ui-donut.vue

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script setup>
22
import { ref, computed, nextTick } from "vue";
3-
import { makeDonut, palette, convertColorToHex, opacity, makeXls } from '../lib';
3+
import { calcMarkerOffsetX, calcMarkerOffsetY, calcNutArrowPath, makeDonut, palette, convertColorToHex, opacity, makeXls } from '../lib';
44
import pdf from "../pdf";
55
import img from "../img";
66
import mainConfig from "../default_configs.json";
@@ -314,7 +314,7 @@ defineExpose({
314314

315315
<template>
316316
<div :ref="`donutChart`" :class="`vue-ui-donut ${donutConfig.useCssAnimation ? '' : 'vue-ui-dna'}`" :style="`font-family:${donutConfig.style.fontFamily};width:100%; text-align:center;${donutConfig.userOptions.show ? 'padding-top:36px' : ''}`" :id="`donut__${uid}`">
317-
<div v-if="(!mutableConfig.inside || isPrinting) && donutConfig.style.chart.title.text" :style="`width:100%;background:${donutConfig.style.chart.backgroundColor}`">
317+
<div v-if="(!mutableConfig.inside || isPrinting) && donutConfig.style.chart.title.text" :style="`width:100%;background:${donutConfig.style.chart.backgroundColor};padding-bottom:24px`">
318318
<!-- TITLE AS DIV -->
319319
<Title
320320
:config="{
@@ -391,7 +391,7 @@ defineExpose({
391391
:font-size="donutConfig.style.chart.title.fontSize"
392392
:fill="donutConfig.style.chart.title.color"
393393
:x="svg.width / 2"
394-
:y="48"
394+
:y="24"
395395
text-anchor="middle"
396396
:style="`font-weight:${donutConfig.style.chart.title.bold ? 'bold' : ''}`"
397397
>
@@ -403,13 +403,35 @@ defineExpose({
403403
:font-size="donutConfig.style.chart.title.subtitle.fontSize"
404404
:fill="donutConfig.style.chart.title.subtitle.color"
405405
:x="svg.width / 2"
406-
:y="48 + donutConfig.style.chart.title.fontSize"
406+
:y="24 + donutConfig.style.chart.title.fontSize"
407407
text-anchor="middle"
408408
:style="`font-weight:${donutConfig.style.chart.title.subtitle.bold ? 'bold' : ''}`"
409409
>
410410
{{ donutConfig.style.chart.title.subtitle.text }}
411411
</text>
412412
</g>
413+
414+
<!-- LABEL CONNECTOR -->
415+
<g v-for="(arc, i) in currentDonut">
416+
<path
417+
v-if="isArcBigEnough(arc) && mutableConfig.dataLabels.show"
418+
:d="calcNutArrowPath(arc, {x: svg.width / 2, y: svg.height / 2})"
419+
:stroke="arc.color"
420+
stroke-width="1"
421+
stroke-linecap="round"
422+
stroke-linejoin="round"
423+
fill="none"
424+
:class="!defaultConfig.useBlurOnHover || [null, undefined].includes(selectedSerie) || selectedSerie === i ? '' : 'vue-ui-donut-blur'"
425+
/>
426+
</g>
427+
428+
<path
429+
v-for="(arc, i) in currentDonut"
430+
:stroke="donutConfig.style.chart.backgroundColor"
431+
:d="arc.path"
432+
:stroke-width="defaultConfig.style.chart.layout.donut.strokeWidth"
433+
fill="#FFFFFF"
434+
/>
413435
<path
414436
v-for="(arc, i) in currentDonut"
415437
class="vue-ui-donut-arc-path"
@@ -503,9 +525,22 @@ defineExpose({
503525
<text
504526
:data-cy="`donut-datalabel-value-${i}`"
505527
v-if="isArcBigEnough(arc) && mutableConfig.dataLabels.show"
506-
text-anchor="middle"
507-
:x="calcDonutMarkerLabelPositionX(arc)"
508-
:y="arc.center.endY - donutConfig.style.chart.layout.labels.percentage.fontSize / 2"
528+
:text-anchor="calcMarkerOffsetX(arc, true).anchor"
529+
:x="calcMarkerOffsetX(arc).x"
530+
:y="calcMarkerOffsetY(arc)"
531+
:fill="arc.color"
532+
:font-size="donutConfig.style.chart.layout.labels.percentage.fontSize * 0.8"
533+
font-family="Arial"
534+
:class="!defaultConfig.useBlurOnHover || [null, undefined].includes(selectedSerie) || selectedSerie === i ? '' : 'vue-ui-donut-blur'"
535+
>
536+
537+
</text>
538+
<text
539+
:data-cy="`donut-datalabel-value-${i}`"
540+
v-if="isArcBigEnough(arc) && mutableConfig.dataLabels.show"
541+
:text-anchor="calcMarkerOffsetX(arc, true, 20).anchor"
542+
:x="calcMarkerOffsetX(arc, true, 20).x"
543+
:y="calcMarkerOffsetY(arc)"
509544
:fill="donutConfig.style.chart.layout.labels.percentage.color"
510545
:font-size="donutConfig.style.chart.layout.labels.percentage.fontSize"
511546
:style="`font-weight:${donutConfig.style.chart.layout.labels.percentage.bold ? 'bold': ''}`"
@@ -514,10 +549,10 @@ defineExpose({
514549
</text>
515550
<text
516551
:data-cy="`donut-datalabel-name-${i}`"
517-
v-if="isArcBigEnough(arc) && mutableConfig.dataLabels.show"
518-
text-anchor="middle"
519-
:x="calcDonutMarkerLabelPositionX(arc)"
520-
:y="arc.center.endY + donutConfig.style.chart.layout.labels.percentage.fontSize / 2"
552+
v-if="isArcBigEnough(arc, true, 20) && mutableConfig.dataLabels.show"
553+
:text-anchor="calcMarkerOffsetX(arc).anchor"
554+
:x="calcMarkerOffsetX(arc, true, 20).x"
555+
:y="calcMarkerOffsetY(arc) + donutConfig.style.chart.layout.labels.percentage.fontSize"
521556
:fill="donutConfig.style.chart.layout.labels.name.color"
522557
:font-size="donutConfig.style.chart.layout.labels.name.fontSize"
523558
:style="`font-weight:${donutConfig.style.chart.layout.labels.name.bold ? 'bold': ''}`"

src/lib.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,10 +627,54 @@ export function createUid() {
627627
});
628628
}
629629

630+
export function calcMarkerOffsetX(arc, isTitle = false, offset = 16) {
631+
let x = 0;
632+
let offsetX = isTitle ? offset : 0;
633+
let anchor="middle";
634+
if(arc.center.endX > arc.cx) {
635+
x = arc.center.endX + offset + offsetX;
636+
anchor = "start";
637+
} else if (arc.center.endX < arc.cx) {
638+
x = arc.center.endX - offset - offsetX;
639+
anchor = "end";
640+
} else {
641+
x = arc.centerX + offsetX;
642+
anchor = "middle";
643+
}
644+
return {x, anchor}
645+
}
646+
647+
export function calcMarkerOffsetY(arc) {
648+
if (arc.center.endY > arc.cy) {
649+
return arc.center.endY + 16;
650+
} else if (arc.center.endY < arc.cy) {
651+
return arc.center.endY - 32;
652+
} else {
653+
return arc.center.endY;
654+
}
655+
}
656+
657+
export function calcNutArrowPath(arc, center=false) {
658+
const start = `M${calcMarkerOffsetX(arc).x},${calcMarkerOffsetY(arc) - 4} `;
659+
const end = ` ${center? center.x : arc.center.endX},${center ? center.y : arc.center.endY}`;
660+
let mid = "";
661+
if (arc.center.endX > arc.cx) {
662+
mid = `${calcMarkerOffsetX(arc).x - 12},${calcMarkerOffsetY(arc) - 4}`;
663+
} else if(arc.center.endX < arc.cx) {
664+
mid = `${calcMarkerOffsetX(arc).x + 12},${calcMarkerOffsetY(arc) - 4}`;
665+
} else {
666+
mid = `${calcMarkerOffsetX(arc).x + 12},${calcMarkerOffsetY(arc) - 4}`;
667+
}
668+
return `${start}${mid}${end}`;
669+
}
670+
630671
const lib = {
631672
adaptColorToBackground,
632673
addVector,
633674
calcLinearProgression,
675+
calcMarkerOffsetX,
676+
calcMarkerOffsetY,
677+
calcNutArrowPath,
634678
calcMedian,
635679
checkArray,
636680
checkNaN,

0 commit comments

Comments
 (0)