Skip to content

Commit c17bfcf

Browse files
committed
Improvement - VueUiDonut - Various fixes and improvements
1 parent ad31950 commit c17bfcf

File tree

7 files changed

+102
-86
lines changed

7 files changed

+102
-86
lines changed

TestingArena/ArenaVueUiDonut.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ const model = ref([
162162
{ key: 'style.chart.layout.donut.borderWidth', def: 1, type: 'range', min: 0, max: 36, label: ['border', 'is', 'thickness'], category: 'donut' },
163163
{ key: 'style.chart.layout.donut.useShadow', def: true, type: 'checkbox' },
164164
{ key: 'style.chart.layout.donut.shadowColor', def: '#1A1A1A', type: 'color' },
165+
{ key: 'style.chart.layout.donut.selectedColor', def: '#0000001A', type: 'color'},
166+
165167
{ key: 'style.chart.legend.show', def: true, type: 'checkbox', label: 'show', category: 'legend' },
166168
{ key: 'style.chart.legend.backgroundColor', def: '#FFFFFF20', type: 'color', label: 'backgroundColor', category: 'legend' },
167169
{ key: 'style.chart.legend.color', def: '#1A1A1A', type: 'color', label: 'textColor', category: 'legend' },

src/atoms/Legend.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function handleClick(legend, i) {
4141
:style="`background:${config.backgroundColor};font-size:${config.fontSize}px;color:${config.color};padding-bottom:${config.paddingBottom}px;padding-top:${config.paddingTop || 12}px;font-weight:${config.fontWeight}`"
4242
>
4343
<slot name="legendTitle" :titleSet="legendSet"></slot>
44-
<div v-for="(legend, i) in legendSet" :class="{ 'vue-data-ui-legend-item': true, 'active': clickable }">
44+
<div v-for="(legend, i) in legendSet" :key="`legend_${i}`" :class="{ 'vue-data-ui-legend-item': true, 'active': clickable }">
4545
<svg @click="handleClick(legend, i)" v-if="legend.shape" :height="config.fontSize" :width="config.fontSize" viewBox="0 0 60 60" :style="`overflow: visible;opacity:${legend.opacity}`">
4646
<Shape
4747
:shape="legend.shape"

src/components/vue-ui-donut.vue

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,16 @@ function prepareChart() {
120120
})
121121
})
122122
})
123+
props.dataset.forEach((ds, i) => {
124+
if (!ds.name || ds.name === '') {
125+
error({
126+
componentName: 'VueUiDonut',
127+
type: 'datasetAttributeEmpty',
128+
property: 'name',
129+
index: i
130+
})
131+
}
132+
})
123133
}
124134
125135
if (FINAL_CONFIG.value.responsive) {
@@ -648,7 +658,6 @@ function handleDatapointLeave({ datapoint, seriesIndex }) {
648658
}
649659
650660
function useTooltip({ datapoint, relativeIndex, seriesIndex, show = false }) {
651-
console.log(datapoint)
652661
if (FINAL_CONFIG.value.events.datapointEnter) {
653662
FINAL_CONFIG.value.events.datapointEnter({ datapoint, seriesIndex });
654663
}
@@ -1172,7 +1181,7 @@ defineExpose({
11721181
<g v-if="currentDonut.length > 1 || FINAL_CONFIG.type === 'classic'">
11731182
<path data-cy="tooltip-trap" v-for="(arc, i) in currentDonut.filter(el => !el.ghost)"
11741183
:d="FINAL_CONFIG.type === 'classic' ? arc.arcSlice : polarAreas[i].path"
1175-
:fill="selectedSerie === i ? 'rgba(0,0,0,0.1)' : 'transparent'" @mouseenter="useTooltip({
1184+
:fill="selectedSerie === i ? FINAL_CONFIG.style.chart.layout.donut.selectedColor : 'transparent'" @mouseenter="useTooltip({
11761185
datapoint: arc,
11771186
relativeIndex: i,
11781187
seriesIndex: arc.seriesIndex,

src/lib.js

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,36 @@
11
import errors from "./errors.json";
22

3-
export function makeDonut(item, cx, cy, rx, ry, piProportion = 1.99999, piMult = 2, arcAmpl = 1.45, degrees = 360, rotation = 105.25, size = 0) {
4-
let { series } = item;
5-
if (!series || item.base === 0)
6-
return {
7-
...series,
8-
proportion: 0,
9-
ratio: 0,
10-
path: "",
11-
startX: 0,
12-
startY: 0,
13-
endX: 0,
14-
center: {},
15-
};
16-
const sum = [...series]
17-
.map((serie) => {
18-
return serie.value
19-
})
20-
.reduce((a, b) => a + b, 0);
3+
export function makeDonut(
4+
item,
5+
cx,
6+
cy,
7+
rx,
8+
ry,
9+
piProportion = 1.99999,
10+
piMult = 2,
11+
arcAmpl = 1.45,
12+
degrees = 360,
13+
rotation = 105.25,
14+
size = 0
15+
) {
16+
const { series } = item;
17+
if (!series || series.length === 0) {
18+
return [];
19+
}
20+
21+
const sum = series.reduce((total, s) => total + s.value, 0);
2122

2223
const ratios = [];
2324
let acc = 0;
24-
for (let i = 0; i < series.length; i += 1) {
25-
const val = Math.min(series[i].value - 0.0001, sum);
26-
let proportion = val / sum;
27-
const ratio = proportion * (Math.PI * piProportion); // (Math.PI * 2) fails to display a donut with only one value > 0 as it goes full circle again
28-
// midProportion & midRatio are used to find the midpoint of the arc to display markers
29-
const midProportion = val / 2 / sum;
25+
26+
for (let i = 0; i < series.length; i++) {
27+
const rawVal = series[i].value;
28+
const isSingle = series.length === 1;
29+
30+
// Force 360° when single datapoint
31+
const proportion = isSingle ? 1 : sum > 0 ? rawVal / sum : 0;
32+
const ratio = proportion * (Math.PI * piProportion);
33+
const midProportion = isSingle ? 0.5 : sum > 0 ? (rawVal / 2) / sum : 0.5;
3034
const midRatio = midProportion * (Math.PI * piMult);
3135
const { startX, startY, endX, endY, path } = createArc(
3236
[cx, cy],
@@ -36,7 +40,6 @@ export function makeDonut(item, cx, cy, rx, ry, piProportion = 1.99999, piMult =
3640
degrees,
3741
piMult
3842
);
39-
4043
const inner = createArc(
4144
[cx, cy],
4245
[rx - size, ry - size],
@@ -46,15 +49,22 @@ export function makeDonut(item, cx, cy, rx, ry, piProportion = 1.99999, piMult =
4649
piMult,
4750
true
4851
);
49-
52+
const center = createArc(
53+
[cx, cy],
54+
[rx * arcAmpl, ry * arcAmpl],
55+
[acc, midRatio],
56+
rotation,
57+
degrees,
58+
piMult
59+
);
5060
ratios.push({
5161
arcSlice: `${path} L ${inner.startX} ${inner.startY} ${inner.path} L ${startX} ${startY}`,
5262
cx: checkNaN(cx),
5363
cy: checkNaN(cy),
5464
...series[i],
5565
proportion: checkNaN(proportion),
5666
ratio: checkNaN(ratio),
57-
path: path.replaceAll('NaN', '0'),
67+
path: path.replaceAll("NaN", "0"),
5868
startX: checkNaN(startX),
5969
startY: checkNaN(startY),
6070
endX: checkNaN(endX),
@@ -64,17 +74,10 @@ export function makeDonut(item, cx, cy, rx, ry, piProportion = 1.99999, piMult =
6474
y: inner.startY,
6575
},
6676
firstSeparator: {
67-
x: Number(inner.path.split(' ').at(-2)),
68-
y: Number(inner.path.split(' ').at(-1))
77+
x: Number(inner.path.split(" ").at(-2)),
78+
y: Number(inner.path.split(" ").at(-1)),
6979
},
70-
center: createArc(
71-
[cx, cy],
72-
[rx * arcAmpl, ry * arcAmpl],
73-
[acc, midRatio],
74-
rotation,
75-
degrees,
76-
piMult
77-
), // center of the arc, to display the marker. rx & ry are larger to be displayed with a slight offset
80+
center,
7881
});
7982
acc += ratio;
8083
}

src/useConfig.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,8 @@ export function useConfig() {
828828
borderWidth: 1,
829829
useShadow: false,
830830
shadowColor: COLOR_BLACK,
831-
emptyFill: COLOR_GREY_LIGHT
831+
emptyFill: COLOR_GREY_LIGHT,
832+
selectedColor: '#0000001A'
832833
}
833834
},
834835
comments: {

tests/lib.test.js

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -500,89 +500,89 @@ describe("makeDonut", () => {
500500
expect(donut).toStrictEqual([
501501
{
502502
arcSlice:
503-
"M100.06646055814842 90.00022085272826 A 10 10 6030.380793751915 0 1 108.69274956498154 95.0567111150052 L 108.69274956498154 95.0567111150052 M108.69274956498154 95.0567111150052 A 10 10 6030.380793751915 0 0 100.06646055814842 90.00022085272826 L 100.06646055814842 90.00022085272826",
503+
"M100.06646055814842 90.00022085272826 A 10 10 6030.380793751915 0 1 108.69326717473096 95.05762144016212 L 108.69326717473096 95.05762144016212 M108.69326717473096 95.05762144016212 A 10 10 6030.380793751915 0 0 100.06646055814842 90.00022085272826 L 100.06646055814842 90.00022085272826",
504504
cx: 100,
505505
cy: 100,
506506
value: 1,
507-
proportion: 0.16665,
508-
ratio: 1.0470875959773207,
509-
path: "M100.06646055814842 90.00022085272826 A 10 10 6030.380793751915 0 1 108.69274956498154 95.0567111150052",
507+
proportion: 0.16666666666666666,
508+
ratio: 1.0471923152088416,
509+
path: "M100.06646055814842 90.00022085272826 A 10 10 6030.380793751915 0 1 108.69326717473096 95.05762144016212",
510510
startX: 100.06646055814842,
511511
startY: 90.00022085272826,
512-
endX: 108.69274956498154,
513-
endY: 95.0567111150052,
512+
endX: 108.69326717473096,
513+
endY: 95.05762144016212,
514514
firstSeparator: {
515515
x: 100.06646055814842,
516516
y: 90.00022085272826,
517517
},
518518
separator: {
519-
x: 108.69274956498154,
520-
y: 95.0567111150052,
519+
x: 108.69326717473096,
520+
y: 95.05762144016212,
521521
},
522522
center: {
523523
startX: 100.09636780931521,
524524
startY: 85.50032023645599,
525-
endX: 107.33264187784894,
526-
endY: 87.49070892931114,
527-
path: "M100.09636780931521 85.50032023645599 A 14.5 14.5 6030.380793751915 0 1 107.33264187784894 87.49070892931114",
525+
endX: 107.33329685274603,
526+
endY: 87.49109288268934,
527+
path: "M100.09636780931521 85.50032023645599 A 14.5 14.5 6030.380793751915 0 1 107.33329685274603 87.49109288268934",
528528
},
529529
},
530530
{
531531
arcSlice:
532-
"M108.69274956498154 95.0567111150052 A 10 10 6030.380793751915 0 1 99.93579085805592 109.9997938571798 L 99.93579085805592 109.9997938571798 M99.93579085805592 109.9997938571798 A 10 10 6030.380793751915 0 0 108.69274956498154 95.0567111150052 L 108.69274956498154 95.0567111150052",
532+
"M108.69326717473096 95.05762144016212 A 10 10 6030.380793751915 0 1 99.93369651802331 109.99978018999806 L 99.93369651802331 109.99978018999806 M99.93369651802331 109.99978018999806 A 10 10 6030.380793751915 0 0 108.69326717473096 95.05762144016212 L 108.69326717473096 95.05762144016212",
533533
cx: 100,
534534
cy: 100,
535535
value: 2,
536-
proportion: 0.33331666666666665,
537-
ratio: 2.0942799111861623,
538-
path: "M108.69274956498154 95.0567111150052 A 10 10 6030.380793751915 0 1 99.93579085805592 109.9997938571798",
539-
startX: 108.69274956498154,
540-
startY: 95.0567111150052,
541-
endX: 99.93579085805592,
542-
endY: 109.9997938571798,
536+
proportion: 0.3333333333333333,
537+
ratio: 2.094384630417683,
538+
path: "M108.69326717473096 95.05762144016212 A 10 10 6030.380793751915 0 1 99.93369651802331 109.99978018999806",
539+
startX: 108.69326717473096,
540+
startY: 95.05762144016212,
541+
endX: 99.93369651802331,
542+
endY: 109.99978018999806,
543543
firstSeparator: {
544-
x: 108.69274956498154,
545-
y: 95.0567111150052
544+
x: 108.69326717473096,
545+
y: 95.05762144016212
546546
},
547547
separator: {
548-
x: 99.93579085805592,
549-
y: 109.9997938571798,
548+
x: 99.93369651802331,
549+
y: 109.99978018999806,
550550
},
551551
center: {
552-
startX: 112.60448686922324,
553-
startY: 92.83223111675754,
554-
endX: 112.51009725731319,
555-
endY: 107.33126637168266,
556-
path: "M112.60448686922324 92.83223111675754 A 14.5 14.5 6030.380793751915 0 1 112.51009725731319 107.33126637168266",
552+
startX: 112.6052374033599,
553+
startY: 92.83355108823508,
554+
endX: 112.50894551419171,
555+
endY: 107.33323135616101,
556+
path: "M112.6052374033599 92.83355108823508 A 14.5 14.5 6030.380793751915 0 1 112.50894551419171 107.33323135616101",
557557
},
558558
},
559559
{
560560
arcSlice:
561-
"M99.93579085805592 109.9997938571798 A 10 10 6030.380793751915 0 1 100.06300489435868 90.00019848280543 L 100.06300489435868 90.00019848280543 M100.06300489435868 90.00019848280543 A 10 10 6030.380793751915 0 0 99.93579085805592 109.9997938571798 L 99.93579085805592 109.9997938571798",
561+
"M99.93369651802331 109.99978018999806 A 10 10 6030.380793751915 0 1 100.06614640578861 90.00021876974294 L 100.06614640578861 90.00021876974294 M100.06614640578861 90.00021876974294 A 10 10 6030.380793751915 0 0 99.93369651802331 109.99978018999806 L 99.93369651802331 109.99978018999806",
562562
cx: 100,
563563
cy: 100,
564564
value: 3,
565-
proportion: 0.4999833333333333,
566-
ratio: 3.141472226395004,
567-
path: "M99.93579085805592 109.9997938571798 A 10 10 6030.380793751915 0 1 100.06300489435868 90.00019848280543",
568-
startX: 99.93579085805592,
569-
startY: 109.9997938571798,
570-
endX: 100.06300489435868,
571-
endY: 90.00019848280543,
565+
proportion: 0.5,
566+
ratio: 3.1415769456265252,
567+
path: "M99.93369651802331 109.99978018999806 A 10 10 6030.380793751915 0 1 100.06614640578861 90.00021876974294",
568+
startX: 99.93369651802331,
569+
startY: 109.99978018999806,
570+
endX: 100.06614640578861,
571+
endY: 90.00021876974294,
572572
firstSeparator: {
573-
x: 99.93579085805592,
574-
y: 109.9997938571798
573+
x: 99.93369651802331,
574+
y: 109.99978018999806
575575
},
576576
separator: {
577-
x: 100.06300489435868,
578-
y: 90.00019848280543,
577+
x: 100.06614640578861,
578+
y: 90.00021876974294,
579579
},
580580
center: {
581-
startX: 99.9068967441811,
582-
startY: 114.4997010929107,
583-
endX: 85.5002940520901,
584-
endY: 99.90765594688226,
585-
path: "M99.9068967441811 114.4997010929107 A 14.5 14.5 6030.380793751915 0 1 85.5002940520901 99.90765594688226",
581+
startX: 99.9038599511338,
582+
startY: 114.4996812754972,
583+
endX: 85.5003187245028,
584+
endY: 99.9038599511338,
585+
path: "M99.9038599511338 114.4996812754972 A 14.5 14.5 6030.380793751915 0 1 85.5003187245028 99.9038599511338",
586586
},
587587
},
588588
]);

types/vue-data-ui.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3392,6 +3392,7 @@ declare module "vue-data-ui" {
33923392
useShadow?: boolean;
33933393
shadowColor?: string;
33943394
emptyFill?: string;
3395+
selectedColor?: string;
33953396
};
33963397
};
33973398
comments?: ChartComments;

0 commit comments

Comments
 (0)