导出完整图谱图片
这个示例展示如何通过自定义 UI 将完整 relation-graph 场景导出为可下载图片。它加载静态左到右树图,先准备图谱捕获状态,再用 modern-screenshot 将准备后的 DOM 转为 blob,并在下载流程完成后恢复图状态。
将完整关系图导出为可下载图像
这个示例构建了什么
这个示例构建了一个只读的 relation-graph 查看器,其主要职责是将整张图导出为图像文件。页面展示了一棵从左到右的树,包含白色矩形节点、带标签的曲线连线、一个浮动说明窗口,以及位于底部迷你工具栏中的自定义图像按钮。
用户可以从两个位置触发同一套导出流程:浮动面板和附着在图上的迷你工具栏。关键结果是,导出不依赖当前缩放级别或可见视口,因为图会在截图前专门为图像生成做好准备。
数据是如何组织的
图数据是在 initializeGraph() 内部声明的一个内联 RGJsonData 对象。它包含一个 rootId、一个扁平的 nodes 数组,以及一个扁平的 lines 数组,其中每条线都已经有自己明确的 id。
在调用 setJsonData() 之前没有繁重的预处理步骤。唯一的准备工作是在代码中定义这份数据集,将其加载到实例中,然后将图居中并适配显示。在真实应用中,同样的数据形态可以表示产品结构、制造系统、子系统拆解、依赖树,或任何需要可用于报告快照的层级结构。
relation-graph 是如何使用的
这个示例将 relation-graph 用作一个树形查看器,并显式控制布局与导出生命周期。图通过 layoutName: 'tree'、from: 'left' 以及固定的 levelGaps 进行配置,因此结果是一个宽幅的技术树,而不是力导向图。
图选项定义了大部分视觉语言:白色矩形节点、曲线连线、左右连接点、沿路径渲染的线文本,以及 showToolBar: false,使默认工具栏不会与自定义导出控件相互干扰。数据加载完成后,代码会调用 moveToCenter() 和 zoomToFit(),让场景立即进入适合展示的状态。
这个示例也直接使用了 relation-graph 的插槽和钩子。RGHooks.useGraphInstance() 提供对 setJsonData()、moveToCenter()、zoomToFit()、prepareForImageGeneration() 和 restoreAfterImageGeneration() 的访问。RGSlotOnView 配合 RGMiniToolBar 将一个自定义导出按钮注入到视口层中,因此即使内置工具栏被禁用,该操作仍然附着在图本身上。
浮动辅助窗口来自一个共享的本地组件。在这个示例中,它不只是说明性的界面元素:它增加了第二个导出入口,暴露了一个设置覆盖层,并使用 graphInstance.setOptions() 在运行时修改 wheelEventAction 和 dragEventAction。
关键交互
主要交互是图像导出。点击浮动面板中的 Download Image,或点击底部迷你工具栏中的红色图像图标,都会运行同一套截图工作流。
浮动窗口本身也可交互。它可以被拖动、最小化,并切换到设置覆盖层。该覆盖层会在滚动、缩放和无之间切换滚轮行为,并在选择、移动和无之间切换画布拖拽行为,然后在需要时再次执行导出操作。
图数据会在挂载时自动加载,然后居中并适配到视口。这意味着用户在生成完整场景图像前,不需要手动平移或缩放。
关键代码片段
这个片段表明,该示例有意将其配置为一棵从左到右的树,样式克制,并且没有内置工具栏。
const graphOptions: RGOptions = {
reLayoutWhenExpandedOrCollapsed: true,
defaultExpandHolderPosition: 'right',
defaultNodeShape: RGNodeShape.rect,
defaultNodeBorderWidth: 1,
defaultNodeColor: '#fff',
defaultLineShape: RGLineShape.Curve2,
defaultJunctionPoint: RGJunctionPoint.lr,
defaultLineTextOnPath: true,
layout: { layoutName: 'tree', from: 'left', levelGaps: [400, 400, 400, 400] },
showToolBar: false
};
这个片段证明,图内容是以内联 RGJsonData 的形式植入的,并且会在视口对齐前通过程序加载。
const myJsonData: RGJsonData = {
rootId: '2',
nodes: [
{ id: '2', text: 'ALTXX' }, { id: '3', text: 'CH2 TTN' }, { id: '4', text: 'CH1 AlCu' },
// ...
],
lines: [
{ id: 'l1', from: '2', to: '5', text: 'Subsystem' },
// ...
]
};
await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();
这个片段是导出流程的核心:relation-graph 先准备场景,modern-screenshot 将 DOM 转成 blob,之后再恢复图状态。
const downloadImage = async () => {
const canvasDom = await graphInstance.prepareForImageGeneration();
const imageBlob = await domToImageByModernScreenshot(canvasDom, {
backgroundColor: '#ffffff'
});
if (imageBlob) {
downloadBlob(imageBlob, 'my-image-name');
}
await graphInstance.restoreAfterImageGeneration();
};
这个片段展示了该示例如何通过视图插槽添加一个附着在图上的导出控件,而不是依赖默认工具栏。
<RelationGraph options={graphOptions}>
<RGSlotOnView>
<RGMiniToolBar positionV='bottom' direction='v'>
<div
className="w-8 h-8 border rounded flex place-items-center justify-center bg-red-700 animate-pulse text-white cursor-pointer hover:text-yellow-200 hover:animate-none"
onClick={downloadImage}
>
<ImageIcon size={20} />
</div>
</RGMiniToolBar>
</RGSlotOnView>
</RelationGraph>
这个片段表明,共享辅助组件是该示例实际行为的一部分,因为它会通过图实例修改运行时的画布交互模式。
<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 }); }}
/>
这个示例的独特之处
与其他 generate-image-* 示例相比,这个示例更偏向交付结果,而不是预览结果。捕获后的结果会立即以 blob 的形式下载,而不是作为 Base64 文本或内联预览保存在组件状态中。
它最强的差异点在于导出入口。内置工具栏被禁用,但该示例仍然通过将 RGSlotOnView 与底部 RGMiniToolBar 结合,直接在图视口内部放置了一个自定义导出操作。对比数据将这种图内集成的导出能力标记为这个导出集群中最少见的特征之一。
它也比那些装饰性截图变体更聚焦于干净的报告输出。对比记录显示,相邻示例更强调水印、图案背景或仅视口截图,而这个示例保持中性的白色背景,并提前准备完整图,因此用户在导出前不需要管理缩放、平移、工具栏可见性或小地图状态。
这种模式还适用于哪些地方
这种模式很适合迁移到产品结构导出、制造或供应链拆解、系统架构树、依赖关系图以及合规文档等场景,在这些场景中,团队需要的是一张一致的完整图像,而不是交互式屏幕截图。
它也适合作为分享与报告工作流的起点:定时生成快照、自定义图工具栏中的一键导出、内部管理工具中的下载操作,或保持相同 prepareForImageGeneration() 与恢复生命周期、但替换截图选项、文件名策略或外围 UI 的品牌化导出变体。