自定义全屏目标容器
这个示例展示如何通过 `fullscreenElementXPath` 将 relation-graph 内置全屏行为重定向到更大的外层容器。一个小型左到右树图位于说明头部与两侧面板之间,使全屏边界清晰可见,便于在更复杂页面布局中复用。
将全屏重定向到页面级图外层容器
这个示例构建了什么
这个示例在一个全页外层容器中构建了一棵小型的从左到右树形图,该容器还包含说明文字和两个固定侧边面板。可见界面刻意保持简洁:一个页头、一个绿色提示区块、中间的图,以及左右两侧的占位块。
用户可以点击节点并使用 relation-graph 内置工具栏。这里最重要的交互是全屏按钮,因为这个 demo 让全屏范围包含周围的外层内容,而不是只把图画布单独全屏。
重点不在树本身。重点在于当 relation-graph 进入全屏模式时,如何让相邻的页面 UI 继续保持可见。
数据是如何组织的
图数据直接在 initializeGraph() 中以内联方式声明为一个 RGJsonData 对象,包含 rootId: 'a'、一个扁平的 nodes 数组和一个扁平的 lines 数组。它描述了一棵紧凑的分支树,共有 16 个节点和 15 条连接。
在加载数据之前,代码会执行一步预处理:为任何尚未拥有 id 的 line 赋值 line-${index}。之后,这份数据集会直接传给 setJsonData(),中间没有 fetch 步骤、适配层或派生视图模型。
在真实应用中,同样的数据结构可以表示审批链、组件依赖树、组织分支,或任何其他需要出现在更大页面布局中的小型关系集合。
relation-graph 是如何使用的
index.tsx 使用 RGProvider 包裹整个示例,MyGraph.tsx 则通过 RGHooks.useGraphInstance() 获取当前激活的图实例。一个仅在挂载时执行的 useEffect() 会运行 initializeGraph(),随后通过 setJsonData()、moveToCenter() 和 zoomToFit() 加载内联数据集并规范化视口。
图本身被配置为一棵从左到右的树,参数包括 layoutName: 'tree'、from: 'left'、treeNodeGapH: 120 和 treeNodeGapV: 10。默认节点是矩形的 100x30 块,连线使用 RGLineShape.StandardCurve,连接点使用 RGJunctionPoint.lr,展开按钮位置设置在右侧。
最重要的选项是 fullscreenElementXPath: '#my-fullscreen-content'。它告诉 relation-graph 的内置全屏操作应当以外层包装元素为目标,而不是仅针对图元素本身,因此页头和两侧面板会与图一起进入全屏。
这个示例没有使用自定义 slots、编辑 API 或自定义工具栏逻辑。本地 SCSS 文件也只包含空的选择器骨架,因此最终可见效果主要来自图配置和外围的 flex 布局,而不是大量样式覆盖。
关键交互
- 点击内置工具栏中的全屏按钮后,整个
#my-fullscreen-content外层容器会进入全屏,因此页头和两侧面板会与图一起保持可见。 - 点击节点会触发
onNodeClick并记录节点文本。它不会改变渲染出的 UI,因此节点检查并不是这个示例的重点,全屏行为才是。
关键代码片段
这个外层结构说明,整个 demo 都运行在同一个 relation-graph provider 上下文中。
const Demo = () => {
return (
<RGProvider>
<MyGraph />
</RGProvider>
);
};
这个选项块证明,图本身保持了简单配置,而全屏则被重定向到一个更大的 DOM 容器。
const graphOptions: RGOptions = {
layout: {
layoutName: 'tree',
from: 'left',
treeNodeGapH: 120,
treeNodeGapV: 10
},
fullscreenElementXPath: '#my-fullscreen-content',
debug: false
};
这个片段展示了该示例如何以内联方式构建由扁平 nodes 和 lines 组成的 RGJsonData。
const myJsonData: RGJsonData = {
rootId: 'a',
nodes: [
{ id: 'a', text: 'a' },
{ id: 'b', text: 'b' },
{ id: 'b1', text: 'b1' }
],
lines: [
{ from: 'a', to: 'b' },
{ from: 'b', to: 'b1' }
]
};
这一步预处理会在数据集加载前补齐缺失的 line id。
myJsonData.lines.forEach((line, index) => {
if (!line.id) {
line.id = `line-${index}`;
}
});
这段初始化流程展示了在数据对象准备完成之后,图实例的完整工作流。
await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();
这段布局片段说明,全屏目标是一个包含说明内容和侧边面板的页面级外层容器,而不只是 RelationGraph 组件本身。
<div className="my-graph bg-white" id="my-fullscreen-content">
<div className="flex flex-col" style={{ height: '100vh' }}>
<div className="border-b">
<div className="p-4 text-xs">
<div className="font-bold text-sm">Customize the fullscreen display content using the fullscreenElementXPath option.</div>
</div>
</div>
<div className="grow flex">
<div className="bg-pink-200 w-36 shrink-0 flex place-items-center justify-center border-r border-gray-300">Left</div>
<RelationGraph options={graphOptions} onNodeClick={onNodeClick} />
<div className="bg-blue-200 w-36 shrink-0 flex place-items-center justify-center border-l border-gray-300">Right</div>
</div>
</div>
</div>
这个示例的独特之处
对比数据清楚地说明了它的核心差异:这个示例的重点并不主要在树布局、命令式图控制或 slot 放置上。它最独特的启示是,relation-graph 的全屏可以被重定向到外层容器,因此周围的页面内容仍然能成为全屏体验的一部分。
与 graph-instance-api 相比,它使用了非常相似的 provider 与实例配合方式,也采用了相近的树形骨架,但在加载完成后对图状态的操作要少得多。与 adv-hide-2-show 相比,它关注的不是隐藏容器中的延迟挂载。与 built-in-slots 相比,这里的辅助 UI 是位于 RelationGraph 外部、普通的页面级同级 DOM,而不是注入到图自身 view 或 canvas 层中的 HTML。
这种由朴素三栏外层结构、小型从左到右树形图以及 fullscreenElementXPath 组成的组合,使这个示例更适合作为以下需求的起点:“我的图位于一个更大的页面中,而全屏时也应该包含这个更大的页面。”
这种模式还适用于哪里
这种模式很适合迁移到以下场景:带持久图例的架构查看器、带证据侧边栏的案件审查页面、带摘要面板的组织树页面,以及带页头说明或筛选器的监控仪表板。在这些迁移场景中,图本身可以继续保持技术上简单,而全屏行为仍然尊重周围布局。
它也适用于需要在图旁边放置说明文字的文档和引导页面。可复用的思路是选择一个包含所有需要在全屏后继续可见的 UI 元素的外层容器,然后将 fullscreenElementXPath 指向这个容器。