[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:animated-route-progress-line-slot":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Custom Route Progress Line Slots with Checked-State Metrics\n\n## What This Example Builds\n\nThis example builds a left-to-right route tree that looks like a transport or flow-monitoring board rather than a default graph. Each line becomes a thick animated route with a moving dot, a vehicle emoji positioned along the computed path, and a label card that expands when the line is checked.\n\nUsers can inspect lines, click the moving marker or label without losing relation-graph's normal line event flow, open a line-specific `Detail` action, drag or minimize the floating help window, switch canvas interaction modes, and export the graph as an image. The main point of the demo is that per-line metadata drives both the motion and the detail reveal, while relation-graph still handles layout, path geometry, and line-state management.\n\n## How the Data Is Organized\n\nThe graph data is declared inline as `RGJsonData` with `rootId`, `nodes`, and `lines`. Every line still uses relation-graph's standard `from` and `to` structure, but each one also carries a `data` object with `myIcon`, `myCapacity`, `myWeight`, `mySpeed`, and `myPercent`. That payload is the real content of the example: it determines which vehicle marker is shown, how large it is, how fast the white dot moves, and how far the highlighted route has progressed.\n\nThere is one small preprocessing step before `setJsonData`: every line has `showEndArrow = false`. That keeps the route display closer to a monitored track than a directional connector with arrowheads. In a real application, the same shape could represent shipment routes, process transfer lines, pipeline status, service traffic, or machine flow, as long as each connection can expose a progress value and a few metrics.\n\n## How relation-graph Is Used\n\n`RGProvider` wraps the example so hooks can resolve the active graph instance. `RelationGraph` is configured with a tree layout that grows from the left, `levelGaps` of `[500, 400]`, `RGJunctionPoint.lr`, and `RGLineShape.StandardCurve`. Those defaults make the route geometry predictable enough for path-following animation.\n\nThe key extension point is `RGSlotOnLine`. `MyGraph` passes the runtime line slot props into `MyLineContent`, then adds a parent callback for the `Detail` action. Inside `MyLineContent`, `RGHooks.useGraphInstance()` calls `generateLinePath` to get the real SVG route, `generateLineTextStyle` to reuse relation-graph's computed label placement, and `onLineClick` to forward custom SVG or HTML clicks back into relation-graph's line event pipeline.\n\nThe slot keeps relation-graph primitives in the loop instead of reimplementing everything manually. `RGLinePath` renders the actual SVG path and receives the forwarded click handler. `RGLineText` renders the HTML label container when the line is in the div-text branch. A wrapper `\u003Cg>` writes CSS variables such as the path itself, total length, moved length, moved percent, and speed, and the stylesheet consumes those variables to animate the stroke, white dot, and emoji marker with `stroke-dasharray` and `offset-path`.\n\nThe example also pairs the custom line slot with `RGSlotOnNode`, which replaces the default node body with a circular warehouse icon node. Outside the graph body, the graph instance API loads and frames the dataset through `setJsonData`, `moveToCenter`, and `zoomToFit`. The shared `DraggableWindow` overlay uses `RGHooks.useGraphStore()` and `setOptions(...)` to switch wheel and drag behavior, then uses `prepareForImageGeneration()` and `restoreAfterImageGeneration()` with `modern-screenshot` to export the graph canvas.\n\n## Key Interactions\n\n- Clicking the custom SVG route, the emoji marker, or the HTML label still forwards into relation-graph's `onLineClick` handling.\n- The richer metric block is hidden by default and only becomes visible when the line enters the checked state.\n- The `Detail` button calls back into the parent component with the current `RGLine` and opens a line-specific alert.\n- The floating overlay can be dragged, minimized, switched into a settings panel, and used to export an image.\n- The settings panel changes wheel behavior and canvas drag behavior without reloading the graph.\n\n## Key Code Fragments\n\nThis block shows the left-to-right tree layout and the default line settings the custom renderer relies on.\n\n```tsx\nconst graphOptions: RGOptions = {\n    defaultJunctionPoint: RGJunctionPoint.lr,\n    defaultLineShape: RGLineShape.StandardCurve,\n    layout: {\n        layoutName: 'tree',\n        from: 'left',\n        levelGaps: [500, 400]\n    }\n};\n```\n\nThis block shows that each route line carries its own icon, capacity, weight, speed, and progress data before the default end arrows are disabled.\n\n```tsx\nlines: [\n    { id: 'l1', from: 'base', to: '1', text: 'Line X01', data: { myIcon: '🚢', myCapacity: 1.2, myWeight: 1, mySpeed: 1, myPercent: 0.2 } },\n    { id: 'l2', from: 'base', to: '2', text: 'Line X02', data: { myIcon: '🚢', myCapacity: 2, myWeight: 1.8, mySpeed: 0.3, myPercent: 0.8 } },\n    // ...\n]\nmyJsonData.lines.forEach((line) => {\n    line.showEndArrow = false;\n});\nawait graphInstance.setJsonData(myJsonData);\n```\n\nThis block shows the graph wiring both the custom line slot and the secondary custom node slot.\n\n```tsx\n\u003CRelationGraph\n    options={graphOptions}\n    onLineClick={onLineClick}\n>\n    \u003CRGSlotOnLine>\n        {(lineSlotProps: RGLineSlotProps) => (\n            \u003CMyLineContent\n                {...lineSlotProps}\n                onMyLineDetailClick={onMyLineDetailClick}\n            />\n        )}\n    \u003C/RGSlotOnLine>\n    \u003CRGSlotOnNode>\n```\n\nThis block shows the line slot deriving real path geometry and converting route metadata into CSS variables for motion and checked-state styling.\n\n```tsx\nconst linePathInfo = useMemo\u003CRGLinePathInfo>(() => graphInstance.generateLinePath(lineConfig), [lineConfig]);\nconst textStyle = graphInstance.generateLineTextStyle(lineConfig, linePathInfo);\nconst pathEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');\npathEl.setAttribute('d', linePathInfo.pathData);\nconst pathLength = pathEl.getTotalLength();\nreturn (\u003Cg\n    style={{\n        '--my-line-path': `path('${linePathInfo.pathData}')`,\n        '--my-line-path-length': pathLength + 'px',\n        '--my-moved-length': (pathLength * lineConfig.line.data?.myPercent) + 'px',\n        '--my-moved-percent': lineConfig.line.data?.myPercent * 100 + '%',\n        '--my-speed': ((1 / lineConfig.line.data?.mySpeed) * 0.5) + 's'\n    }}>\n```\n\nThis block shows the slot keeping `RGLinePath` but adding a moving dot and a size-varying vehicle marker that sits on the route path.\n\n```tsx\n\u003CRGLinePath\n    lineConfig={lineConfig}\n    linePathInfo={linePathInfo}\n    useTextOnPath={useSvgTextPath}\n    checked={checked}\n    graphInstanceId={graphInstanceId}\n    onLineClick={onLineClick}\n>\n    \u003Cg>\n        \u003Ccircle className=\"my-dot\" r=\"3\">\u003C/circle>\n        \u003Cg className=\"my-container\">\n            \u003Ctext onClick={onLineClick} fontSize={(lineConfig.line.data?.myWeight || 1) * 20 + 15} y={-5} transform=\"scale(-1, 1)\">{lineConfig.line.data?.myIcon}\u003C/text>\n        \u003C/g>\n    \u003C/g>\n\u003C/RGLinePath>\n```\n\nThis block shows the HTML label branch rendering the route metrics and a parent-handled detail action.\n\n```tsx\n\u003Cdiv className=\"my-text\">\n    \u003Cdiv>Cap: {lineConfig.line.data?.myCapacity.toFixed(1)}\u003C/div>\n    \u003Cdiv>Weight: {lineConfig.line.data?.myWeight.toFixed(1)}\u003C/div>\n    \u003Cdiv>Speed: {lineConfig.line.data?.mySpeed.toFixed(1)}\u003C/div>\n\u003C/div>\n\u003Cbutton\n    className=\"cursor-pointer hover:underline bg-blue-600 text-white py-1 px-3 rounded mt-2\"\n    onClick={() => { onMyLineDetailClick(lineConfig.line); }}\n>\n    Detail\n\u003C/button>\n```\n\nThis block shows the CSS rule that keeps the metric card hidden until the line is checked.\n\n```scss\n.rg-line-peel.rg-line-checked {\n    .rg-line-label {\n        display: block;\n        background-color: rgb(255, 0, 150);\n        color: #fff;\n    }\n\n    .my-text {\n        display: block;\n    }\n}\n```\n\nThis block shows the shared viewer utility panel changing canvas behavior and exporting an image of the prepared graph DOM.\n\n```tsx\nconst { options } = RGHooks.useGraphStore();\nconst dragMode = options.dragEventAction;\nconst wheelMode = options.wheelEventAction;\n\n\u003CSettingRow\n    label=\"Wheel Event:\"\n    options={[\n        { label: 'Scroll', value: 'scroll' },\n        { label: 'Zoom', value: 'zoom' },\n        { label: 'None', value: 'none' },\n    ]}\n    value={wheelMode}\n    onChange={(newValue: string) => { graphInstance.setOptions({ wheelEventAction: newValue }); }}\n/>\n```\n\n## What Makes This Example Distinct\n\nThe comparison data positions this example as the status-rich member of the nearby custom line slot demos. Its strongest distinguishing trait is that it turns per-line metadata into route-progress rendering by combining `RGSlotOnLine`, `generateLinePath`, `generateLineTextStyle`, `RGLinePath`, and `RGLineText` in one custom renderer. That combination is then pushed further by using the same metadata to control marker icon, marker size, draw distance, and animation speed.\n\nCompared with `adv-line-slot-1`, this variant is more data-driven. It does not stop at a generic moving dot and a simple detail link; it adds `myPercent`, checked-only route metrics, and a coordinated node treatment. Compared with `adv-line-slot`, it shifts the focus away from endpoint annotation and toward monitored progress along the route itself. Compared with `line`, the distinction is even sharper: this demo replaces the line renderer and measures the generated path, instead of staying inside relation-graph's built-in line option gallery.\n\nThe custom node slot matters here, but it is secondary. The comparison record is clear that the real lesson is checked-line inspection plus path-driven route animation, not a broad node-style showcase.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to logistics tracking, warehouse transfer monitoring, pipeline status boards, infrastructure flow views, service traffic maps, and production routing dashboards. It is especially useful when each connection needs to expose progress, speed, or load directly on the line, while keeping the graph read-only and preserving relation-graph's built-in layout and event handling.\n",false,500,1782615379447]