[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:animated-shortest-path-highlighting":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Animated Shortest-Path Highlighting with Selectable Line Effects\n\n## What This Example Builds\n\nThis example builds a read-only relation viewer that continuously emphasizes the shortest route between two nodes in a compact graph. The canvas uses icon-based circular nodes, curved links with custom arrow markers, and a dark neon visual theme. Users can click two nodes to compute a route manually, let the demo replay random routes automatically, switch between `tree` and `center` layouts, and change the visual skin used on the active route.\n\nThe main point is not generic line theming. The selected effect class is reserved for the current shortest path, while unrelated nodes and lines are dimmed to push attention toward the route under inspection.\n\n## How the Data Is Organized\n\nThe graph data is declared inline as one `RGJsonData` object with a `rootId`, a flat `nodes` array, and a flat `lines` array. The sample mixes outgoing and incoming lines around the same hub so the highlighted route can cross different parts of the topology.\n\nBefore `setJsonData` runs, the code rewrites every line to use custom SVG marker ids, enables the start arrow, and disables the default end arrow. The pathfinding data is not kept as a separate static structure. Instead, the example rebuilds a helper graph from `graphInstance.getNodes()` and `graphInstance.getLinks()`, then reconstructs a shortest route by walking those connections in either direction. In a production system, the same shape could represent service dependencies, process handoffs, warehouse routes, infrastructure traces, or escalation paths.\n\n## How relation-graph Is Used\n\n`RGProvider` supplies the graph instance, and `RGHooks.useGraphInstance()` drives nearly all runtime behavior. The graph starts with `layout.layoutName = 'tree'`, `from = 'left'`, `treeNodeGapH = 100`, `treeNodeGapV = 20`, `defaultJunctionPoint = RGJunctionPoint.ltrb`, `defaultNodeShape = RGNodeShape.circle`, and `defaultLineShape = RGLineShape.StandardCurve`.\n\nThe example keeps relation-graph's built-in renderers and customizes them through slots, defs, and CSS. `RGSlotOnNode` replaces the default node body with an icon-and-text node. `MySvgDefs` injects the custom arrow markers and the glitch filter used by the electric route style. The SCSS file targets `.rg-node-peel`, `.rg-line-peel`, `.rg-line-bg`, and `.rg-line` so the example can restyle built-in nodes and lines without providing a custom line slot.\n\nAt runtime, `setJsonData` loads the prepared graph, `moveToCenter()` and `zoomToFit()` normalize the viewport, `updateOptions()` relaunches the same dataset in another layout, and `getNodes()`, `getLinks()`, `getLines()`, `updateNode()`, and `updateLine()` compute and render the active path. The shared floating window also uses `prepareForImageGeneration()`, `getOptions()`, `setOptions()`, and `restoreAfterImageGeneration()` to expose canvas settings and image export around the graph.\n\n## Key Interactions\n\n- One node click stores a starting endpoint. A different second click computes the shortest path and highlights matching nodes and lines.\n- Clicking the same node twice is ignored. Clicking a line clears any pending first-node selection.\n- An `800ms` timer feeds random nodes into the same node-click flow, so autoplay and manual path selection share one route-highlighting mechanism.\n- The floating panel switches the graph between `tree` and `center` layouts, reloads the dataset, and lets users swap the route effect between `Electric Current` and `Data Flow`.\n- The shared window can also be dragged, minimized, opened as a canvas-settings overlay, and used to export the current graph as an image.\n\n## Key Code Fragments\n\nThis initialization pass proves that line markers are assigned during data preparation, before the graph is loaded.\n\n```tsx\nmyJsonData.lines.forEach(line => {\n    line.endMarkerId = 'my-arrow-001';\n    line.startMarkerId = 'my-arrow-001-start';\n    line.showStartArrow = true;\n});\nmyJsonData.lines.forEach((line) => {\n    line.showEndArrow = false;\n});\nawait graphInstance.setJsonData(myJsonData);\n```\n\nThis timer keeps replaying the same route-selection flow instead of creating a separate autoplay renderer.\n\n```tsx\nconst restartRandomPathTask = () => {\n    clearInterval(playTimerRef.current);\n    playTimerRef.current = setInterval(() => {\n        const nodes = graphInstance.getNodes();\n        const randomNode = nodes[Math.floor(Math.random() * nodes.length)];\n        onNodeClick(randomNode);\n    }, 800);\n};\n```\n\nThis click handler turns two endpoint selections into one shortest-path query and clears the pending start node afterward.\n\n```tsx\nconst onNodeClick = (node: RGNode, $event?: RGUserEvent) => {\n    if (checkedNodeIdRef.current) {\n        if (checkedNodeIdRef.current === node.id) {\n            return;\n        }\n        calcShortestPath(checkedNodeIdRef.current, node.id, graphInstance, itemsOnPathClassName);\n        checkedNodeIdRef.current = '';\n    } else {\n        checkedNodeIdRef.current = node.id;\n    }\n};\n```\n\nThis helper shows that the pathfinding layer is rebuilt from the live relation-graph instance rather than from a second hard-coded adjacency list.\n\n```ts\nloadDataFromRelationGraph(graphInstance: RelationGraphInstance) {\n    this.nodes = graphInstance.getNodes().map(n => {\n        return { id: n.id, childs: [], indexed: false, parentNode: null };\n    });\n    this.edges = graphInstance.getLinks().map(link => {\n        return { from: link.fromNode.id, to: link.toNode.id };\n    });\n}\n```\n\nThis mutation pass applies the chosen effect class only to route lines and fades the rest of the graph context.\n\n```ts\ngraphInstance.getLines().forEach((line: RGLine) => {\n    if (lineIdsOnPath.includes(line.id)) {\n        graphInstance.updateLine(line, { className: flagClassName });\n    } else {\n        graphInstance.updateLine(line, { opacity: 0.2 });\n    }\n});\n```\n\nThis SCSS preset shows that the animated route skins are ordinary classes on relation-graph's built-in line layers.\n\n```scss\n.rg-line-peel.my-line-class-12 {\n    .rg-line-bg {\n        stroke: #334455;\n        stroke-width: 6px;\n        stroke-dasharray: 9, 9, 9;\n        animation: traffic-slow 4s linear infinite;\n    }\n\n    .rg-line {\n        stroke: #00d2ff;\n        stroke-dasharray: 20, 80;\n        animation: traffic-fast 1.5s linear infinite;\n    }\n}\n```\n\n## What Makes This Example Distinct\n\nThe comparison data positions this example between line-style demos and path-analysis demos. Compared with `custom-line-animation` and `custom-line-style`, it does not re-theme every rendered line. Instead, the style selector changes how the computed route is displayed, while non-route items are dimmed. Compared with `find-min-path`, it uses a lighter interaction model: two node clicks and a timer-driven replay loop reuse the same shortest-path routine rather than relying on a form-based query flow.\n\nThat combination is what makes the example stand out. The rare part is not any single ingredient by itself, but the mix of live shortest-path computation, path-only animated skins, custom SVG arrow markers, runtime layout switching, and autoplay-driven route playback in one viewer. It is therefore a stronger starting point for route-inspection interfaces than for generic graph-wide line-style galleries.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to infrastructure and operations diagrams where teams need to inspect one route at a time without editing the graph. Examples include service-dependency tracing, logistics handoff maps, alert-escalation chains, data lineage viewers, and network path walkthroughs.\n\nIt also fits presentation-oriented tools that need both analysis and atmosphere. A team can keep the same underlying topology, switch layouts for readability, and apply different route skins for demos, investigations, or exported snapshots without replacing relation-graph's built-in line renderer.\n",false,500,1782615377168]