JavaScript is required

导出图谱Base64图片数据

这个示例展示如何把完整 relation-graph 场景捕获为 Base64 图片数据,而不是立即下载。它加载静态图,准备导出状态,使用共享 modern-screenshot 辅助方法截图,把 blob 转为 data URL,并在悬浮工具窗中同时预览图片与原始字符串。

将 Relation Graph 导出为 Base64 图像数据

这个示例构建了什么

这个示例构建了一个只读的图谱导出工具,它不会立即下载截图结果,而是将捕获结果保存在内存中。页面会显示一个全高度的 relation-graph 画布、蓝色圆形节点、右上角的内置工具栏,以及一个悬浮在图谱上方的控制窗口。

用户可以选择导出背景色,执行 Generate Image Base64 操作,预览生成的截图,并在同一个面板中查看完整的数据 URL 字符串。这个示例最重要的点在于工作流:先让图谱进入适合生成图片的状态,将其捕获为 blob,再转换为 Base64,最后回渲染到界面中以便立即验证。

数据是如何组织的

图谱数据在 initializeGraph() 内部以内联方式声明为一个 RGJsonData 对象。它使用 rootId: '2'、扁平的 nodes 数组,以及扁平的 lines 数组,其中每条连线都已经显式包含 fromtotext 字段。

在调用 setJsonData() 之前没有任何结构预处理。这个示例直接在代码中组装静态数据集,将其加载到图谱实例中,然后重新居中并让视口自适应。在真实应用中,这种数据形态同样可以表示子系统关系、制造结构、设备装配、依赖图,或任何后续需要作为图像数据嵌入其他流程的网络。

relation-graph 是如何使用的

RGProvider 包裹了整个示例,这样 relation-graph 的 hooks 就可以解析当前活动的图谱实例。在 MyGraph 内部,RGHooks.useGraphInstance() 是主要的集成入口:它通过 setJsonData() 加载数据集,使用 moveToCenter()zoomToFit() 对齐视口,并通过 prepareForImageGeneration()restoreAfterImageGeneration() 驱动导出生命周期。

这个示例没有在 graphOptions 中声明命名布局,因此在 JSON 数据加载完成后,最终渲染出来的排布依赖 relation-graph 的默认行为。本地选项主要聚焦在展示层:toolBarDirectiontoolBarPositionHtoolBarPositionV 让内置工具栏以水平控制组的形式固定显示在右上角,而 defaultLineColordefaultNodeBorderColordefaultNodeBorderWidthdefaultNodeWidthdefaultNodeHeightdefaultNodeShapedefaultJunctionPoint 则建立了蓝色圆形节点的视觉风格。

这个示例没有使用节点、连线、画布或视口插槽,也没有启用图谱编辑。相反,它把 relation-graph 与两个本地辅助模块组合在一起。domToImageByModernScreenshot.tsmodern-screenshot 做了封装,并暴露出 blobToBase64(...)DraggableWindow.tsx 则提供了悬浮外壳和共享的 CanvasSettingsPanel。这个共享面板通过 RGHooks.useGraphStore() 读取实时选项状态,并通过 graphInstance.setOptions(...) 在运行时修改滚轮和拖拽行为。本地 SCSS 文件只提供了选择器骨架,因此大多数可见样式来自图谱选项和工具类,而不是深度样式表覆盖。

关键交互

图谱会在挂载时自动初始化。用户在导出前不需要手动整理视图,因为代码会先加载数据集,再立即将其居中并缩放到适配当前视口。

核心交互是 Base64 捕获流程。颜色输入框会更新下一次截图使用的背景色,点击 Generate Image Base64 后,代码会捕获已准备好的图谱,恢复图谱状态,将 blob 转换为数据 URL,然后同时显示预览图和原始 Base64 字符串。

这个悬浮工具窗口还可以被拖动、最小化,并切换为设置覆盖层。这个共享覆盖层会在实时图谱实例上修改 wheelEventActiondragEventAction,同时还暴露了另一条基于下载的图片导出路径,但这些控件更多是围绕示例自身 Base64 工作流的可复用脚手架,而不是它要讲解的核心内容。

