From b86e6fdadcc7a665363120780bd021ce80dd7c07 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Thu, 20 Feb 2025 17:07:48 +0100 Subject: [PATCH] ui: add sankey link sourceValue to chart tooltip --- .../app/components/Charts/SankeyChart.tsx | 22 ++++++++-- frontend/app/components/Charts/sankeyUtils.ts | 44 ++++++++++++++++--- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/frontend/app/components/Charts/SankeyChart.tsx b/frontend/app/components/Charts/SankeyChart.tsx index 9a31916d9..0fdb38592 100644 --- a/frontend/app/components/Charts/SankeyChart.tsx +++ b/frontend/app/components/Charts/SankeyChart.tsx @@ -77,13 +77,18 @@ const EChartsSankey: React.FC = (props) => { }); setFinalNodeCount(filteredNodes.length); - + const nodeValues: Record = {}; const echartNodes = filteredNodes - .map((n) => { + .map((n, i) => { let computedName = getNodeName(n.eventType || 'Minor Paths', n.name); if (computedName === 'Other') { computedName = 'Others'; } + if (n.id) { + nodeValues[n.id] = 0; + } else { + nodeValues[i] = 0; + } const itemColor = computedName === 'Others' ? 'rgba(34,44,154,.9)' @@ -124,6 +129,17 @@ const EChartsSankey: React.FC = (props) => { .filter((link) => link.source === 0) .reduce((sum, link) => sum + link.value, 0); + Object.keys(nodeValues).forEach((nodeId) => { + const intId = parseInt(nodeId as string); + const outgoingValues = echartLinks + .filter((l) => l.source === intId) + .reduce((p, c) => p + c.value, 0); + const incomingValues = echartLinks + .filter((l) => l.target === intId) + .reduce((p, c) => p + c.value, 0); + nodeValues[nodeId] = Math.max(outgoingValues, incomingValues); + }); + const option = { ...defaultOptions, tooltip: { @@ -237,7 +253,7 @@ const EChartsSankey: React.FC = (props) => { }, }, tooltip: { - formatter: sankeyTooltip(echartNodes, []), + formatter: sankeyTooltip(echartNodes, nodeValues), }, nodeAlign: 'left', nodeWidth: 40, diff --git a/frontend/app/components/Charts/sankeyUtils.ts b/frontend/app/components/Charts/sankeyUtils.ts index 92997f223..a4e0826af 100644 --- a/frontend/app/components/Charts/sankeyUtils.ts +++ b/frontend/app/components/Charts/sankeyUtils.ts @@ -1,18 +1,32 @@ -// sankeyUtils.ts -export function sankeyTooltip(echartNodes: any[], nodeValues: number[]) { +export function sankeyTooltip( + echartNodes: any[], + nodeValues: Record +) { return (params: any) => { if ('source' in params.data && 'target' in params.data) { const sourceName = echartNodes[params.data.source].name; const targetName = echartNodes[params.data.target].name; + const sourceValue = nodeValues[params.data.source]; + + const safeSourceName = shortenString(sourceName); + const safeTargetName = shortenString(targetName); return `
- ${sourceName} ${targetName} + ${safeSourceName} +
+
+ ${sourceValue} Sessions +
+
+ ${safeTargetName}
- ${params.data.value} ( ${params.data.percentage.toFixed(2)}% ) + ${params.data.value} ( ${params.data.percentage.toFixed( + 2 + )}% ) Sessions
@@ -31,6 +45,21 @@ export function sankeyTooltip(echartNodes: any[], nodeValues: number[]) { }; } +const shortenString = (str: string) => { + const limit = 60; + const leftPart = 25; + const rightPart = 20; + const safeStr = + str.length > limit + ? `${str.slice(0, leftPart)}...${str.slice( + str.length - rightPart, + str.length + )}` + : str; + + return safeStr; +}; + export const getEventPriority = (type: string): number => { switch (type) { case 'DROP': @@ -42,9 +71,12 @@ export const getEventPriority = (type: string): number => { } }; -export const getNodeName = (eventType: string, nodeName: string | null): string => { +export const getNodeName = ( + eventType: string, + nodeName: string | null +): string => { if (!nodeName) { return eventType.charAt(0) + eventType.slice(1).toLowerCase(); } return nodeName; -}; \ No newline at end of file +};