[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:zh:force-layout-live-parameter-tuning":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Force 布局实时参数调优\n\n## 这个示例构建了什么\n\n这个示例围绕一个静态分支数据集构建了一个全屏力导向图试验场。画布显示统一的圆形节点和笔直的青绿色连线，同时一个悬浮的白色控制窗口允许用户调节节点斥力、连线弹性以及布局迭代次数。\n\n重点并不在于自定义渲染或图编辑。真正有用的部分在于图只加载一次，然后直接原地调整正在运行的力求解器。同一个悬浮窗口还暴露了共享工作区工具，例如滚轮模式切换、拖动画布模式切换以及图片导出。\n\n## 数据如何组织\n\n图数据直接在 `MyGraph.tsx` 中内联组装。它使用一个 `RGJsonData` 对象，其中包含 `rootId: 'a'`、一个 `rawNodes` 数组和一个 `rawLines` 数组。在调用 `setJsonData` 之前，示例会把每条原始连线映射为一个带有生成 `id` 的新对象，因此最终传入 relation-graph 的数据集具备显式的连线标识符。\n\n示例数据构成了一个有根的分支结构：一个根节点 `a`、四个顶层分支（`b`、`c`、`d`、`e`），以及每个分支下更深层的子节点组。总计来看，这个文件定义了 103 个节点和 102 条连线。在生产应用中，同样的结构可以表示组织树、依赖展开、分类体系、事故传播树，或任何仍然更适合使用力导向间距而不是严格树布局的类层级网络。\n\n## relation-graph 的使用方式\n\n页面包裹在 `RGProvider` 中，而 `MyGraph` 通过 `RGHooks.useGraphInstance()` 获取作用域属于该 provider 的图实例。`RelationGraph` 组件接收了一组聚焦的图配置：圆形节点、60x60 的默认节点尺寸、连接到边框的直线、青色与青绿色默认配色，以及内置的 `force` 布局。\n\n图实例 API 驱动了运行时行为。`initializeGraph()` 负责加载准备好的 `RGJsonData`、将图居中，并设置一个固定缩放级别。`updateMyOptions()` 会把 `graphInstance.layoutor` 视为 `RGLayouts.ForceLayout`，并在不重建数据集的情况下推入新的物理参数值。另一条单独的 `restartForceLayout()` 路径则会重写 `layout.maxLayoutTimes`、调用 `doLayout()`，然后重新居中并重新设置画布缩放，以便用户对比连续布局与固定迭代预算两种效果。\n\n这个示例中没有节点插槽、连线插槽，也没有编辑 API。样式通过图配置以及一个本地 SCSS 文件完成，该文件会强制节点文字为白色，并定义选中连线的覆盖样式。可拖拽的辅助窗口及其设置面板来自共享的本地组件，并再次使用 relation-graph hooks 来操作画布选项和图片生成。\n\n## 关键交互\n\n- `Node Repulsion` 滑块会修改当前 force 布局器上的 `force_node_repulsion`。\n- `Line Elastic` 滑块会修改当前 force 布局器上的 `force_line_elastic`。\n- 分段选择器用于在 `Layout Forever` 和 `Layout Fixed Times(...)` 之间切换。\n- 选择固定模式后，一个范围输入会控制 `maxLayoutTimes`，并触发一次新的 `doLayout()` 运行。\n- 悬浮辅助窗口可以拖动和最小化，因此用户可以在保持控件近旁可用的同时查看图。\n- 辅助窗口的设置视图可以修改滚轮行为、修改画布拖动行为，并下载图像快照。\n\n节点和连线点击处理器都已存在，但在审阅过的源码中，它们只会把被点击的对象输出到控制台。在这里，它们并不驱动布局、选择或编辑行为。\n\n## 关键代码片段\n\n下面这段片段展示了该示例使用 relation-graph 内置的 `force` 布局，并配合最小化的视觉样式，而不是自定义节点渲染。\n\n```tsx\nconst graphOptions: RGOptions = {\n  debug: true,\n  defaultNodeBorderWidth: 0,\n  defaultNodeShape: RGNodeShape.circle,\n  defaultNodeWidth: 60,\n  defaultNodeHeight: 60,\n  defaultLineColor: 'rgba(0, 186, 189, 1)',\n  defaultNodeColor: 'rgba(0, 206, 209, 1)',\n  defaultLineShape: RGLineShape.StandardStraight,\n  layout: { layoutName: 'force', maxLayoutTimes: Number.MAX_SAFE_INTEGER },\n  defaultJunctionPoint: RGJunctionPoint.border\n};\n```\n\n下面这段片段展示了图数据只准备一次：在把它加载到图实例之前，先为每条连线补上显式的 ID。\n\n```tsx\nconst linesWithIds = rawLines.map((line, index) => ({\n  ...line,\n  id: `l${index + 1}`\n}));\n\nconst myJsonData: RGJsonData = {\n  rootId: 'a',\n  nodes: rawNodes,\n  lines: linesWithIds\n};\n```\n\n下面这段片段展示了一次性数据加载，以及随后显式执行的视口重置。\n\n```tsx\nawait graphInstance.setJsonData(myJsonData);\ngraphInstance.moveToCenter();\ngraphInstance.setZoom(30);\n```\n\n下面这段片段展示了第一条运行时控制路径：当滑块变化时，直接更新当前激活的 `ForceLayout` 实例。\n\n```tsx\nconst forceLayout = graphInstance.layoutor as InstanceType\u003Ctypeof RGLayouts.ForceLayout>;\nif (forceLayout) {\n  forceLayout.updateOptions(myForceLayoutOptions);\n}\n```\n\n下面这段片段展示了第二条运行时控制路径：通过重写布局选项并重新运行求解器来切换重新布局模式。\n\n```tsx\ngraphInstance.updateOptions({\n  layout: {\n    layoutName: 'force',\n    maxLayoutTimes: layoutForever ? Number.MAX_SAFE_INTEGER : maxLayoutTimes\n  }\n});\nawait graphInstance.doLayout();\ngraphInstance.moveToCenter();\ngraphInstance.setZoom(30);\n```\n\n下面这段片段展示了悬浮 UI 如何把连续布局与带有滑块上限的布局运行区分开来。\n\n```tsx\n\u003CSimpleUISelect currentValue={layoutForever} data={[\n  { value: true, text: 'Layout Forever' },\n  { value: false, text: `Layout Fixed Times(${maxLayoutTimes})` }\n]} onChange={(newValue: boolean) => { setLayoutForever(newValue); }} />\n{!layoutForever && \u003Cinput\n  type=\"range\"\n  min=\"10\"\n  max=\"1000\"\n  step=\"20\"\n  value={maxLayoutTimes}\n```\n\n## 这个示例的独特之处\n\n这个示例的独特之处在于，它把内置的 `force` 布局当作一个最小化的实时基线，而不是一个庞大的控制面板。图始终停留在同一份内联数据集上，可见的力导向控制项只保留了斥力和连线弹性，而迭代控制则被放进一个独立的“连续布局 / 固定次数重新布局”切换中。\n\n与 `layout-force-options` 相比，这个版本更适合作为起点来阅读，因为它没有加入数据集预设，也没有扩展出更宽泛的全局力参数面板。与 `performance-test-force-layout` 相比，它避开了性能测试脚手架，例如合成规模预设、缩略图导航以及自定义节点渲染。与 `layout-force-options-pro` 相比，它停留在全局求解器调优层面，而不是深入到按节点或按连线的力参数覆盖，以及运行时图变更。\n\n另一个独特之处是它在视觉上的克制。页面保持了无边框的 60px 圆形节点、笔直的青绿色连线，以及一个可拖拽的白色辅助窗口，因此真正被突出展示的是力导向行为本身。\n\n## 这种模式还适用于哪里\n\n这种模式很适合迁移到内部工具中，在团队确定最终图设计之前先调试间距行为。例如，同样的方法可以用于依赖图、服务拓扑图、组织结构、分类浏览器等场景，在这些场景中数据保持稳定，但目标中的力导向行为仍需要持续校准。\n\n它同样是面向操作人员工作台的实用模式。产品可以只加载一次图，让用户调整求解器强度和重新运行时长，然后在保持同一数据集不变的前提下，对比不同布局参数下的可读性、重叠减少效果以及导出质量。\n",false,500,1782615385390]