@@ -13,6 +13,7 @@ import {
1313 createCsvContent ,
1414 createUid ,
1515 dataLabel ,
16+ deepEmptyObjectToNull ,
1617 downloadCsv ,
1718 error ,
1819 getMissingDatasetAttributes ,
@@ -41,6 +42,8 @@ import PackageVersion from "../atoms/PackageVersion.vue";
4142import PenAndPaper from " ../atoms/PenAndPaper.vue" ;
4243import { useUserOptionState } from " ../useUserOptionState" ;
4344import { useChartAccessibility } from " ../useChartAccessibility" ;
45+ import BaseDraggableDialog from " ../atoms/BaseDraggableDialog.vue" ;
46+ import VueUiDonut from " ./vue-ui-donut.vue" ;
4447
4548const { vue_ui_donut_evolution: DEFAULT_CONFIG } = useConfig ();
4649
@@ -422,36 +425,29 @@ function displayArcPercentage(arc, stepBreakdown) {
422425}
423426
424427function leave () {
425- if (isFixed .value ) return ;
426428 hoveredIndex .value = null ;
427429 hoveredDatapoint .value = null ;
428430}
429431
430432function enter (datapoint ) {
431- if (isFixed .value ) return ;
432433 hoveredIndex .value = datapoint .index ;
433434 hoveredDatapoint .value = datapoint;
434435}
435436
436437const fixedDatapointIndex = ref (null );
437438
438439function fixDatapoint (datapoint , index ) {
439- if (! datapoint .subtotal ) return ;
440+ if (! datapoint .subtotal || ! FINAL_CONFIG . value . style . chart . dialog . show ) return ;
440441 hoveredDatapoint .value = null ;
441442 hoveredIndex .value = null ;
442443 isFixed .value = true ;
443444 fixedDatapoint .value = datapoint;
445+ createDonutDatasetForDialog (datapoint);
444446 if (! [null , undefined ].includes (index)) {
445447 fixedDatapointIndex .value = index;
446448 }
447449}
448450
449- function unfixDatapoint () {
450- fixedDatapoint .value = null ;
451- isFixed .value = false ;
452- fixedDatapointIndex .value = null ;
453- }
454-
455451const legendSet = computed (() => {
456452 return convertedDataset .value
457453 .map ((serie , i ) => {
@@ -582,8 +578,27 @@ function toggleAnnotator() {
582578function isArcBigEnoughHover (arc ) {
583579 return arc .proportion * 100 > FINAL_CONFIG .value .style .chart .donuts .hover .hideLabelsUnderValue ;
584580}
585- function isArcBigEnoughZoom (arc ) {
586- return arc .proportion * 100 > FINAL_CONFIG .value .style .chart .donuts .zoom .hideLabelsUnderValue ;
581+
582+ const donutDataset = ref ([]);
583+ const donutConfig = ref ({});
584+ const dialog = ref (null );
585+
586+ function createDonutDatasetForDialog (ds ) {
587+ donutDataset .value = ds .donut .map (ds => {
588+ return {
589+ name: ds .name ,
590+ values: [ds .value ],
591+ color: ds .color
592+ }
593+ });
594+
595+ donutConfig .value = deepEmptyObjectToNull ({
596+ ... FINAL_CONFIG .value .style .chart .dialog .donutChart ,
597+ responsive: true ,
598+ theme: FINAL_CONFIG .value .theme ,
599+ });
600+
601+ dialog .value && dialog .value .open ();
587602}
588603
589604defineExpose ({
@@ -692,7 +707,7 @@ defineExpose({
692707 : class = " { 'vue-data-ui-fullscreen--on': isFullscreen, 'vue-data-ui-fulscreen--off': !isFullscreen }"
693708 data- cy= " donut-evolution-svg"
694709 : viewBox= " `0 0 ${svg.absoluteWidth} ${svg.absoluteHeight}`"
695- : style= " `max-width:100%; overflow: visible; background:transparent;color:${FINAL_CONFIG.style.chart.color}`"
710+ : style= " `max-width:100%; overflow: visible; background:transparent;color:${FINAL_CONFIG.style.chart.color}; `"
696711 >
697712 < PackageVersion / >
698713
@@ -764,7 +779,7 @@ defineExpose({
764779 < / g>
765780
766781 <!-- Y LABELS -->
767- < g v- if = " FINAL_CONFIG.style.chart.layout.grid.yAxis.dataLabels.show" : class = " {'donut-opacity': true, 'donut-behind': hoveredIndex !== null || isFixed }" >
782+ < g v- if = " FINAL_CONFIG.style.chart.layout.grid.yAxis.dataLabels.show" : class = " {'donut-opacity': true, 'donut-behind': hoveredIndex !== null}" >
768783 < g v- for = " (yLabel, i) in yLabels" >
769784 < line
770785 data- cy= " axis-y-tick"
@@ -803,7 +818,7 @@ defineExpose({
803818 < / g>
804819
805820 <!-- X LABELS -->
806- < g v- if = " FINAL_CONFIG.style.chart.layout.grid.xAxis.dataLabels.show" : class = " {'donut-opacity': true, 'donut-behind': isFixed }" >
821+ < g v- if = " FINAL_CONFIG.style.chart.layout.grid.xAxis.dataLabels.show" : class = " {'donut-opacity': true,}" >
807822 < g v- for = " (_, i) in (slicer.end - slicer.start)" >
808823 < text
809824 data- cy= " axis-x-label"
@@ -822,7 +837,7 @@ defineExpose({
822837 <!-- DATAPOINTS -->
823838 < g v- for = " (datapoint, i ) in drawableDataset" >
824839 < line
825- : class = " {'donut-opacity': true, 'donut-behind': hoveredIndex !== null || isFixed }"
840+ : class = " {'donut-opacity': true, 'donut-behind': hoveredIndex !== null}"
826841 v- if = " FINAL_CONFIG.style.chart.layout.line.show && i < drawableDataset.length - 1 && ![datapoint.subtotal, drawableDataset[i + 1].subtotal].includes(null)"
827842 : x1= " datapoint.x"
828843 : y1= " datapoint.y"
@@ -844,7 +859,7 @@ defineExpose({
844859 < / g>
845860 < / g>
846861
847- < g v- for = " (datapoint, i ) in drawableDataset" : data- cy= " `donut-wrapper-${i}`" : class = " {'donut-opacity': true, 'donut-behind': (i !== hoveredIndex && hoveredIndex !== null) || isFixed }" >
862+ < g v- for = " (datapoint, i ) in drawableDataset" : data- cy= " `donut-wrapper-${i}`" : class = " {'donut-opacity': true, 'donut-behind': (i !== hoveredIndex && hoveredIndex !== null)}" >
848863 < g v- if = " datapoint.subtotal" >
849864 < g v- if = " hoveredIndex !== null && hoveredIndex === i" >
850865 < g v- for = " arc in datapoint.donutHover" >
@@ -886,7 +901,7 @@ defineExpose({
886901 < / g>
887902 < / g>
888903 < / g>
889- < g v- for = " (datapoint, i ) in drawableDataset" : class = " {'donut-opacity': true, 'donut-behind': (i !== hoveredIndex && hoveredIndex !== null) || isFixed }" >
904+ < g v- for = " (datapoint, i ) in drawableDataset" : class = " {'donut-opacity': true, 'donut-behind': (i !== hoveredIndex && hoveredIndex !== null)}" >
890905 < g v- if = " datapoint.subtotal !== null" >
891906 < circle
892907 v- if = " datapoint.subtotal === 0"
@@ -918,7 +933,7 @@ defineExpose({
918933 < / g>
919934
920935 <!-- DATALABELS -->
921- < g v- for = " (datapoint, i ) in drawableDataset" : class = " {'donut-opacity': true, 'donut-behind': (i !== hoveredIndex && hoveredIndex !== null) || isFixed}" >
936+ < g v- for = " (datapoint, i ) in drawableDataset" : class = " {'donut-opacity': true, 'donut-behind': (i !== hoveredIndex && hoveredIndex !== null) || ( isFixed && i !== fixedDatapoint.index) }" >
922937 < text
923938 v- if = " datapoint.subtotal !== null && FINAL_CONFIG.style.chart.layout.dataLabels.show"
924939 text- anchor= " middle"
@@ -936,12 +951,14 @@ defineExpose({
936951 < rect
937952 v- for = " (datapoint, i) in drawableDataset"
938953 : x= " padding.left + (i * slit)"
939- : y= " svg.absoluteHeight - padding.bottom - 10 "
954+ : y= " padding.top "
940955 : width= " slit"
941- : height= " 10"
942- : fill= " hoveredIndex === datapoint.index ? `url(#hover_${uid})` : 'transparent'"
943- @click= " fixDatapoint(datapoint, i)"
944- : class = " {'donut-hover': hoveredIndex === datapoint.index && datapoint.subtotal}"
956+ : height= " svg.height"
957+ : fill= " [hoveredIndex, fixedDatapointIndex].includes(datapoint.index) ? `url(#hover_${uid})` : 'transparent'"
958+ : class = " {'donut-hover': datapoint.subtotal && [hoveredIndex, fixedDatapointIndex].includes(datapoint.index)}"
959+ : style= " {
960+ pointerEvents: 'none'
961+ }"
945962 / >
946963 < rect
947964 v- for = " (datapoint, i) in drawableDataset"
@@ -957,124 +974,6 @@ defineExpose({
957974 @click= " fixDatapoint(datapoint, i)"
958975 : class = " {'donut-hover': hoveredIndex === datapoint.index && datapoint.subtotal}"
959976 / >
960-
961- <!-- DIALOG -->
962- < g v- if = " isFixed" data- cy- zoom class = " vue-ui-donut-evolution-dialog" >
963- < rect
964- : rx= " 4"
965- : x= " padding.left"
966- : y= " padding.top"
967- : width= " svg.width"
968- : height= " svg.height"
969- : fill= " FINAL_CONFIG.style.chart.backgroundColor"
970- style= " filter:drop-shadow(0 12px 12px rgba(0,0,0,0.3))"
971- / >
972- < line
973- data- dom- to- png- ignore
974- : x1= " svg.absoluteWidth - padding.right - 15"
975- : y1= " padding.top + 5"
976- : x2= " svg.absoluteWidth - padding.right - 4"
977- : y2= " padding.top + 15.5"
978- stroke- linecap= " round"
979- : stroke= " FINAL_CONFIG.style.chart.color"
980- stroke- width= " 1.5"
981- / >
982- < line
983- data- dom- to- png- ignore
984- : x1= " svg.absoluteWidth - padding.right - 15"
985- : y2= " padding.top + 5"
986- : x2= " svg.absoluteWidth - padding.right - 4"
987- : y1= " padding.top + 15.5"
988- stroke- linecap= " round"
989- : stroke= " FINAL_CONFIG.style.chart.color"
990- stroke- width= " 1.5"
991- / >
992- < circle
993- data- cy- close
994- @click= " unfixDatapoint"
995- @keypress .enter = " unfixDatapoint"
996- : cx= " svg.absoluteWidth - padding.right - svg.width / 40"
997- : cy= " padding.top + svg.height / 30"
998- : r= " svg.height / 12"
999- fill= " transparent"
1000- style= " cursor:pointer"
1001- tabindex= " 0"
1002- / >
1003-
1004- < g v- for = " arc in fixedDatapoint.donutFocus" >
1005- < path
1006- v- if = " isArcBigEnoughZoom(arc)"
1007- data- cy- zoom- donut
1008- : d= " calcNutArrowPath(arc, {x: svg.centerX, y: svg.centerY}, 12, 12, false, false, 15)"
1009- : stroke= " arc.color"
1010- stroke- width= " 1"
1011- stroke- linecap= " round"
1012- stroke- linejoin= " round"
1013- fill= " none"
1014- class = " vue-ui-donut-evolution-focus"
1015- / >
1016- < / g>
1017- < circle
1018- : cx= " padding.left + svg.width / 2"
1019- : cy= " padding.top + svg.height / 2"
1020- : r= " svg.height / 7"
1021- : fill= " FINAL_CONFIG.style.chart.backgroundColor"
1022- / >
1023- < path
1024- v- for = " (arc, k) in fixedDatapoint.donutFocus"
1025- : d= " arc.arcSlice"
1026- : fill= " `${arc.color}`"
1027- : stroke- width= " 1"
1028- : stroke= " FINAL_CONFIG.style.chart.backgroundColor"
1029- class = " vue-ui-donut-evolution-focus"
1030- / >
1031- < g v- for = " (arc, i) in fixedDatapoint.donutFocus" class = " vue-ui-donut-evolution-focus" >
1032- < text
1033- v- if = " isArcBigEnoughZoom(arc)"
1034- : data- cy= " `donut-datalabel-value-${i}`"
1035- : text- anchor= " calcMarkerOffsetX(arc, true, 20).anchor"
1036- : x= " calcMarkerOffsetX(arc, true, 10).x"
1037- : y= " calcMarkerOffsetY(arc)"
1038- : fill= " FINAL_CONFIG.style.chart.layout.grid.yAxis.dataLabels.color"
1039- : font- size= " 10"
1040- : font- weight= " 'bold'"
1041- >
1042- {{ arc .name }}: {{ displayArcPercentage (arc, fixedDatapoint .donutFocus ) }} ({{ arc .value === null ? ' -' : labellizeValue (arc .value , arc, i) }})
1043- < / text>
1044- < / g>
1045- < circle
1046- : cx= " padding.left + (svg.width / 2)"
1047- : cy= " padding.top + (svg.height / 2)"
1048- : r= " svg.height / 3.8"
1049- : fill= " `url(#focus_${uid})`"
1050- / >
1051- < circle
1052- : cx= " padding.left + (svg.width / 2)"
1053- : cy= " padding.top + (svg.height / 2)"
1054- : r= " svg.height / 7.7"
1055- : fill= " FINAL_CONFIG.style.chart.backgroundColor"
1056- / >
1057- < text
1058- text- anchor= " middle"
1059- : x= " padding.left + svg.width / 2"
1060- : y= " padding.top + (svg.height / 2) + 14 / 3"
1061- : font- size= " 14"
1062- : font- weight= " 'bold'"
1063- : fill= " FINAL_CONFIG.style.chart.layout.dataLabels.color"
1064- class = " vue-ui-donut-evolution-focus"
1065- >
1066- {{ labellizeValue (fixedDatapoint .subtotal , fixedDatapoint, null ) }}
1067- < / text>
1068- < text
1069- v- if = " FINAL_CONFIG.style.chart.layout.grid.xAxis.dataLabels.values[fixedDatapoint.index]"
1070- : x= " padding.left + 6"
1071- : y= " padding.top + FINAL_CONFIG.style.chart.layout.grid.xAxis.dataLabels.fontSize * 2"
1072- : font- size= " FINAL_CONFIG.style.chart.layout.grid.xAxis.dataLabels.fontSize * 1.6"
1073- : fill= " FINAL_CONFIG.style.chart.layout.dataLabels.color"
1074- >
1075- {{ FINAL_CONFIG .style .chart .layout .grid .xAxis .dataLabels .values [Number (fixedDatapoint .index ) + Number (slicer .start )] }}
1076- < / text>
1077- < / g>
1078977 < slot name= " svg" : svg= " svg" / >
1079978 < / svg>
1080979
@@ -1209,6 +1108,24 @@ defineExpose({
12091108 < / DataTable>
12101109 < / template>
12111110 < / Accordion>
1111+
1112+ < BaseDraggableDialog
1113+ v- if = " FINAL_CONFIG.style.chart.dialog.show"
1114+ ref= " dialog"
1115+ @close= " fixedDatapoint = null; isFixed = false"
1116+ : backgroundColor= " FINAL_CONFIG.style.chart.dialog.backgroundColor"
1117+ : color= " FINAL_CONFIG.style.chart.dialog.color"
1118+ : headerBg= " FINAL_CONFIG.style.chart.dialog.header.backgroundColor"
1119+ : headerColor= " FINAL_CONFIG.style.chart.dialog.header.color" >
1120+ < template #title>
1121+ {{ FINAL_CONFIG .style .chart .layout .grid .xAxis .dataLabels .values [Number (fixedDatapoint .index ) + Number (slicer .start )] }}
1122+ < / template>
1123+ < VueUiDonut
1124+ v- if = " fixedDatapoint"
1125+ : config= " donutConfig"
1126+ : dataset= " donutDataset"
1127+ / >
1128+ < / BaseDraggableDialog>
12121129 < / div>
12131130< / template>
12141131
0 commit comments