JavaScript is required

默认折叠的可展开树图

这个示例展示如何在 `setJsonData()` 后立即折叠指定分支,并通过后续节点点击逐步展开。它是预加载层级上的渐进披露参考,包含自动重布局及共享画布设置与导出工具。

构建一个初始折叠并可渐进展开的树

这个示例构建了什么

这个示例构建了一个小型的从左到右树形查看器,并且初始状态下部分分支处于折叠状态。用户首先看到的是一个紧凑的橄榄黄色层级结构,包含矩形节点、正交连线以及位于右侧的展开控件;随后可以通过点击已折叠节点来显示隐藏分支。这个示例的重点并不是通用的树渲染,而是一套明确的启动流程:一次性加载完整数据集,在代码中折叠选定节点,然后让图谱以渐进披露浏览器的方式运行。

数据是如何组织的

图数据以内联 RGJsonData 的形式声明,包含 rootId: 'a'、一个扁平的 nodes 数组以及一个扁平的 lines 数组。这个示例没有使用嵌套的 children;每一条关系都通过明确的 fromto id 表达,因此按节点 id 执行折叠步骤会很容易定位。

setJsonData() 之后有一个重要的预处理步骤:代码使用 getNodeById() 查找 abc,并在第一次稳定布局之前先折叠这些节点。这意味着查看器的初始状态并不是原始的完整可见图,而是一个经过刻意设计的信息披露状态。

在生产场景中,同样的数据结构可以表示组织分支、课程大纲、产品分类树、故障排查流程,或者任何完整图谱已经已知、但不应一次性全部展示出来的层级结构。

relation-graph 是如何使用的

该图使用 layoutName: 'tree' 并设置 from: 'left',因此层级会以从左到右的方式水平阅读。defaultLineShapeRGLineShape.StandardOrthogonaldefaultJunctionPointRGJunctionPoint.lrdefaultExpandHolderPosition'right',从而使整体视觉语言与水平树保持一致。示例还为节点和连线设置了匹配的橄榄黄色默认样式,并通过本地 SCSS 覆盖确保节点文字在较深的填充色上仍保持白色。

RGHooks.useGraphInstance() 是主要的集成入口。示例通过图实例加载内联数据、按 id 定位特定节点、折叠这些节点、执行 doLayout()、将结果居中、缩放到适应视口,并在后续的 onNodeClick 中展开已折叠分支。由于图选项中启用了 reLayoutWhenExpandedOrCollapsed,因此在点击处理器内部不需要为分支展开编写手动布局代码。

这里没有使用自定义节点、连线、画布或视口插槽,也没有编辑工作流。相反,外围 UI 来自一个共享的 DraggableWindow 辅助组件。该辅助组件增加了一个浮动说明窗口、一个基于 RGHooks.useGraphStore() 的设置面板、对滚轮和拖拽行为的实时 setOptions() 调用,以及一个基于 prepareForImageGeneration()restoreAfterImageGeneration() 的导出流程。这些工具很有用,但它们属于共享脚手架,而不是这个示例最核心的独特行为。

关键交互

  • 只有当 node.expanded === false 时点击节点才会展开它,因此这个示例的行为是单向展开查看器,而不是完整的点击切换树。
  • 由于启用了 reLayoutWhenExpandedOrCollapsed,树在展开或折叠状态变化后会自动重新排布。
  • 浮动辅助窗口可以拖动或最小化,因此说明和工具始终可用,同时不会持续占据画布空间。
  • 设置面板可以在运行时切换滚轮和拖拽行为,并将当前图谱下载为图片。

关键代码片段

这段代码展示了该 demo 被配置为一个水平正交树,并在右侧使用内置展开控件。

const graphOptions: RGOptions = {
    debug: false,
    layout: {
        layoutName: 'tree',
        from: 'left',
    },
    defaultNodeShape: RGNodeShape.rect,
    defaultLineShape: RGLineShape.StandardOrthogonal,
    defaultJunctionPoint: RGJunctionPoint.lr,
    defaultExpandHolderPosition: 'right',
    reLayoutWhenExpandedOrCollapsed: true,

这段代码说明完整数据集会先被加载,然后再按节点 id 有选择地折叠节点。

await graphInstance.setJsonData(myJsonData);
['a', 'b', 'c'].forEach(nodeId => {
    const node = graphInstance.getNodeById(nodeId);
    if (node) {
        graphInstance.collapseNode(node);
    }
});

这段代码展示了显式的启动顺序,它会在交互开始之前稳定初始折叠视图。

await graphInstance.doLayout();
graphInstance.moveToCenter();
graphInstance.zoomToFit();

这段代码表明,节点点击只会显示已折叠分支,而不会再次折叠已经展开的分支。

const onNodeClick = async (node: RGNode, $event: RGUserEvent) => {
    const isExpanded = node.expanded;
    if (isExpanded === false) {
        graphInstance.expandNode(node);
    }
};

这段代码展示了浮动设置面板如何通过实时更新选项来改变 relation-graph 行为,而不是重新构建图谱。

<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 }); }}
/>

这个示例的独特之处

这个示例之所以独特,是因为它聚焦于一种非常具体的信息披露模式:整个树在初始数据集中就已经完整存在,选定分支会在 setJsonData() 之后立即被折叠,并且初始视图会在用户开始浏览之前先完成稳定布局。因此,它是一个关于程序化启动折叠的聚焦参考,而不是通用树渲染示例。

open-by-level 相比,它强调的是通过直接点击节点逐支显示分支,而不是为整棵树重新计算披露层级深度。与 expand-button 相比,它显示的是已经加载好的后代节点,而不是之后再惰性加载新的子节点。与 graph-instance-apitree-data 相比,它不只是一个简单的实例方法 demo 或被动的树加载示例,而是把启动折叠加节点点击展开作为核心教学流程。

浮动辅助窗口及其设置/导出控件虽然有用,但并不是这里的核心差异点,因为这套外壳也被其他 demo 共享。这个示例最有代表性的组合是:预加载的扁平树、选择性的启动折叠、单向点击展开,以及在一个紧凑的从左到右查看器中的自动重新布局。

这种模式还适用于哪里

这种模式适用于这样一些场景:完整层级已经可用,但如果一开始就显示所有分支,会让用户不堪重负。典型例子包括入门知识地图、部门浏览器、课程模块树、产品分类导航以及故障隔离指南。

当初始界面需要只突出主要决策,同时让细节按需可发现时,这种模式也很合适。如果后续版本需要远程加载分支,这个示例可以作为 UI 基线,然后再把显示逻辑切换为基于 onNodeExpand 的数据获取流程。