JavaScript is required

发光图标节点树样式

这是一个静态的左到右 relation-graph 示例,使用可复用的“图标+文字”节点插槽渲染深色霓虹树图。它还演示了基于 CSS 的选中态主题、用于切换滚轮与拖拽模式的悬浮设置窗,以及画布图片导出。

带自定义图标节点的暗色霓虹树形查看器

这个示例构建了什么

这个示例构建了一个静态的从左到右树形查看器,带有深色径向画布和一个可复用的自定义节点模板。图谱会加载一份内联的类层级数据,将其居中、缩放到适合视图,并把每个节点渲染成一个发光胶囊,内部组合了 LandPlotIcon 和节点标签。一个悬浮工具窗口始终位于画布上方,因此用户可以阅读说明、打开设置面板、切换滚轮和拖拽行为,并将当前图谱导出为图片。这个示例最值得注意的表现细节是:连线标签默认保持隐藏,直到 relation-graph 将某条线标记为 checked 才会显示。

数据是如何组织的

数据在 initializeGraph() 内部以内联方式声明为一个 RGJsonData 对象,其中包含 rootIdnodeslines。在调用 setJsonData 之前没有 fetch 步骤,也没有预处理流程;这个示例只是构造了这个字面量对象,然后直接把它发送给图谱实例。

不过,这个结构仍然比普通树形稍微复杂一些。大多数连线都从 base 节点发出,但也有几条线回指到根节点,另一个分支还从 H-7-1H-7-2 指向节点 7。在真实产品里,这种形状可以表示一个同时包含上游和下游汇报关系的组织视图、一个带反向调用者的服务依赖图,或一个以中心项为核心同时存在出入关系的审核工作流。

relation-graph 的使用方式

index.tsxRGProvider 包裹这个示例,使 relation-graph hooks 同时对主图组件和共享的悬浮设置面板可用。在 MyGraph.tsx 中,RelationGraph 接收了一个聚焦的 graphOptions 对象:树形布局、从左到右方向、较宽的横向间距、紧凑的纵向间距、圆形节点几何、曲线连线、左右连接点锚位,以及透明的默认节点外观,这样最终视觉效果就由自定义 slot 和 SCSS 控制。

这个示例在两个地方使用了 RGHooks.useGraphInstance()。在 MyGraph 中,这个 hook 会在挂载后通过 setJsonData() 加载内联数据集,然后调用 moveToCenter()zoomToFit()。在 CanvasSettingsPanel 中,同一个 hook 则驱动运行时行为:它通过 setOptions() 更新 wheelEventActiondragEventAction,通过 prepareForImageGeneration() 为导出做准备,通过 getOptions() 读取当前背景,并在截图完成后通过 restoreAfterImageGeneration() 还原图谱。这里还使用了 RGHooks.useGraphStore(),从而让面板能够反映当前的交互设置。

本地代码里唯一的自定义图谱 slot 是 RGSlotOnNode。它替换了默认节点主体,为所有节点渲染同一套 React 片段,包括图标和文本。这里没有本地的连线 slot、画布 slot、视口 slot、显式图谱事件处理器,也没有编辑 API。大部分视觉定制都发生在 my-relation-graph.scss 中,它覆盖了 relation-graph 的类名,例如 .rg-map.rg-node-peel.rg-line-peel.rg-node-checked.rg-line-checked

关键交互

  • 图谱会在挂载时初始化,加载静态数据集,将根节点簇移动到中心,并缩放到适合完整结构。
  • 悬浮说明窗口可以通过标题栏拖动,并且在设置面板关闭时可以最小化。
  • 齿轮按钮会打开设置浮层,点击半透明背景会再次将其关闭。
  • 设置浮层会在 scrollzoomnone 之间切换 wheelEventAction
  • 同一个浮层会在 selectionmovenone 之间切换 dragEventAction
  • Download Image 操作会先准备图谱画布,再使用 modern-screenshot 进行截图、下载 blob,最后恢复图谱状态。
  • 样式表定义了 checked 状态反馈:checked 节点会切换为绿色辉光,checked 连线会显示带绿色背景的标签。

关键代码片段

这个片段展示了示例如何移除库默认的节点外观,因此最终可见的节点渲染完全由 slot 标记和 SCSS 决定。

