性能模式测试-Tree
这个示例构建了 relation-graph 内置树布局在性能模式下的全屏压测场。它可按多种规模预设重新生成合成层级数据,保持自定义员工卡片节点和小地图启用,并允许在实时图上继续调整布局与连接器表现。
在性能模式下借助实时运行时控制对树形布局进行压力测试
这个示例构建了什么
这个示例构建的是一个全屏树形布局压力测试工作台,而不是面向具体业务的查看器。它会渲染一个合成层级结构,并配有自定义员工卡片风格节点、带彩色标签的连接线、一个悬浮控制窗口,以及右下角的迷你视图。
用户可以在六个数据集规模预设之间切换,重新调整树的方向和间距,实时修改连接线样式,改变画布的滚轮和拖拽行为,并导出图片。这个示例的重点在于:它在启用更丰富展示层的同时,使用 performanceMode 运行 relation-graph 内置的 tree 布局。
数据如何组织
数据起始于一个内联的 RGJsonData 种子对象,其中包含 rootId: 'a'、一个扁平的 nodes 数组,以及一个扁平的 lines 数组。这个种子本身已经形成一棵树,而 generateTestJsonData(testDataSize) 会先克隆它,再继续添加更多后代节点。
这里的预处理步骤很关键。对于每个 id 中包含 - 的节点,生成器都会继续追加更多子节点和边。当 testDataSize 大于 30 时,它会切换为两层的平方根扩展;否则就从 1 到 testDataSize 追加一层额外层级。扩展完成后,每个节点都会获得一个随机颜色和头像 URL,每条连线都会获得一个生成的 id、from > to 文本以及一个随机颜色。
在真实应用中,同样的数据结构可以代表大型组织架构图、分类树、文档层级、访问控制树,或任何在接入真实后端数据前用于测试布局可读性的生成式层级结构。
如何使用 relation-graph
这个示例包裹在 RGProvider 中,而 MyGraph 使用 RGHooks.useGraphInstance() 作为主要的运行时控制入口。基础 RGOptions 启用了矩形节点、正交连接线、内置 tree 布局、右上角工具栏位置、调试默认值,以及 performanceMode: true。
图谱逻辑被有意拆分为三条运行时路径。数据集规模变化时,会重新生成 JSON 数据、停止自动布局、清空图谱,通过 setJsonData(...) 重新加载数据,将视口移回中心、让图谱自适应显示,然后重新应用连线样式。布局变化时,则通过 updateOptions(...) 更新实时 layout 配置块,调用 doLayout(),并在不重建数据集的前提下重新让视口适配图谱。连线样式变化时,则遍历 getLines() 并原地应用 updateLine(...)。
插槽是展示层的核心。RGSlotOnNode 渲染 MyNodeSlot,它会把每个节点渲染成紧凑的员工卡片样式,并读取 node.data.pic 和 node.text。RGSlotOnView 挂载 RGMiniView,作为一个持续存在的总览组件。my-relation-graph.scss 中的样式去除了内置节点皮肤,通过 --rg-node-color 驱动节点边框,并让连线标签继承其连接线颜色。
悬浮的 DraggableWindow 是一个共享工具,但在这个示例里它之所以重要,是因为它承载了数据集选择器、可复用的 MyTreeGraphOptions 面板、一个会对实时图谱调用 setOptions(...) 的设置覆盖层,以及基于 prepareForImageGeneration() 和 restoreAfterImageGeneration() 的图片导出流程。
关键交互
最主要的交互是规模切换。点击六个预设按钮中的任意一个,都会改变 testDataSize,从而重建这个合成树并重新加载图谱。
第二个主要交互是运行时布局调优。用户可以在 left、right、top 和 bottom 之间切换树方向,修改水平和垂直节点间距,并立即在当前图谱上重新运行内置树布局。
第三个主要交互是实时连接线调优。同一个悬浮面板可以通过修改当前已挂载的连线,而不是重建图谱,来改变线条形状、正交圆角、连接点以及线条文本偏移。
辅助窗口本身也是可交互的:它可以被拖动、最小化、展开成画布设置覆盖层、在滚轮模式和拖拽模式之间切换,并用于下载渲染后的图片。节点点击和连线点击仅用于控制台检查,不会改变图谱。
关键代码片段
这个片段展示了示例如何启用内置 tree 布局,并配合固定矩形节点和 performanceMode。
const graphOptions: RGOptions = {
defaultNodeShape: RGNodeShape.rect,
defaultNodeWidth: 150,
defaultNodeHeight: 60,
defaultLineShape: RGLineShape.StandardOrthogonal,
defaultLineWidth: 3,
layout: {
layoutName: 'tree',
treeNodeGapH: 400,
treeNodeGapV: 10
},
performanceMode: true
};
这个片段证明了数据集在发送给 relation-graph 之前会先被克隆并扩展。
const data = JSON.parse(JSON.stringify(jsonData));
const newNodes = [];
const newLines = [];
for (const node of data.nodes) {
if (node.id.includes('-')) {
if (testDataSize > 30) {
const level1 = Math.sqrt(testDataSize);
for (let a = 1; a <= level1; a++) {
const aNodeId = node.id + '-' + a;
newNodes.push({ id: aNodeId, text: aNodeId });
newLines.push({ from: node.id, to: aNodeId });
这个片段展示了在规模预设改变时运行的重置并重新加载序列。
const initializeGraph = async () => {
const myJsonData = generateTestJsonData(testDataSize);
graphInstance.stopAutoLayout();
graphInstance.clearGraph();
await graphInstance.sleep(200);
await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();
updateData();
};
这个片段展示了布局方向和间距如何通过 updateOptions(...) 与 doLayout() 在实时图谱上更新。
graphInstance.updateOptions({
layout: {
layoutName: 'tree',
from: myTreeGraphOptions.layoutFrom,
treeNodeGapH: myTreeGraphOptions.rangeHorizontal,
treeNodeGapV: myTreeGraphOptions.rangeVertical
}
});
await graphInstance.doLayout();
graphInstance.moveToCenter();
graphInstance.zoomToFit();
这个片段展示了连接线样式变化是通过遍历已挂载的连线并逐条更新来实现的,而不是重建数据。
graphInstance.getLines().forEach((line) => {
graphInstance.updateLine(line, {
lineShape: myTreeGraphOptions.lineShape,
lineRadius: myTreeGraphOptions.lineRadius,
fromJunctionPoint: myTreeGraphOptions.junctionPoint,
toJunctionPoint: myTreeGraphOptions.junctionPoint,
textOffsetX: myTreeGraphOptions.textOffsetX,
textOffsetY: myTreeGraphOptions.textOffsetY,
placeText: (myTreeGraphOptions.lineShape === RGLineShape.StandardOrthogonal) ? 'end' : undefined
});
});
这个片段展示了基于插槽的展示层:视口中的迷你视图,以及针对每个树节点的自定义节点渲染器。
<RGSlotOnView>
<RGMiniView width="300px" height="150px" position="br" />
</RGSlotOnView>
<RGSlotOnNode>
{(nodeSlotProps: RGNodeSlotProps) => {
return <MyNodeSlot node={nodeSlotProps.node} />;
}}
</RGSlotOnNode>
这个示例的独特之处
对比数据把这个示例描述为一个内置树布局压力实验室,而不是外部布局集成或图编辑器。它最突出的少见组合包括:performanceMode、六个合成规模预设、实时树方向与间距控制、原地正交连线调优、自定义员工卡片节点插槽,以及同一张全屏画布上的 RGMiniView。
与 performance-test-force-layout 相比,它强调的是层级可读性和树专属展示控制,而不是力导系数或求解器时长。与 use-dagre-layout 和 use-dagre-layout-2 相比,当需求是在不断变化的规模下压测 relation-graph 自身的树布局,而不是引入外部坐标引擎时,它是更好的起点。
对比数据还强调了一个不太常见的搭配:随着层级扩展到面向性能的规模,这个示例依然保留了自定义插槽渲染卡片、按节点和连线随机着色,以及与连接线颜色同步的线标签。与 node 和 layout-center 相比,这让插槽和实时样式变更成为大型树工作负载实验的一部分,而不只是一个小型静态样式展示。
这种模式还适用于哪里
这种模式适用于组织架构图、角色层级、课程树、内容分类体系和文档映射在上线前的规模检查场景,因为团队需要在接入真实生产数据之前,先理解更丰富的树形展示会呈现出怎样的行为。
它同样适用于内部工具和 QA 工作流。数据重建、仅重布局更新、以及仅变更连线这三种路径的分离,对于希望在大型层级结构上受控测试间距预设、标签位置、连接线路由、导出行为或插槽渲染成本的团队也很有价值。