JavaScript is required

图案胶带线条渲染

这个示例用填充式胶带风 SVG 丝带替换默认 relation-graph 连线,并允许用户在半透明纯色及多种静态/动画图案填充之间切换。它还可在运行时把现有节点在圆形和矩形之间切换,保持连线点击仍接入 relation-graph,并提供共享画布设置与图片导出。

通过图案切换与节点形状实时更新实现胶带式线条渲染

本示例构建的内容

本示例构建了一个采用中心布局的小型拓扑查看器,其边线不再以普通描边方式绘制。每条关系都会被渲染为一个填充的、类似胶带的 SVG 面区域,因此整张图在深色技术风画布上看起来更像是分层带状结构,而不是默认的节点连线图。

用户可以在线条填充效果之间切换,包括半透明纯色和多种 SVG 图案;可以将现有所有节点在圆形和矩形之间切换;可以打开共享的画布设置面板;还可以将图谱导出为图片。这个示例的关键点在于,线条表面虽然被完全自定义了,但线条点击依然会走 relation-graph 的标准交互流程。

数据是如何组织的

数据集在 initializeGraph 中以内联 RGJsonData 的方式声明。它使用 rootId: '2',包含 9 个节点和 8 条连线,并且每条线都采用 relation-graph 的标准格式,即 fromtotext。这份数据刻意保持小而静态,以便让示例聚焦于渲染行为,而不是数据加载。

在调用 setJsonData 之前,没有进行任何业务数据预处理。特殊处理发生在渲染阶段:对于每条可见线条,示例都会基于源节点与目标节点的几何信息计算出一个闭合的四点面积路径。在真实系统中,同样的结构可以表示子系统依赖、设备连接、流程连接或网络拓扑片段,而带状填充则可以编码类别、状态或流量风格。

relation-graph 的使用方式

RGProvider 包裹整个演示,以便 relation-graph 的 hooks 可以解析当前图实例。RelationGraph 接收一组选项,用于保持展示简洁且一致:中心布局、边界连接点、默认蓝色线条颜色、白色节点颜色、零节点边框宽度,以及一个绑定到 React state 的 defaultNodeShape。在挂载时,setJsonDatamoveToCenterzoomToFit 会负责加载并将图谱调整到合适视图中。

主要扩展点是 RGSlotOnLine。示例没有使用内置边线渲染器,而是将每条线传给 MyLineContent,并在其中再次通过 RGHooks.useGraphInstance() 访问 relation-graph API。该组件会基于实时的 fromto 节点计算自定义带状路径,保留 relation-graph 线条状态,例如 checkedselected,并通过 graphInstance.onLineClick(...) 转发点击事件。

运行时样式链路被拆分为 React state、SVG defs 和 SCSS 三部分。fillStyleId 会写入外层图容器上的 CSS 变量 --rg-line-fill-styleMySvgDefs 定义可用的静态与动态图案;my-relation-graph.scss 则将选中的填充应用到 .rg-line,移除普通描边,添加选中轮廓,并结合混合模式与悬停亮度效果,让这些带状线条呈现出半透明胶带的质感。这个样式文件还同时创建了深色网格背景以及洋红色节点视觉风格。

该示例是一个查看器而不是编辑器。它不允许用户新增或重新连接图数据,但会在运行时修改展示状态。当节点形状选择器变化时,图实例会遍历现有节点并调用 updateNode,从而让已经渲染出来的节点立即切换形状。共享的 DraggableWindow 组件还暴露了一个由 RGHooks.useGraphStore() 驱动的画布设置面板,其中滚轮模式、拖拽模式和图片导出都通过 relation-graph 实例 API 处理。

关键交互

  • 点击自定义带状线仍会触发 relation-graph 的线条点击处理,因为自定义 <path> 会阻止冒泡,并通过 graphInstance.onLineClick(...) 转发原生事件。
  • Line Fill Style 选择器可以在半透明纯色填充与命名 SVG 图案 id 之间切换,例如 dots、stripes、circuit、lava、arrows 和 rainbow。
  • Node Shape 选择器会遍历当前活动节点并调用 updateNode,从而将所有节点从 circle 切换为 rectangle,或反向切回。
  • 浮动窗口可以拖动,也可以切换为共享设置面板。
  • 设置面板可以修改滚轮行为、修改画布拖拽行为,并在调用 prepareForImageGeneration()restoreAfterImageGeneration() 后下载图片。

关键代码片段

这一段展示了查看器使用中心布局,并将默认节点形状绑定到 React state。