const graphOptions: RGOptions = {
    backgroundColor: '#004466',
    defaultLineColor: 'rgba(255, 255, 255, 0.6)',
    defaultNodeColor: 'transparent',
    defaultNodeBorderWidth: 0,
    defaultNodeBorderColor: 'transparent',
    defaultNodeShape: RGNodeShape.circle,
    defaultLineShape: RGLineShape.StandardCurve,
    defaultJunctionPoint: RGJunctionPoint.lr,
};

这个片段展示了创建从左到右层级视图的树形布局设置。

layout: {
    layoutName: 'tree',
    from: 'left',
    treeNodeGapH: 140,
    treeNodeGapV: 10
}

这个片段展示了这个数据集如何围绕根节点混合出向关系和入向关系,而不是建模为一棵严格单向的树。

lines: [
    { id: 'l1', from: 'base', to: '1', text: 'Line X01' },
    { id: 'l5', from: '5', to: 'base', text: 'Incoming Line X05' },
    { id: 'l6', from: '6', to: 'base', text: 'Incoming Line X06' },
    { id: 'l1-01', to: '7', from: 'H-7-1', text: 'Line X7-1' },
    { id: 'l1-07', to: 'H-7-21', from: 'H-7-211', text: 'Line X7-21-1' }
]

这个片段展示了那个唯一可复用的节点 slot,它为所有节点提供相同的图标加标签主体。

<RGSlotOnNode>
    {(nodeSlotProps) => {
        const { node } = nodeSlotProps;
        return (
            <div className="my-icon-node gap-2 flex rounded-full place-items-center justify-center">
                <LandPlotIcon size={10} />
                {node.text}
            </div>
        );
    }}
</RGSlotOnNode>

这个片段展示了导出流程如何在截图前后调用 relation-graph 实例 API。

const canvasDom = await graphInstance.prepareForImageGeneration();
let graphBackgroundColor = graphInstance.getOptions().backgroundColor;
if (!graphBackgroundColor || graphBackgroundColor === 'transparent') {
    graphBackgroundColor = '#ffffff';
}
const imageBlob = await domToImageByModernScreenshot(canvasDom, {
    backgroundColor: graphBackgroundColor
});
await graphInstance.restoreAfterImageGeneration();

这个片段展示了与选择相关的连线样式:标签默认隐藏,只有在 checked 状态下才会显示。

.rg-line-peel {
    .rg-line-label {
        display: none;
    }
}

.rg-line-peel.rg-line-checked {
    .rg-line-label {
        display: block;
        background-color: #028c02;
    }
}

这个示例的独特之处

根据整理好的对比数据,这个示例并不只是另一个节点样式演示。它最强的差异化在于聚焦:它没有比较多种 slot 变体,而是使用一种一致的图标加文本节点族,同时把这种节点处理方式与深色径向画布、青色辉光样式、绿色 checked 状态反馈以及“仅在 checked 时显示”的边标签结合起来。

这让它与附近的示例形成了明确区别。和 node-style2 相比,它从仅用 CSS 对默认节点渲染器做皮肤定制,转向了完全基于 slot 的节点渲染,同时保留了相同的静态查看模式。和 node-style3 相比,它放弃了力导布局的动态感以及基于元数据的图标多样性,换成了更平稳的从左到右层级视图,并提供更强的 checked 状态连线反馈。和 node-style 相比,它的重点不在于展示许多 slot 模板,而在于打磨一套可在整张图中复用的统一视觉系统。

对比数据也提醒不要夸大它的独特性。悬浮设置窗口和图片导出流程来自相邻示例中复用的共享演示脚手架,因此 node-style4 的真正价值在于:在一个统一主题里,把单一自定义节点 slot、透明的内建节点外观,以及具备选择感知的连线标签显隐机制组合到了一起。

这种模式还适用于哪里

这种模式非常适合那些需要精致的只读关系视图、但又不想构建编辑器的仪表板。典型场景包括团队或组织查看器、系统依赖图、资产血缘树、审批链,以及要求整个图中节点家族始终保持一致视觉风格的拓扑总览。

它也很适合关系元数据在用户聚焦某条边之前都应保持低调的场景。checked 状态下才显示标签的方式,可以在稠密图中减少杂乱,同时在需要时仍然暴露连线名称。悬浮设置与导出面板也可以复用到内部工具中,用于快速截图,或临时切换交互模式,而无需在画布本身加入永久性的工具栏外观。