直接用层级数据加载树图
这个示例展示如何将嵌套层级 RGJsonData 直接传入 relation-graph,并渲染为左到右树图,无需手动编写连线记录。它也演示了标准的 provider 作用域初始化流程,以及用于画布模式切换和图片导出的共享查看器工具。
直接从层级数据加载一棵从左到右的树
本示例构建了什么
本示例将一个小型层级结构渲染为一棵从左到右展开的树,使用矩形节点和正交连线。页面主体几乎是一个全高图谱画布,上方悬浮着一个说明窗口。用户可以查看已准备好的树、拖动或最小化辅助窗口、打开画布设置并导出图片,但示例本身没有加入示例专属的节点编辑或分支控制逻辑。它的重点更聚焦:层级数据是用嵌套的 children 数组直接编写的,而不是先手动拍平成节点和连线数据集。
数据如何组织
数据集以内联方式声明为一个 RGJsonData 对象,包含 rootId、一个 nodes 数组,以及每个父节点下递归的 children 字段。lines 数组被有意留空,因此组件传给 relation-graph 的是层级树形结构,而不是显式的边记录。
在调用 setJsonData() 之前没有任何预处理。该示例依赖 relation-graph 识别这棵嵌套树,并在内部将其拍平后再渲染。在真实应用中,同样的数据形态可以表示组织架构、文件夹树、商品分类、物料清单结构或审批链。示例中的说明也指出了一个重要取舍:当以这种形式直接使用树数据时,输入载荷中的每一条连线都不能单独设置样式。
relation-graph 的使用方式
这个 demo 使用标准的 React provider 模式:index.tsx 用 RGProvider 包裹 MyGraph,而 MyGraph.tsx 通过 RGHooks.useGraphInstance() 读取当前激活的图谱实例。图谱选项配置了 tree 布局,将起点设在左侧,使用 treeNodeGapH = 150 和 treeNodeGapV = 20,并保持几何外观简洁:矩形节点、100 像素节点宽度、正交连线、左右连接点,以及位于右侧的展开控制柄。
图谱实例 API 完成了大部分实际工作。组件挂载后,会用这份内联层级数据调用 setJsonData(),随后调用 moveToCenter() 和 zoomToFit(),使首次渲染时视图就已经正确取景。额外的运行时工具只来自共享的 DraggableWindow 辅助组件。这个辅助组件使用 RGHooks.useGraphStore() 读取当前画布行为,通过 graphInstance.setOptions() 切换滚轮和拖拽模式,并在 modern-screenshot 的截图流程前后调用 prepareForImageGeneration() 和 restoreAfterImageGeneration()。
本示例没有自定义节点、连线、画布或视口插槽,也没有编辑工作流。SCSS 文件主要只有空的选择器骨架,因此最终外观更接近 relation-graph 默认样式,而不是一套自定义皮肤。
关键交互
第一个交互是自动发生的,而不是手动触发:树会在 useEffect() 中加载,视口随后立即居中并适配内容。之后,这张图谱的行为更像一个查看器。
悬浮的辅助窗口是主要的交互覆盖层。它的标题栏可以拖动,也可以最小化和恢复;其设置面板可以把滚轮行为在 scroll、zoom 和 none 之间切换,也可以把画布拖拽行为在 selection、move 和 none 之间切换。这个面板还可以把当前图谱导出为图片。示例本身没有添加节点点击处理、加载后的展开或折叠规则、行内编辑,或任何自定义选择行为。
关键代码片段
这段选项代码建立了从左到右的树形几何布局,以及默认的节点和连线样式。
const graphOptions: RGOptions = {
debug: false,
layout: {
layoutName: 'tree',
from: 'left',
treeNodeGapH: 150,
treeNodeGapV: 20,
},
defaultExpandHolderPosition: 'right',
defaultNodeShape: RGNodeShape.rect,
defaultNodeWidth: 100,
defaultLineShape: RGLineShape.StandardOrthogonal,
};
这段内联载荷展示了核心的数据形态模式:层级结构直接通过嵌套的 children 数组来编写。
const myJsonData: RGJsonData = {
rootId: 'a',
nodes: [
{
id: 'a', text: 'a', children: [
{
id: 'b', text: 'b', children: [
{
id: 'b1', text: 'b1', children: [
这段挂载阶段的代码把层级数据交给 relation-graph,并立即让初始视图适配到合适位置。
await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();
useEffect(() => {
initializeGraph();
}, []);
这一行设置代码说明,悬浮辅助窗口可以通过 setOptions() 动态修改画布行为。
<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 }); }}
/>
这段导出流程会先让图谱画布进入可截图状态,再用 modern-screenshot 渲染,最后恢复图谱状态。
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();
这个示例的独特之处
对比数据将这个示例定位为“直接输入层级数据”的最小基线。它最鲜明的组合特征是:嵌套的 RGJsonData 载荷、空的 lines 数组、朴素的从左到右正交树形布局,以及几乎没有自定义 SCSS 或插槽渲染。对于一个仍然包含共享悬浮工具窗口的 demo 来说,这里的图谱专属逻辑也异常收敛:只有一次启动加载流程,再加上一组继承来的查看器工具能力。
与 tree-distance 相比,这个示例关注的是验证“直接输入层级数据”这一路径,而不是比较运行时的间距策略。与 expand-gradually 和 open-by-level 相比,它在初始化后让层级结构保持被动可见,而不是在扁平的节点与连线数据集之上继续叠加分支状态逻辑、点击展开行为或深度重置。与 line-style1 相比,它去掉了显式的连线记录和自定义节点视觉,因此当问题只是“业务中的嵌套数据能否先不做额外转换就渲染成一棵树”时,它会是一个更干净的起点。
这一模式还能用在哪里
- 在引入自定义卡片或编辑能力之前,直接把嵌套 API 返回渲染为组织架构图。
- 当源数据本身就是层级结构时,用来展示文件夹结构、商品分类或物料清单树。
- 在项目早期先验证从左到右的树布局,再决定是否需要显式连线记录来支持按边设置样式。
- 先构建一个朴素的层级查看器,后续再逐步加入更丰富的节点模板或分支交互,以此形成迁移路径。