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