const graphOptions: RGOptions = {
    defaultNodeShape: nodeShape,
    defaultJunctionPoint: RGJunctionPoint.border,
    defaultLineColor: '#2E74B5',
    defaultNodeColor: '#ffffff',
    defaultNodeBorderWidth: 0,
    layout: {
        layoutName: 'center'
    }
};

这一段展示了在加载到 relation-graph 之前内联定义的拓扑数据。

const myJsonData: RGJsonData = {
    rootId: '2',
    nodes: [
        { id: '2', text: 'ALTXX' },
        { id: '3', text: 'CH2 TTN' },
        // ...
    ],
    lines: [
        { from: '2', to: '5', text: 'Subsystem' },
        { from: '2', to: '3', text: 'Subsystem' },
        // ...
    ]
};

这一段展示了图谱的初始加载流程,以及加载完成后的视口定位处理。

await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();

这一段展示了节点形状选择器如何影响已经绘制在画布上的节点。

const updateGraphOptions = () => {
    graphInstance.getNodes().forEach(node => {
        graphInstance.updateNode(node, {
            nodeShape
        });
    });
};

这一段展示了用于将每一条内置线条替换为 MyLineContent 的 slot 覆盖方式。

<RelationGraph options={graphOptions}>
    <RGSlotOnLine>
        {({ lineConfig, checked }: RGLineSlotProps) => (
            <MyLineContent lineConfig={lineConfig} checked={checked} />
        )}
    </RGSlotOnLine>
</RelationGraph>

这一段展示了自定义线条组件如何计算带状路径,并将点击事件重新转发回 relation-graph。

const onLineClick = (e: React.MouseEvent | React.TouchEvent) => {
    e.stopPropagation();
    graphInstance.onLineClick(line, e.nativeEvent as RGUserEvent);
};
const path = generateLinePathAsSimpleArea(
    lineConfig.from,
    lineConfig.to
);

这一段展示了辅助函数如何把两侧的支撑点转换为一个闭合的 SVG 面区域。

const side1 = findStartXyAndEndXy(fromNode, toNode, false);
const side2 = findStartXyAndEndXy(fromNode, toNode, true);

return `M ${ax} ${ay}
        L ${cx} ${cy}
        L ${dx_point} ${dy_point}
        L ${bx} ${by}
        Z`;

这一段展示了共享设置面板如何使用 relation-graph API 导出图谱图片。

const canvasDom = await graphInstance.prepareForImageGeneration();
const imageBlob = await domToImageByModernScreenshot(canvasDom, {
    backgroundColor: graphBackgroundColor
});
if (imageBlob) {
    downloadBlob(imageBlob, 'my-image-name');
}
await graphInstance.restoreAfterImageGeneration();

这个示例的独特之处

对比数据表明,这个示例与 customer-line1adv-line-slotadv-line-slot-1custom-line-stylecustom-line-animation 属于同一类,但它的关注点更窄,也更偏几何层面的实现。它最鲜明的特征,是把 RGSlotOnLine、闭合面路径辅助函数、由 CSS 变量驱动的填充切换,以及一组静态和动态 SVG 图案库组合在一起。因此,当目标不是简单重设内置描边样式,而是直接替换连接线可见表面本身时,它就是一个很有参考价值的案例。

customer-line1 相比,这个示例在图谱实时变更方面走得更远,因为它增加了全图范围的节点形状切换,并采用了居中的拓扑视图,而不是固定树形展示。与 adv-line-slotadv-line-slot-1 相比,它的重点不在于给 relation-graph 原生线条图元添加注释或动画,而在于把每一条连接都转化为可复用的填充带状区域。与 custom-line-stylecustom-line-animation 相比,它不是通过 CSS 重新换肤内置线条渲染器,而是通过基于 slot 的几何替换来改变线条外观。

稀有性数据也支持一个相对克制但更有力度的结论:深色霓虹画布、图案填充的带状线条、保留点击能力的自定义路径、节点形状切换,以及共享的画布/导出面板,这样的组合在整个示例集合中并不常见。它并未被表述为唯一的 line-slot 示例,但它确实是一个高度集中的带状边线渲染参考案例。

这一模式还适用于哪些场景

这一模式很适合应用在拓扑查看器、子系统地图、工业流程图、网络路由视图以及依赖关系可视化中,尤其是在连接线本身需要承载视觉语义时。相同的方法还可以扩展到严重级别带、方向编码传输通道、品牌化边线皮肤,或需要在单一渲染器下提供多种线条表现形式的主题化监控面板中,而不必更改底层图数据模型。