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