[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:zh:animated-line-slot-detail-link":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# 带可点击 `Detail` 标签的自定义连线插槽动画\n\n## 这个示例构建了什么\n\n这个示例在深色画布上构建了一棵从左向右展开的路由树，然后用自定义连线插槽替换默认的边渲染器。最终效果是一组加粗的、具有动画效果的管道式连线，一个沿着每条计算路径移动的洋红色圆点，以及一个可附加绿色 `Detail` 操作的白色连线标签。\n\n用户可以直观检查整个网络，点击连线而不丢失 relation-graph 正常的连线事件流，从标签触发某条连线专属的详情操作，打开悬浮设置面板，并将画布导出为图片。这个示例的核心在于，连线层虽然被完全自定义了，但几何计算、文本定位和事件管线仍然由 relation-graph 提供。\n\n## 数据如何组织\n\n图数据通过一个内联的 `RGJsonData` 对象加载，其中包含 `rootId`、`nodes` 和 `lines`。每条连线都保存了 `from`、`to`、`text`，以及一个携带路线风格元数据的 `data` 负载，例如 `myIcon`、`myCapacity`、`myWeight` 和 `mySpeed`。在加载数据之前，示例会遍历每一条连线并设置 `showEndArrow = false`，这样既能让管道动画在视觉上更干净，也能避免自定义描边与默认箭头混在一起。\n\n这种结构可以直接映射到运输路线、服务依赖、机器到机器的传输，或者任何边上承载运行指标的有向网络。这个示例中的数据集是静态的，但只要每个连接仍能表示为一组 `from` 和 `to` 再加上每条连线的详情，相同的数据形态也适用于由 API 驱动的连线元数据。\n\n## 如何使用 relation-graph\n\n`RGProvider` 包裹了整个示例，使 hooks 能解析到当前激活的图实例。在 `MyGraph` 内部，`RelationGraph` 被配置为一个从左侧生长的树形布局，配合 `[500, 400]` 的 `levelGaps`、`RGJunctionPoint.lr` 和 `RGLineShape.StandardCurve`。这样一来，自定义渲染器就能基于一条可预测的曲线路由形状进行装饰。\n\n主要的自定义入口是 `RGSlotOnLine`。示例没有直接接受 relation-graph 默认输出的连线，而是把每条连线运行时的 slot props 传给 `MyLineContent`。该组件调用 `generateLinePath` 获取真实的 SVG 路径，调用 `generateLineTextStyle` 复用 relation-graph 已计算好的标签定位，把自定义点击转发回 `graphInstance.onLineClick`，通过 `RGLinePath` 渲染路径，并通过 `RGLineText` 按条件渲染非 SVG 标签分支。\n\n图实例 API 也在 slot 之外被使用。`setJsonData`、`moveToCenter` 和 `zoomToFit` 会在挂载时初始化视图。共享设置面板使用 `setOptions` 切换滚轮和拖拽行为，并通过 `prepareForImageGeneration` 配合 `restoreAfterImageGeneration` 导出干净的画布图片。最终的视觉效果来自 `my-relation-graph.scss`：它重写了画布背景，去掉了节点外壳，增加了选中节点发光效果，使用 `stroke-dasharray` 为连线描边添加动画，并通过 `offset-path` 驱动移动圆点。\n\n## 关键交互\n\n- 即使连线视觉来自自定义 slot，点击 SVG 连线路径仍然会进入 relation-graph 的 `onLineClick` 管线。\n- 当非 SVG 标签分支处于激活状态时，点击标签同样会转发到同一个连线点击处理函数。\n- 追加的 `Detail` 链接会把当前 `RGLine` 传给父级逻辑，并为该连线弹出一个提示框。\n- 悬浮的 `DraggableWindow` 可以拖动、最小化，并切换为画布设置面板。\n- 设置面板可以修改滚轮行为、修改画布拖拽行为，并下载当前图的导出图片。\n\n## 关键代码片段\n\n这段代码展示了自定义渲染器所依赖的布局配置和默认连线设置。\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\n这段代码展示了内联路线数据集，以及在加载前关闭默认终点箭头的预处理步骤。\n\n```tsx\nconst myJsonData: RGJsonData = {\n    rootId: 'base',\n    nodes: [\n        { id: 'base', text: '🏢 Base', },\n        // ...\n    ],\n    lines: [\n        { from: 'base', to: '1', text: 'Line X01', data: { myIcon: '🚢', myCapacity: 1.2, myWeight: 1, mySpeed: 1 } },\n        // ...\n    ]\n};\nmyJsonData.lines.forEach((line) => {\n    line.showEndArrow = false;\n});\nawait graphInstance.setJsonData(myJsonData);\n```\n\n这段代码展示了示例如何用 `MyLineContent` 替换 relation-graph 默认的连线渲染器。\n\n```tsx\n\u003CRelationGraph\n    options={graphOptions}\n    onLineClick={onLineClick}\n>\n    \u003CRGSlotOnLine>\n        {(lineSlotProps: RGLineSlotProps) => {\n            return (\n                \u003CMyLineContent\n                    {...lineSlotProps}\n                    onMyLineDetailClick={onMyLineDetailClick}\n                />\n            );\n        }}\n    \u003C/RGSlotOnLine>\n\u003C/RelationGraph>\n```\n\n这段代码展示了自定义 slot 如何一次性计算真实路径几何，并同时将结果暴露给 relation-graph 辅助方法和 CSS 动画。\n\n```tsx\nconst linePathInfo = useMemo\u003CRGLinePathInfo>(() => graphInstance.generateLinePath(lineConfig), [lineConfig]);\nconst onLineClick = (e: React.MouseEvent | React.TouchEvent) => {\n    graphInstance.onLineClick(lineConfig.line, e.nativeEvent);\n};\nconst textStyle = graphInstance.generateLineTextStyle(lineConfig, linePathInfo);\nconst pathEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');\npathEl.setAttribute('d', linePathInfo.pathData);\nreturn (\u003Cg\n    style={{\n        '--my-line-path': `path('${linePathInfo.pathData}')`,\n        '--my-line-path-length': pathEl.getTotalLength()\n    }}>\n```\n\n这段代码展示了该 slot 如何保留 relation-graph 原生的连线基础图元，同时添加一个移动圆点。\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    \u003Ccircle className=\"my-dot\" r=\"5\">\u003C/circle>\n\u003C/RGLinePath>\n```\n\n这段代码展示了非 SVG 标签分支如何在计算好的连线文本后再追加一个独立的 `Detail` 操作。\n\n```tsx\n\u003Cdiv\n    className={`rg-line-label ${useTextOnPath ? 'rg-line-label-on-path' : ''}`}\n    style={{\n        ...textStyle.cssStyles\n    }}\n    onTouchStart={onLineClick}\n    onClick={onLineClick}\n>\n    {textStyle.text}\n    \u003Ca\n        className=\"text-green-300 cursor-pointer hover:underline\"\n        onClick={() => { onMyLineDetailClick(lineConfig.line); }}\n    >\n        Detail\n    \u003C/a>\n\u003C/div>\n```\n\n这段代码展示了如何用 CSS 把计算得到的几何信息转换为管道动画和沿路径运动的效果。\n\n```scss\n.rg-line {\n    stroke: rgb(67, 102, 241);\n    stroke-width: 10px;\n    animation: draw-line 5s linear infinite;\n    stroke-dasharray: var(--my-line-path-length);\n    stroke-dashoffset: var(--my-line-path-length);\n}\n\n.my-dot {\n    offset-path: var(--my-line-path);\n    offset-distance: 0%;\n    animation: ride-path 5s linear infinite;\n}\n```\n\n## 这个示例的独特之处\n\n对比数据将这个示例定位为一个聚焦于动画连线 slot 的参考，而不是通用的连线样式示例。它最明显的特点是：虽然连线渲染器被整体替换了，但 `RGLinePath` 和 `RGLineText` 仍然保留在流程里，同时内部继续使用 `generateLinePath`、`generateLineTextStyle` 以及 relation-graph 正常的 `onLineClick` 流程。单是这种组合就已经相当少见。\n\n与 `adv-line-slot` 相比，这个示例更强调有度量依据的管线动画，而不是端点注释。它利用真实的 SVG 路径长度同时驱动描边绘制效果和移动圆点，而 `adv-line-slot` 被描述为更通用的带注释连线 slot 同类示例。与 `adv-line-slot-2` 相比，这个示例更轻量，重点保持在动画连线渲染和简单的详情操作上，而没有继续加入自定义节点 slot、进度位置标记或仅在选中状态下显示的指标面板。与 `adv-line-slot2` 相比，它更贴近 relation-graph 原生的连线图元，而不是把每条边改造成带状填充几何体。\n\n最终形成的是一种紧凑、偏查看器取向的模式：它结合了深色的路线监控视觉风格、混合使用 SVG 和 HTML 的标签，以及连线级别的操作，同时又不会扩展成一个更宽泛的编辑类示例。\n\n## 这种模式还适用于哪里\n\n这种模式可以改造用于物流看板、网络流量视图、服务依赖图、制造传输流程、能源分配路线或安全路径分析。它特别适合那些“边本身需要承载叙事”的场景：需要展示流动动画、连线级指标、直接的连线操作，以及可导出的展示输出，而底层路径几何和事件路由依然继续交给 relation-graph 处理。\n",false,500,1782615379075]