@@ -82,6 +82,7 @@ const observedEl = ref(null);
8282const readyTeleport = ref (false );
8383const tableUnit = ref (null );
8484const userOptionsRef = ref (null );
85+ const tooltip = ref (null );
8586
8687const isDataset = computed (() => {
8788 return !! props .dataset && props .dataset .length ;
@@ -430,22 +431,23 @@ function computeSankeyCoordinates(ds) {
430431 let yCursor = Math .max (0 , (innerH - used) / 2 );
431432
432433 names .forEach ((name , i ) => {
433- const h = heights[i];
434- const x = p .left + levelIndex * colSpacing;
435- const y = yCursor;
436-
437- nodeCoordinates[name] = {
438- x,
439- y,
440- absoluteY: y,
441- height: h,
442- i,
443- color: nodes[name].color ,
444- value: nodes[name].value ,
445- };
434+ const h = heights[i];
435+ const x = p .left + levelIndex * colSpacing;
436+ const y = yCursor;
437+
438+ nodeCoordinates[name] = {
439+ x,
440+ y,
441+ absoluteY: y,
442+ height: h,
443+ i,
444+ color: nodes[name].color ,
445+ value: nodes[name].value ,
446+ id: createUid ()
447+ };
446448
447- yCursor += h;
448- if (i < n - 1 ) yCursor += gapPx;
449+ yCursor += h;
450+ if (i < n - 1 ) yCursor += gapPx;
449451 });
450452 });
451453
@@ -581,11 +583,14 @@ const selectedNodes = ref(null);
581583const selectedSource = ref (null );
582584const dataTooltipSlot = ref (null );
583585const useCustomFormat = ref (false );
586+ const selectedNodeId = ref (null );
587+
584588
585589function selectNode (node , index ) {
586590 segregated .value = [];
587591 selectedNodes .value = findConnectedNodes (node .name );
588592 selectedSource .value = node .name ;
593+ selectedNodeId .value = node .id ;
589594
590595 const nodeName = node .name ;
591596 const dataset = sanitizedDataset .value ;
@@ -712,6 +717,7 @@ function selectNode(node, index) {
712717}
713718
714719function unselectNode (index ) {
720+ selectedNodeId .value = null ;
715721 const datapoint = dataTooltipSlot .value ;
716722 if (FINAL_CONFIG .value .events .datapointLeave ) {
717723 FINAL_CONFIG .value .events .datapointLeave ({ datapoint, seriesIndex: index });
@@ -1006,6 +1012,17 @@ async function generateSvg({ isCb }) {
10061012 }
10071013}
10081014
1015+ async function focusNode (node , i ) {
1016+ selectNode (node, i);
1017+ if (mutableConfig .value .showTooltip ) {
1018+ await nextTick ();
1019+ if (flowChart .value && tooltip .value ) {
1020+ const { left , top } = flowChart .value .getBoundingClientRect ();
1021+ tooltip .value .placeTooltip ({x: (left ?? 0 ) + 12 , y: (top ?? 0 ) + 12 });
1022+ }
1023+ }
1024+ }
1025+
10091026defineExpose ({
10101027 getData,
10111028 getImage,
@@ -1150,9 +1167,17 @@ defineExpose({
11501167 < / linearGradient>
11511168 < / defs>
11521169
1153- < path data- cy= " link" v- for = " path in mutableDataset.links" class = " vue-ui-flow-link" : d= " path.path" stroke- linejoin= " round" stroke- miterlimit= " 1"
1154- : fill= " `url(#${path.id})`" : stroke= " FINAL_CONFIG.style.chart.links.stroke"
1155- : stroke- width= " FINAL_CONFIG.style.chart.links.strokeWidth" : style= " `
1170+ < path
1171+ data- cy= " link"
1172+ v- for = " path in mutableDataset.links"
1173+ class = " vue-ui-flow-link"
1174+ : d= " path.path"
1175+ stroke- linejoin= " round"
1176+ stroke- miterlimit= " 1"
1177+ : fill= " `url(#${path.id})`"
1178+ : stroke= " FINAL_CONFIG.style.chart.links.stroke"
1179+ : stroke- width= " FINAL_CONFIG.style.chart.links.strokeWidth"
1180+ : style= " `
11561181 opacity:${selectedNodes
11571182 ? selectedNodes.includes(path.source) &&
11581183 selectedNodes.includes(path.target)
@@ -1164,7 +1189,8 @@ defineExpose({
11641189 : 0.3
11651190 : FINAL_CONFIG.style.chart.links.opacity
11661191 }
1167- `" / >
1192+ `"
1193+ / >
11681194
11691195 < rect
11701196 data- cy= " node"
@@ -1177,9 +1203,32 @@ defineExpose({
11771203 : fill= " node.color"
11781204 : stroke= " FINAL_CONFIG.style.chart.nodes.stroke"
11791205 : stroke- width= " FINAL_CONFIG.style.chart.nodes.strokeWidth"
1206+ : rx= " FINAL_CONFIG.style.chart.nodes.borderRadius"
1207+ : style= " {
1208+ opacity: selectedNodes ? (selectedNodes.includes(node.name) ? 1 : 0.3) : 1,
1209+ outline: selectedNodeId !== null && selectedNodeId === node.id ? '2px solid currentColor' : undefined,
1210+ }"
1211+
1212+ role= " button"
1213+ tabindex= " 0"
1214+ : aria- label= " `${node.name}: ${applyDataLabel(
1215+ FINAL_CONFIG.style.chart.nodes.labels.formatter,
1216+ node.value,
1217+ dataLabel({
1218+ p: FINAL_CONFIG.style.chart.nodes.labels.prefix,
1219+ v: node.value,
1220+ s: FINAL_CONFIG.style.chart.nodes.labels.suffix,
1221+ r: FINAL_CONFIG.style.chart.nodes.labels.rounding
1222+ })
1223+ )}`"
11801224 @mouseenter= " selectNode(node, i)"
1181- @mouseleave= " unselectNode(i)" : style = " `opacity:${selectedNodes ? (selectedNodes.includes(node.name) ? 1 : 0.3) : 1 }` "
1225+ @mouseleave= " unselectNode(i)"
11821226 @click= " clickNode(i)"
1227+ @keydown .enter .prevent = " clickNode(i)"
1228+ @keydown .space .prevent = " clickNode(i)"
1229+ @keydown .esc .prevent = " unselectNode(i)"
1230+ @focus= " focusNode(node, i)"
1231+ @blur= " unselectNode(i)"
11831232 / >
11841233
11851234 < g v- if = " FINAL_CONFIG.style.chart.nodes.labels.show" >
@@ -1256,6 +1305,7 @@ defineExpose({
12561305
12571306 <!-- TOOLTIP -->
12581307 < Tooltip
1308+ ref= " tooltip"
12591309 : show= " mutableConfig.showTooltip && isTooltip"
12601310 : backgroundColor= " FINAL_CONFIG.style.chart.tooltip.backgroundColor"
12611311 : color= " FINAL_CONFIG.style.chart.tooltip.color"
0 commit comments