线条形态、锚点与自定义箭头
这个示例构建了一个中心布局参考图,一次性对比多种内置连线行为,包括线形、线宽、连接锚点、箭头显示、文字位置,以及基于 marker 的自定义箭头。它保持图数据静态,加入基于 CSS 的标签样式和暗色主题切换,并提供画布交互模式与图片导出的辅助控件。
在一个参考图中展示线条形状、连接点锚位与自定义箭头
这个示例构建了什么
该示例构建了一个全高的 relation-graph 画布,用作线条渲染的可视化参考板。查看者会看到一个预先排好的中心布局图,其中包含通用的字母节点,以及大量带注释的连接线,在同一画面中对比线宽、线条形状、连接点位置、箭头可见性、文本放置方式和颜色处理。
用户不会编辑图结构,但可以查看这个预设的对照面板、切换深色主题、打开悬浮设置面板、更改滚轮和拖拽行为,并将画布导出为图片。这个示例的重点在于覆盖面广:它会同时展示许多内置线条选项,然后再通过 CSS 标签样式和自定义 SVG 箭头标记对其进行扩展。
数据是如何组织的
图数据在 initializeGraph() 中以内联方式声明为一个 RGJsonData 对象,包含 rootId: 'a'、22 个节点和 28 条线。setJsonData() 之前没有预处理步骤。这个示例直接在代码中构造最终数据集,并按原样加载。
大部分语义都放在 lines 数组中。每条边记录都可以携带自己的 lineShape、lineWidth、color、fontColor、showStartArrow、showEndArrow、startMarkerId、endMarkerId、fromJunctionPoint、toJunctionPoint、useTextOnPath 和 className。节点数据大多只是用于承载对比布局的占位内容,不过也有少数节点会覆盖尺寸、形状或固定位置。在真实产品中,同样的数据结构可以表示工作流分支、集成路径、血缘边、依赖连接,或需要为每条连接单独指定渲染规则的带注释网络路径。
如何使用 relation-graph
index.tsx 用 RGProvider 包裹这个 demo,MyGraph.tsx 则通过 RGHooks.useGraphInstance() 获取当前图实例。图使用内置的 center 布局,并显式设置了 levelGaps、圆形节点默认值、60x60 的默认节点尺寸,以及白色默认节点颜色。
图会在挂载时加载一次。initializeGraph() 会调用 setJsonData(),然后执行 moveToCenter() 和 zoomToFit(),让这个预设画廊在初始状态下就完整可见。这个示例没有使用节点插槽、线条插槽、画布插槽或编辑 API,而是把大部分变化都放进内置的线条元数据字段中。
在内置渲染器之上,这个示例还叠加了两种非数据层面的自定义方式。MyLineArrowDefine 会注入 SVG <marker> 定义,让选中的线条可以通过 marker id 使用自定义的起始和结束箭头。局部 SCSS 文件则通过每条线的类名(如 .my-text-bg-001 到 .my-text-bg-004)来样式化内置线条标签,而当勾选框启用时,外层包裹类会切换为 .my-graph-dark,从而重新定义画布、线条文本、节点和工具栏的样式。
悬浮帮助窗口来自一个共享的本地组件,但它也是示例渲染结果的一部分。这个辅助组件会使用 RGHooks.useGraphStore() 读取当前交互模式,使用 graphInstance.setOptions() 切换滚轮和拖拽行为,并通过 prepareForImageGeneration() 与 restoreAfterImageGeneration() 将当前图视图导出为图片。
关键交互
最显眼的交互,是悬浮说明窗口中的本地深色主题切换。它不会更改图数据,但会改变同一组线条样式在浅色和深色背景下的视觉表现。
悬浮帮助窗口中的设置面板为图增加了操作层控制。用户可以把滚轮事件切换为滚动或缩放,把画布拖拽切换为框选或移动,也可以下载当前画布的图片。这些控件影响的是查看环境,而不是图结构本身。
说明窗口本身也可以通过其内置辅助控件进行拖拽、最小化和重新打开。节点点击和线条点击事件虽然已绑定,但它们只是在控制台打印对象,因此更像是调试或查看用的检查钩子,而不是有实际业务意义的终端用户流程。
关键代码片段
这段代码表明,整个场景使用了 relation-graph 的内置中心布局和默认节点选项。
const graphOptions: RGOptions = {
defaultNodeShape: RGNodeShape.circle,
defaultNodeBorderWidth: 1,
defaultNodeWidth: 60,
defaultNodeHeight: 60,
defaultNodeColor: '#ffffff',
layout: {
layoutName: 'center',
levelGaps: [300, 200, 200]
}
};
这段代码表明,大部分可见差异都是直接在每条线记录中表达的。
{ id: 'line-2', from: 'a', to: 'c', text: 'useTextOnPath Line 1', useTextOnPath: true, fontSize: 10, color: 'rgba(30, 144, 255, 1)' },
{ id: 'line-5', from: 'a', to: 'd', text: 'Thick Line', lineWidth: 3 },
{ id: 'line-6', from: 'a', to: 'e', text: 'Hide Arrow', showEndArrow: false },
{ id: 'line-11', from: 'a', to: 'd', text: 'Polyline', lineShape: RGLineShape.StandardOrthogonal, fromJunctionPoint: RGJunctionPoint.left, toJunctionPoint: RGJunctionPoint.top, className: 'my-text-bg-001' },
这段代码表明,部分线条会附加自定义 marker id,而不只是依赖默认箭头。
{ id: 'line-18', from: 'c', to: 'm1', text: 'RGJunctionPoint.bottom', endMarkerId: 'my-arrow-001', startMarkerId: 'my-arrow-001-start', showStartArrow: true, lineShape: RGLineShape.StandardCurve, toJunctionPoint: RGJunctionPoint.bottom, lineWidth: 6, color: '#00ced1' },
{ id: 'line-19', from: 'c', to: 'm2', text: 'Custom Line Arrow', endMarkerId: 'my-arrow-001', startMarkerId: 'my-arrow-001-start', showStartArrow: true, lineShape: RGLineShape.StandardCurve, fromJunctionPoint: RGJunctionPoint.border, lineWidth: 7, color: '#00ced1' },
这段代码展示了隐藏的 SVG 定义,它们使这些自定义 marker id 可供图渲染器使用。
<svg className="absolute opacity-0" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="my-arrow-001" markerWidth="80" markerHeight="80" refX="2" refY="3"
markerUnits="userSpaceOnUse" orient="auto" viewBox="0 0 12 12">
<path d="M 4 6, V 0, L 0 3, Z" style={{ fill: 'context-stroke' }}></path>
</marker>
<marker id="my-arrow-001-start" markerWidth="80" markerHeight="80" refX="2" refY="3"
markerUnits="userSpaceOnUse" orient="auto-start-reverse" viewBox="0 0 12 12">
<path d="M 4 6, V 0, L 0 3, Z" style={{ fill: 'context-stroke' }}></path>
</marker>
</defs>
</svg>
这段代码表明,标签展示也通过 CSS 类和深色主题包裹类进行了自定义。
.my-text-bg-003 {
.rg-line-label {
background-color: rgb(13, 179, 1);
color: #ffffff;
border-radius: 20px;
padding: 3px 10px;
}
}
.my-graph-dark {
.relation-graph {
.rg-map {
background-color: #333;
}
}
}
这段代码表明,共享帮助窗口会通过 relation-graph API 切换图的交互模式。
<SettingRow
label="Wheel Event:"
options={[
{ label: 'Scroll', value: 'scroll' },
{ label: 'Zoom', value: 'zoom' },
{ label: 'None', value: 'none' },
]}
value={wheelMode}
onChange={(newValue: string) => { graphInstance.setOptions({ wheelEventAction: newValue }); }}
/>
这个示例的独特之处
从这组对比数据可以看出,这个示例的突出之处在于:一个静态的中心布局图把许多内置线条行为集中展示在同一个地方,包括混合线条形状、显式连接点锚位、宽度变化、隐藏或反向箭头、沿路径排布的文本标签、自定义 marker id,以及按线条分类的标签类。它的独特价值不在于某一项技巧是独有的,而在于它把这么多能力组合进了同一个预设参考板中。
与 advanced-line-usage 相比,这个示例更宽、更密。两个 demo 都使用内联数据,并且点击处理器都只输出到控制台,但 line 增加了更多可见变体、自定义 SVG marker 定义、深色主题切换,以及悬浮工具窗口。与 custom-line-style 相比,区别在于实现方式:custom-line-style 强调运行时的批量重设样式,而这个示例则从一开始就通过每条边的数据和 CSS 类,同时展示大部分变化。
与 line-style1 和 layout-center 相比,这个示例较少强调某一种狭义的预设线条族或整图级展示控制,而更强调把一个预设数据集当作广义的边行为展示板来使用。当团队想先对比 relation-graph 的内置线条能力,再决定是否进入自定义线条插槽或完整编辑器时,它会是一个很强的起点。
这种模式还适用于哪里
这种模式很适合迁移到那些“连接本身承载多重含义”的产品场景中。团队可以把它改造成用于工作流分支、依赖方向、网络路由、集成连接或血缘路径的 QA 面板,让每条边通过不同的宽度、箭头、锚位或标签规则来表达状态或语义。
它也适合作为内部文档。在设计自定义渲染器之前,团队可以先构建一个像这样紧凑的参考图,用来判断哪些需求已经被 relation-graph 的内置线条字段、CSS 主题能力和注入式 SVG marker 所覆盖。在培训材料中,同样的结构也可以作为可复用的边配置选项可视化目录。