图谱缩放预设
这个示例把内联自上而下树图加载到 relation-graph,并通过悬浮辅助窗中的 5 个固定缩放预设控制视口。它用 `setJsonData()`、`moveToCenter()` 和 `setZoom()` 初始化图谱,后续预设变更由 React 状态同步,同时保留共享画布设置与图片导出工具。
使用固定缩放预设控制自上而下的树图
这个示例构建了什么
这个示例构建了一个撑满高度的树形查看器,并配有一个浮动控制卡片,用户可以通过它把画布强制切换到五个精确的缩放级别之一。图本身是一个自上而下的层级结构,使用高挑的浅蓝色矩形节点和克制的弧形连线,因此在没有其他视觉干扰的情况下也能很容易看出缩放变化。
用户可以在浮动选择器中点击 100%、80%、40%、20% 或 10%。首次加载时,示例会挂载内联数据集、将视口居中、应用当前缩放预设,并在页面右上角附近显示一条成功提示。
这个示例的重点并不只是树形布局本身。它更像是一份简洁的参考,用来说明如何通过外部 React 状态控制 relation-graph 的缩放,而不是只依赖滚轮手势或内置的导航辅助功能。
数据是如何组织的
数据在 initializeGraph() 中以内联方式声明为一个 RGJsonData 对象,其中包含 rootId、扁平的 nodes 数组和扁平的 lines 数组。从结构上看,它是一个以 a 为根节点的常规树状层级,在 b、c、d 和 e 下还有较大的分支组。
在调用 setJsonData() 之前,没有 fetch 步骤,也没有预处理层。这个数据字面量直接在组件中构造,并直接传给图实例,从而让示例把重点放在视口控制,而不是数据加载或转换上。
在真实应用中,同样的数据形状可以表示组织树、产品分类、文件层级、依赖提纲,或任何需要由周边 UI 提供可预测缩放级别的只读知识视图。有一个源数据细节值得注意:连线记录 { id: 'e', to: 'e2' } 缺少 from 字段,因此这个示例更适合作为缩放控制模式的参考,而不是严格的连线 schema 参考。
relation-graph 是如何使用的
index.tsx 用 RGProvider 包裹页面,使当前图实例可供 hooks 使用。随后 MyGraph.tsx 通过 RGHooks.useGraphInstance() 加载数据并控制视口,而 DraggableWindow.tsx 中共享的 CanvasSettingsPanel 同时使用 RGHooks.useGraphInstance() 和 RGHooks.useGraphStore() 来读取并修改实时画布选项。
图配置把这个 demo 固定在一种树形布局上:layoutName: 'tree'、from: 'top'、treeNodeGapH: 10 和 treeNodeGapV: 100。示例还设置了矩形节点、较窄的 30 x 100 默认节点尺寸、弧形连线,以及上下方向的连接点,因此整个图读起来更像一棵纵向树,而不是通用网络。
这个示例中没有自定义节点插槽、连线插槽、画布插槽或编辑手柄。视觉上的定制来自 my-relation-graph.scss,它在 .relation-graph 下覆盖默认的节点和连线外观,而不是用自定义组件替换渲染。
图实例 API 的调用流程清晰而精简。setJsonData() 负责加载内联树数据,moveToCenter() 负责规范化首次视图,setZoom() 则同时应用初始预设和之后每一次预设变化。共享的辅助窗口还通过 setOptions() 提供关于滚轮和拖拽行为的运行时控制,并通过 prepareForImageGeneration()、getOptions() 和 restoreAfterImageGeneration() 支持截图导出。
关键交互
主要交互是预设缩放选择。点击 SimpleUISelect 中的某个值会更新 React 状态,而 useEffect([zoom]) 这座桥梁会把该值继续传给 graphInstance.setZoom()。
浮动辅助窗口为图增加了第二层交互。它的标题栏可以拖动,内容可以最小化和恢复,设置按钮会在同一个窗口外壳之上打开一个覆盖面板。
在这个设置覆盖层中,用户可以把滚轮行为切换为 scroll、zoom 或 none,也可以把画布拖拽行为切换为 selection、move 或 none。这些控件继承自共享辅助窗口,因此它们在这里也会出现,但相对于“缩放预设”这个主题仍然是次要内容。
辅助窗口还暴露了图片导出能力。它会先为捕获准备图画布 DOM,再通过 modern-screenshot 将其渲染为 blob、下载文件,最后恢复图状态。
关键代码片段
这个片段说明,示例被固定为一个自上而下的树结构,带有高挑的矩形节点和弧形连线。
const graphOptions: RGOptions = {
layout: {
layoutName: 'tree',
from: 'top',
treeNodeGapH: 10,
treeNodeGapV: 100
},
defaultNodeShape: RGNodeShape.rect,
defaultNodeWidth: 30,
defaultLineShape: RGLineShape.StandardCurve,
defaultJunctionPoint: RGJunctionPoint.tb,
这个片段展示了扁平的内联 RGJsonData 结构,它会被直接加载到图实例中。
const myJsonData: RGJsonData = {
rootId: 'a',
nodes: [
{ id: 'a', text: 'a' }, { id: 'b', text: 'b' }, { id: 'b1', text: 'b1' },
// ...many more nodes omitted
],
lines: [
{ id: 'l1', from: 'a', to: 'b' }, { id: 'l2', from: 'b', to: 'b1' },
// ...many more lines omitted
]
};
这个片段证明,初始化是一次性完成“加载、重新居中、应用当前缩放”的顺序流程。
await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.setZoom(zoom);
SimpleGlobalMessage.showMessage({
type: 'success',
message: `Set Zoom To: ${zoom}%`
});
这个片段展示了状态到实例的桥接方式,用于让选中的预设与实时视口保持同步。
const setGraphZoom = () => {
graphInstance.setZoom(zoom);
};
useEffect(() => {
setGraphZoom();
}, [zoom]);
这个片段表明,示例专属 UI 是一个紧凑的外部选择器,提供五个固定百分比。
<SimpleUISelect
data={[
{ value: 100, text: '100%' },
{ value: 80, text: '80%' },
{ value: 40, text: '40%' },
{ value: 20, text: '20%' },
{ value: 10, text: '10%' }
]}
currentValue={zoom}
onChange={(newValue: string) => {
这个片段展示了共享设置覆盖层如何通过图实例修改实时画布行为。
<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 }); }}
/>
这个片段展示了围绕 relation-graph 图片生成生命周期构建的截图导出路径。
const canvasDom = await graphInstance.prepareForImageGeneration();
let graphBackgroundColor = graphInstance.getOptions().backgroundColor;
if (!graphBackgroundColor || graphBackgroundColor === 'transparent') {
graphBackgroundColor = '#ffffff';
}
const imageBlob = await domToImageByModernScreenshot(canvasDom, {
backgroundColor: graphBackgroundColor
});
await graphInstance.restoreAfterImageGeneration();
这个示例的独特之处
对比结果已经清楚说明了差异:这个示例位于一组带有浮动窗口查看器工具的案例附近,例如 disable-effect、gee-thumbnail-diagram、drag-and-wheel-event 和 switch-layout,但它的示例专属 UI 要窄得多。当前的稀有度数据表明,不寻常的部分是“预设缩放选择器”本身,而不是共享辅助窗口。
与 disable-effect 相比,这个示例并不是关于锁定或解锁交互。它保留了导航能力,重点放在选择精确的缩放预设上;当产品需要确定性的视口状态,而不是权限开关时,这种方式更有用。
与 gee-thumbnail-diagram 相比,它强调的是已知百分比,而不是概览式导航。用户在这里不会拖动缩略图视口;外围 UI 只是简单地把选定的缩放值推送给 setZoom()。
与 drag-and-wheel-event 和 switch-layout 相比,数据集和布局在加载后基本保持固定。这个图不会变成一个更广泛的行为试验场;它的主要要点是在一个原本稳定的树结构外层,明确建立从 React 状态到 setZoom() 的同步模式。
最强的差异化组合在于:顶部起始的树、一次性内联加载、立即执行 moveToCenter()、一个包含五个取值的外部缩放选择器,以及对实时图实例进行命令式 setZoom() 调用。这使它成为一个聚焦于可预测视口缩放的起点,而不是面向布局变更、缩略图导航或交互模式实验。
这个模式还适用于哪里
这个模式非常适合那些需要从外围 UI 提供可预测、可命名缩放状态的嵌入式图查看器。典型场景包括仪表板面板、引导式演示、展示模式、侧边栏中的知识查看器,以及需要让图以已知比例打开、并允许用户在少数几个认可级别之间跳转的管理页面。
它也适用于那些希望把缩放预设绑定到外部状态的产品,例如路由参数、用户保存的偏好、工具栏按钮或新手引导步骤。在不改变数据集加载到 relation-graph 方式的前提下,同样的结构还可以扩展到键盘快捷键、紧凑的移动端控件,或针对不同场景的默认缩放级别。