点击线条高亮线条及端点节点
这个示例展示一棵自上而下树图:点击关系线可高亮该线及其两个端点节点。它使用 relation-graph 实例 API 重置上次状态、运行时应用临时 class,并在点击画布背景时清除高亮。
高亮被点击的连线及其端点节点
这个示例构建了什么
这个示例构建了一个紧凑的自上而下树形查看器,其中可选中的对象是关系连线本身。界面展示为一个间距较宽的正交层级结构,带有小型紫色节点标签、可见的连线标签,以及位于全高画布上方的浮动辅助窗口。
当用户点击某条连线时,这个示例会加宽该连线,将其标签块切换为深紫色样式,并为这条连线的两个端点节点添加环形高亮。点击空白画布会清除这种临时强调状态。最关键的一点是,高亮从边开始,再传播到恰好两个节点,而不是从节点悬停开始,也不会扩展到整个分支。
数据是如何组织的
图以内联方式组装为一个 RGJsonData 对象,其中包含 rootId、扁平的 nodes 数组和扁平的 lines 数组。每个节点都有稳定的 id 和 text,每条连线也都有自己的 id、from、to 以及标签文本。这个示例在调用 setJsonData 之前不会做任何结构预处理;它直接在 initializeGraph() 中准备数据集,并按原样加载。
这种结构可以很好地映射到真实的关系型数据集,例如服务依赖、审批链、组织汇报线或设备连接。在生产代码中,同样的数据形态可以由 API 记录构建出来,但只要连线端点保持稳定 id,交互逻辑就能保持不变。
relation-graph 是如何使用的
这个演示使用了 RGProvider,这样示例组件和共享的浮动工具面板都可以通过 hooks 解析到同一个图实例。在 MyGraph 内部,使用 RGHooks.useGraphInstance() 来加载数据、让图适配视图、重置 class,并在用户操作后更新实时节点和连线。
图配置刻意保持布局稳定:它使用内置的 tree 布局,自上而下流动,分支在横向和纵向都保持 150 像素的间距,并通过 RGLineShape.SimpleOrthogonal 加上 RGJunctionPoint.tb 来布线。默认节点外观被设为透明,因为可见的节点主体来自 RGSlotOnNode,它会为每个节点标签渲染一个自定义的圆角标签块。
这个示例还使用 relation-graph 的运行时 API,而不是在每次交互后重建整个数据集。getLines() 和 updateLine() 用于清除上一条连线的状态并为被点击的关系设置样式,而 getNodes() 和 updateNode() 用于应用或移除端点高亮 class。共享的 CanvasSettingsPanel 使用 useGraphInstance() 和 useGraphStore() 来暴露滚轮模式、拖拽模式和图片导出,但这些控件只是辅助脚手架,并不是本示例的主要教学点。
关键交互
点击关系连线是主要交互。处理函数会先清除之前的自定义高亮,然后按 id 找到被点击的连线,增加其宽度,应用 my-line-highlight class,并且只高亮两个相连的节点。
点击画布背景是重置交互。它会清除 relation-graph 的 checked 状态,并执行同一套高亮重置流程,因此临时强调状态不会在多次选择之间累积。
浮动辅助窗口可以拖动和最小化,它的设置按钮会打开共享画布控件,用于调整滚轮行为、拖拽行为和图片下载。这些控件会影响查看环境,但不会改变示例的图数据或高亮范围。
关键代码片段
这个 options 配置块说明,该示例是一个固定的自上而下树形图,使用正交连线,并且默认节点外观为透明。
const graphOptions: RGOptions = {
defaultNodeColor: 'transparent',
defaultNodeBorderWidth: 0,
defaultNodeBorderColor: 'transparent',
defaultLineColor: 'rgba(128, 128, 255)',
defaultNodeShape: RGNodeShape.rect,
toolBarDirection: 'h',
toolBarPositionH: 'right',
toolBarPositionV: 'bottom',
defaultPolyLineRadius: 10,
defaultLineShape: RGLineShape.SimpleOrthogonal,
defaultLineWidth: 1,
defaultJunctionPoint: RGJunctionPoint.tb,
// ...
};
这个数据集片段表明,图使用了一个内联树形载荷,其中包含稳定的节点 id 和显式的连线端点。
const myJsonData: RGJsonData = {
rootId: 'a',
nodes: [
{ id: 'a', text: 'a', data: { icon: 'align_bottom' } },
{ id: 'b', text: 'b', data: { icon: 'basketball' } },
// ...
],
lines: [
{ id: 'l1', data: { 'myLineId': 'line1' }, from: 'a', to: 'b', text: 'Relation Description' },
{ id: 'l2', data: { 'myLineId': 'line2' }, from: 'b', to: 'b1', text: 'Relation Description' },
// ...
],
};
这段事件流程就是核心模式:清除之前的状态,为一条被点击的边设置样式,然后把高亮传播到它的端点。
const onLineClick = (clickedLine: RGLine) => {
clearHighlightStatus();
graphInstance.getLines().forEach(line => {
if (clickedLine.id === line.id) {
graphInstance.updateLine(line, {
className: 'my-line-highlight',
lineWidth: 3
});
}
});
graphInstance.getNodes().forEach(node => {
if (clickedLine.from === node.id || clickedLine.to === node.id) {
graphInstance.updateNode(node, { className: 'my-node-highlight' });
}
});
};
这组 slot 与 SCSS 的配合展示了该示例如何替换默认节点主体,并把可见的端点强调附加到渲染出来的节点外壳上。
<RelationGraph options={graphOptions} onLineClick={onLineClick} onCanvasClick={onCanvasClick}>
<RGSlotOnNode>
{({ node }: RGNodeSlotProps) => (
<div className="px-2 bg-purple-200 rounded">
<div className="my-node">
{node.text}
</div>
</div>
)}
</RGSlotOnNode>
</RelationGraph>
.rg-node-peel.my-node-highlight {
.rg-node {
box-shadow: 0px 0px 0px 5px rgba(75, 28, 119, 1);
}
}
.rg-line-peel.my-line-highlight {
.rg-line-label {
color: #ffffff;
background-color: rgba(75, 28, 119, 1);
}
}
这个示例的独特之处
与附近的示例(如 line-hightlight、deep-each 和 custom-line-style)相比,这个示例最适合“关系本身”必须作为交互目标的场景。它不是从节点悬停开始,也不会递归遍历整个子树,更不会切换全图范围的连线皮肤。相反,它保持布局固定,并把一条被点击的内置连线变成该连线及其恰好两个节点的临时检查状态。
对比信息还表明,显式的画布重置流程也是这个示例突出的原因之一。在一个带有共享工具脚手架的小型查看器演示中,它把宽间距正交树、通过 slot 渲染的紫色节点标签、从边开始的选择、端点节点环形高亮,以及背景点击重置组合成了一种非常聚焦的关系检查模式。
因此,当可选对象是边时,它比 line-hightlight 更适合作为起点;而当期望的作用范围是局部端点强调而不是整条分支的聚焦时,它又比 deep-each 更适合作为参考。
这种模式还适用于哪里
这种模式很适合迁移到依赖关系图中,在这类场景里,点击一条连接应该只揭示被该依赖直接绑定的两个服务。它也适用于工作流或审批图,其中边表示一个需要被检查的交接动作,但又不希望改变图中其他部分的状态。
同样的方法也适用于数据血缘查看器、网络链路检查以及故障排查界面,在这些场景中,用户需要快速回答“这条连接绑定的是哪两个实体?”而不必展开整个邻域。如果产品后续需要更多上下文,这种从边开始的高亮还可以扩展为侧边面板、详情弹出层或多步下钻,同时继续保持相同的 getLines() 和 getNodes() 更新模式。