@@ -95,15 +95,6 @@ const svg = computed(() => {
9595
9696const emit = defineEmits ([' selectLegend' , ' selectDatapoint' ]);
9797
98- function segregate (legend ) {
99- if (segregated .value .includes (legend .id )) {
100- segregated .value = segregated .value .filter (s => s !== legend .id )
101- } else {
102- segregated .value .push (legend .id )
103- }
104- emit (' selectLegend' , legend)
105- }
106-
10798function selectDatapoint ({ datapoint, index }) {
10899 emit (' selectDatapoint' , { datapoint, index })
109100}
@@ -180,11 +171,11 @@ const immutableDataset = computed(() => {
180171 })
181172 }
182173 })
183- })
174+ });
184175
185176const donutSize = computed (() => donutConfig .value .style .chart .layout .donut .strokeWidth )
186177
187- const mutableDataset = computed (() => {
178+ const md = computed (() => {
188179 return [... immutableDataset .value ].map ((ds , i ) => {
189180 const sizeRatio = i * donutSize .value / immutableDataset .value .length ;
190181
@@ -201,8 +192,125 @@ const mutableDataset = computed(() => {
201192 proportion: s .value / total
202193 }
203194 }),
195+ }
196+ })
197+ });
198+
199+ function checkSegregation (sourceArray , n , targetArray ) {
200+ let count = 0 ;
201+ for (let i = 0 ; i < sourceArray .length ; i += 1 ) {
202+ if (targetArray .includes (sourceArray[i])) {
203+ count += 1 ;
204+ }
205+ }
206+ return count < n;
207+ }
208+
209+ const mutableDataset = ref (md .value );
210+ const rafUp = ref (null );
211+ const rafDown = ref (null );
212+
213+ function segregateDonut (item ) {
214+ emit (' selectLegend' , item);
215+ const target = immutableDataset .value .flatMap (d => d .series ).find (el => el .id === item .id );
216+ const source = mutableDataset .value .flatMap (d => d .series ).find (el => el .id === item .id ).value ;
217+ let initVal = source;
218+
219+ const allParentDonutIds = immutableDataset .value .find (el => el .id === target .arcOfId ).series .map (s => s .id );
220+ const canSegregate = checkSegregation (allParentDonutIds, allParentDonutIds .length - 1 , segregated .value );
221+
222+ if (segregated .value .includes (item .id )) {
223+ segregated .value = segregated .value .filter (s => s !== item .id );
224+ function animUp () {
225+ if (initVal > target .value ) {
226+ cancelAnimationFrame (animUp);
227+ mutableDataset .value = mutableDataset .value .map (ds => {
228+ return {
229+ ... ds,
230+ series: ds .series .map (s => {
231+ if (s .id == item .id ) {
232+ return {
233+ ... s,
234+ value: target .value
235+ }
236+ } else {
237+ return s;
238+ }
239+ })
240+ }
241+ });
242+ } else {
243+ initVal += (target .value * 0.025 );
244+ mutableDataset .value = mutableDataset .value .map (ds => {
245+ return {
246+ ... ds,
247+ series: ds .series .map (s => {
248+ if (s .id === item .id ) {
249+ return {
250+ ... s,
251+ value: initVal
252+ }
253+ } else {
254+ return s;
255+ }
256+ })
257+ }
258+ });
259+ rafUp .value = requestAnimationFrame (animUp);
260+ }
261+ }
262+ animUp ();
263+ } else if (canSegregate) {
264+ function animDown () {
265+ if (initVal < 0.1 ) {
266+ cancelAnimationFrame (animDown);
267+ segregated .value .push (item .id );
268+ mutableDataset .value = mutableDataset .value .map ((ds , i ) => {
269+ return {
270+ ... ds,
271+ series: ds .series .map (s => {
272+ if (s .id === item .id ) {
273+ return {
274+ ... s,
275+ value: 0
276+ }
277+ } else {
278+ return s
279+ }
280+ })
281+ }
282+ });
283+ } else {
284+ initVal /= 1.1 ;
285+ mutableDataset .value = mutableDataset .value .map ((ds , i ) => {
286+ return {
287+ ... ds,
288+ series: ds .series .map (s => {
289+ if (s .id === item .id ) {
290+ return {
291+ ... s,
292+ value: initVal
293+ }
294+ } else {
295+ return s
296+ }
297+ })
298+ }
299+ });
300+ rafDown .value = requestAnimationFrame (animDown);
301+ }
302+ }
303+ animDown ();
304+ }
305+ }
306+
307+ const donuts = computed (() => {
308+ return mutableDataset .value .map ((ds , i ) => {
309+ const sizeRatio = i * donutSize .value / immutableDataset .value .length ;
310+ return {
311+ ... ds,
204312 donut: makeDonut (
205- { series: ds .series . filter ( serie => ! segregated . value . includes ( serie . id )) },
313+ { series: ds .series },
206314 svg .value .width / 2 ,
207315 svg .value .height / 2 ,
208316 donutSize .value - sizeRatio,
@@ -216,7 +324,7 @@ const mutableDataset = computed(() => {
216324 )
217325 }
218326 })
219- })
327+ });
220328
221329const gradientSets = computed (() => {
222330 return [... immutableDataset .value ].map ((ds , i ) => {
@@ -239,7 +347,7 @@ const gradientSets = computed(() => {
239347 )[0 ]
240348 }
241349 })
242- })
350+ });
243351
244352const selectedDonut = ref (null );
245353const selectedDatapoint = ref (null );
@@ -366,7 +474,7 @@ const legendSets = computed(() => {
366474 return {
367475 ...s,
368476 opacity: segregated.value.includes(s.id) ? 0.5 : 1,
369- segregate: () => segregate (s),
477+ segregate: () => segregateDonut (s),
370478 isSegregated: segregated.value.includes(s.id)
371479 }
372480 })
@@ -557,7 +665,7 @@ defineExpose({
557665
558666 <svg :xmlns="XMLNS" v-if="isDataset" :class="{ 'vue-data-ui-fullscreen--on': isFullscreen, 'vue-data-ui-fulscreen--off': !isFullscreen }" :viewBox="` 0 0 ${svg .width } ${svg .height }` " :style="` max- width: 100 % ; overflow: visible; background: ${donutConfig .style .chart .backgroundColor };color: ${donutConfig .style .chart .color }` ">
559667 <!-- NESTED DONUTS -->
560- <g v-for="(item, i) in mutableDataset ">
668+ <g v-for="(item, i) in donuts ">
561669 <g v-for="(arc, j) in item.donut">
562670 <path
563671 class="vue-ui-donut-arc-path"
@@ -598,9 +706,10 @@ defineExpose({
598706 </g>
599707
600708 <g v-if="donutConfig.style.chart.layout.labels.dataLabels.showDonutName">
601- <g v-for="(item, i) in mutableDataset ">
709+ <g v-for="(item, i) in donuts ">
602710 <g v-for="(arc, j) in item.donut">
603711 <text
712+ :class="{ 'animated': donutConfig.useCssAnimation }"
604713 v-if="j === 0"
605714 :x="svg.width / 2"
606715 :y="arc.startY - donutConfig.style.chart.layout.labels.dataLabels.fontSize + donutConfig.style.chart.layout.labels.dataLabels.donutNameOffsetY"
@@ -617,9 +726,10 @@ defineExpose({
617726
618727 <!-- DATALABELS -->
619728 <g v-if="donutConfig.style.chart.layout.labels.dataLabels.show">
620- <g v-for="(item, i) in mutableDataset ">
729+ <g v-for="(item, i) in donuts ">
621730 <g v-for="(arc, j) in item.donut" :filter="getBlurFilter(arc, j)">
622731 <text
732+ :class="{ 'animated': donutConfig.useCssAnimation }"
623733 v-if="isArcBigEnough(arc) && mutableConfig.dataLabels.show && donutConfig.style.chart.layout.labels.dataLabels.showPercentage"
624734 :text-anchor="calcMarkerOffsetX(arc, true).anchor"
625735 :x="calcMarkerOffsetX(arc, false, donutConfig.style.chart.layout.labels.dataLabels.offsetX).x"
@@ -631,6 +741,7 @@ defineExpose({
631741 {{ dataLabel({ v: arc.proportion * 100, s: '%', r: donutConfig.style.chart.layout.labels.dataLabels.roundingPercentage }) }}
632742 </text>
633743 <text
744+ :class="{ 'animated': donutConfig.useCssAnimation }"
634745 v-if="isArcBigEnough(arc) && mutableConfig.dataLabels.show && donutConfig.style.chart.layout.labels.dataLabels.showPercentage && donutConfig.style.chart.layout.labels.dataLabels.showValue"
635746 :text-anchor="calcMarkerOffsetX(arc, true).anchor"
636747 :x="calcMarkerOffsetX(arc, false, donutConfig.style.chart.layout.labels.dataLabels.offsetX).x"
@@ -642,6 +753,7 @@ defineExpose({
642753 ({{ dataLabel({ p: donutConfig.style.chart.layout.labels.dataLabels.prefix, v: arc.value, s: donutConfig.style.chart.layout.labels.dataLabels.suffix, r: donutConfig.style.chart.layout.labels.dataLabels.roundingValue }) }})
643754 </text>
644755 <text
756+ :class="{ 'animated': donutConfig.useCssAnimation }"
645757 v-if="isArcBigEnough(arc) && mutableConfig.dataLabels.show && !donutConfig.style.chart.layout.labels.dataLabels.showPercentage && donutConfig.style.chart.layout.labels.dataLabels.showValue"
646758 :text-anchor="calcMarkerOffsetX(arc, true).anchor"
647759 :x="calcMarkerOffsetX(arc, false, donutConfig.style.chart.layout.labels.dataLabels.offsetX).x"
@@ -657,7 +769,7 @@ defineExpose({
657769 </g>
658770
659771 <!-- TOOLTIP TRAPS -->
660- <g v-for="(item, i) in mutableDataset ">
772+ <g v-for="(item, i) in donuts ">
661773 <g v-for="(arc, j) in item.donut">
662774 <path
663775 data-cy-donut-trap
@@ -712,15 +824,15 @@ defineExpose({
712824 v-for="legendSet in legendSets"
713825 :legendSet="legendSet"
714826 :config="legendConfig"
715- @clickMarker="({ legend, index }) => segregate (legend, index )"
827+ @clickMarker="({ legend }) => segregateDonut (legend)"
716828 >
717829 <template #legendTitle="{ titleSet }">
718830 <div class="vue-ui-nested-donuts-legend-title" v-if="titleSet[0].arcOf">
719831 {{ titleSet[0].arcOf }}
720832 </div>
721833 </template>
722834 <template #item="{ legend, index }">
723- <div :data-cy="` legend- item- ${index}` " @click="segregate (legend, index )" :style="` opacity: ${segregated .includes (legend .id ) ? 0.5 : 1 }` ">
835+ <div :data-cy="` legend- item- ${index}` " @click="segregateDonut (legend)" :style="` opacity: ${segregated .includes (legend .id ) ? 0.5 : 1 }` ">
724836 {{ legend.name }} : {{ dataLabel({p: donutConfig.style.chart.layout.labels.dataLabels.prefix, v: legend.value, s: donutConfig.style.chart.layout.labels.dataLabels.suffix, r: donutConfig.style.chart.legend.roundingValue}) }}
725837 <template v-if="!segregated.includes(legend.id)">
726838 ({{ isNaN(legend.value / legend.total) ? '-' : dataLabel({ v: legend.value / legend.total * 100, s: '%', r: donutConfig.style.chart.legend.roundingPercentage }) }})
@@ -765,7 +877,7 @@ defineExpose({
765877 position: relative;
766878}
767879
768- path {
880+ .animated {
769881 animation: donut 0.5s ease-in-out;
770882 transform-origin: center;
771883}
0 commit comments