JavaScript is required

带详情链接的动画线条插槽

这个示例在深色画布上构建了一棵从左向右展开的路由树,然后用自定义连线插槽替换默认的边渲染器。最终效果是一组加粗的、具有动画效果的管道式连线,一个沿着每条计算路径移动的洋红色圆点,以及一个可附加绿色 `Detail` 操作的白色连线标签。

带可点击 Detail 标签的自定义连线插槽动画

这个示例构建了什么

这个示例在深色画布上构建了一棵从左向右展开的路由树,然后用自定义连线插槽替换默认的边渲染器。最终效果是一组加粗的、具有动画效果的管道式连线,一个沿着每条计算路径移动的洋红色圆点,以及一个可附加绿色 Detail 操作的白色连线标签。

用户可以直观检查整个网络,点击连线而不丢失 relation-graph 正常的连线事件流,从标签触发某条连线专属的详情操作,打开悬浮设置面板,并将画布导出为图片。这个示例的核心在于,连线层虽然被完全自定义了,但几何计算、文本定位和事件管线仍然由 relation-graph 提供。

数据如何组织

图数据通过一个内联的 RGJsonData 对象加载,其中包含 rootIdnodeslines。每条连线都保存了 fromtotext,以及一个携带路线风格元数据的 data 负载,例如 myIconmyCapacitymyWeightmySpeed。在加载数据之前,示例会遍历每一条连线并设置 showEndArrow = false,这样既能让管道动画在视觉上更干净,也能避免自定义描边与默认箭头混在一起。

这种结构可以直接映射到运输路线、服务依赖、机器到机器的传输,或者任何边上承载运行指标的有向网络。这个示例中的数据集是静态的,但只要每个连接仍能表示为一组 fromto 再加上每条连线的详情,相同的数据形态也适用于由 API 驱动的连线元数据。

如何使用 relation-graph

RGProvider 包裹了整个示例,使 hooks 能解析到当前激活的图实例。在 MyGraph 内部,RelationGraph 被配置为一个从左侧生长的树形布局,配合 [500, 400]levelGapsRGJunctionPoint.lrRGLineShape.StandardCurve。这样一来,自定义渲染器就能基于一条可预测的曲线路由形状进行装饰。

主要的自定义入口是 RGSlotOnLine。示例没有直接接受 relation-graph 默认输出的连线,而是把每条连线运行时的 slot props 传给 MyLineContent。该组件调用 generateLinePath 获取真实的 SVG 路径,调用 generateLineTextStyle 复用 relation-graph 已计算好的标签定位,把自定义点击转发回 graphInstance.onLineClick,通过 RGLinePath 渲染路径,并通过 RGLineText 按条件渲染非 SVG 标签分支。

图实例 API 也在 slot 之外被使用。setJsonDatamoveToCenterzoomToFit 会在挂载时初始化视图。共享设置面板使用 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 的参考,而不是通用的连线样式示例。它最明显的特点是:虽然连线渲染器被整体替换了,但 RGLinePathRGLineText 仍然保留在流程里,同时内部继续使用 generateLinePathgenerateLineTextStyle 以及 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 处理。