关键代码片段

这段代码表明,该示例使用的是静态内联图谱数据集,并在居中和适配视口之前将其直接加载到实例中。

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' },
        // ...
    ]
};

这段代码证明,在 JSON 结构组装完成之后,实际的初始化工作是由 relation-graph 实例 API 完成的。

await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();

这段代码是整个示例的核心:relation-graph 负责让图谱进入导出准备状态,共享辅助函数负责捕获 DOM,而结果则会被转换成 Base64 状态,而不是立即下载。

const generateImageBase64 = async () => {
    const canvasDom = await graphInstance.prepareForImageGeneration();
    const imageBlob = await domToImageByModernScreenshot(canvasDom, {
        backgroundColor: myImageBackgroundColor
    });
    await graphInstance.restoreAfterImageGeneration();
    if (imageBlob) {
        const base64 = await blobToBase64(imageBlob);
        setBase64String(base64);
    }
};

这段代码说明,图谱的可见样式主要是通过 relation-graph 选项定义的,而不是依赖自定义渲染插槽。

const graphOptions: RGOptions = {
    toolBarDirection: 'h',
    toolBarPositionH: 'right',
    toolBarPositionV: 'top',
    defaultLineColor: 'rgb(37 99 235)',
    defaultNodeBorderColor: 'rgb(37 99 235)',
    defaultNodeBorderWidth: 2,
    defaultNodeWidth: 60,
    defaultNodeHeight: 60,
    defaultNodeShape: RGNodeShape.circle,
    defaultJunctionPoint: RGJunctionPoint.border
};

这段代码展示了让截图过程可配置、并让结果持续显示在页面上的本地 UI 控件。

<input
    type="color"
    value={myImageBackgroundColor}
    onChange={(e) => setMyImageBackgroundColor(e.target.value)}
    className="w-8 h-8 cursor-pointer border rounded"
/>
<SimpleUIButton onClick={generateImageBase64}>Generate Image Base64</SimpleUIButton>
{base64String && (
    <div className="overflow-auto break-words h-36">{base64String}</div>
)}

这段代码展示了导出流程背后的可复用辅助层:modern-screenshot 负责生成 blob,而 FileReader 则把这个 blob 转换成数据 URL。

const defaultOptions = {
    scale: 2,
    cacheBust: true,
    ...options
};
const blob = await domToBlob(element, defaultOptions);
export const blobToBase64 = (blob: Blob): Promise<string> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => {
      resolve(reader.result);
    };
    reader.onerror = (error) => {
      reject(error);
    };
    reader.readAsDataURL(blob);
  });
};

这个示例的独特之处

从对比数据来看,这个示例最接近 generate-imagegenerate-image-with-watermark,但它强调的重点不同。那些相邻示例使用的是同一套 prepare-capture-restore 生命周期,而这个示例则把结果推进到组件状态中作为 Base64 数据保存,并在悬浮窗口中同时保留预览图和原始字符串。

它在这种以内存为核心的工作流里也更具可配置性。本地背景色选择器可以改变导出图片的背景,而不需要修改图谱选项或样式资源,因此当目标使用场景事先并不明确时,更适合反复截图和验证。

toolbar-positionnode-style2 相比,工具栏位置和蓝色默认样式只是辅助性的设计决定,而不是主要教学点。这里最有代表性的组合是固定在右上角的工具栏、可拖拽的共享工具外壳、可配置的导出背景、blob 到 Base64 的转换,以及对生成数据 URL 的即时页面内检查。

这种模式还适用于哪里

这种模式适用于那些需要把图谱图像作为一个值来使用、而不是直接下载文件的系统:例如将快照嵌入 CMS 内容、通过 API 发送图谱预览、把数据 URL 附加到表单提交中,或在后续步骤完成前把临时截图保存在客户端状态里。

它也适合调试和集成场景。当团队需要验证捕获输出、比较不同背景设置、测试下游渲染,或排查 relation-graph 的导出行为在接入上传、剪贴板或消息传递流程之前的表现时,让预览图和原始 Base64 字符串同时保留在页面中会很有帮助。