[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:zh:show-single-nodes":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# 在圆形布局中保持孤立节点可见\n\n## 这个示例构建了什么\n\n这个示例构建了一个全高度的 relation-graph 查看器，将一组稀疏的圆形节点排列成一个类似轨道的圆环。若干节点看起来没有可见关系，但由于数据集在加载前补入了隐藏的结构性边，它们仍会保留在布局中。用户可以查看图谱并点击节点或连线，不过这些点击只会把被点击的对象输出到控制台。\n\n## 数据如何组织\n\n图谱数据在 `initializeGraph()` 中以内联方式创建，为一个包含 19 个节点和 5 条显式连线的 `RGJsonData` 对象。加载数据前，代码从第一个节点（`a`）推导出 `rootId`，并为其余每个节点追加一条从根节点指向该节点、且带有 `opacity: 0` 的额外连线。在真实应用中，同样的结构可以表示人员、设备、服务、账户或记录，其中一些条目没有可见关系，但仍需要在同一个共享布局中保持稳定位置。\n\n## relation-graph 的使用方式\n\n`index.tsx` 使用 `RGProvider` 包裹整个示例，`MyGraph.tsx` 通过 `RGHooks.useGraphInstance()` 获取作用域属于该 provider 的实例。图谱选项启用了 relation-graph 内置的 `circle` 布局，使用边框连接点，将节点渲染为 60 x 60 的圆形，并保持默认连线宽度为 2。组件挂载时执行的 `useEffect()` 会运行初始化流程：组装数据、注入隐藏辅助边、调用 `setJsonData()`，然后执行 `moveToCenter()` 和 `zoomToFit()`。\n\n这个示例除了 `RGProvider` 和 `RelationGraph` 之外，没有使用自定义插槽、视口工具、编辑器功能或额外的图谱子组件。查阅到的 SCSS 文件基本只是空选择器的骨架，因此最终可见结果本质上就是 relation-graph 默认效果，再叠加所选布局和内联 wrapper 高度设置。\n\n## 关键交互\n\n- 组件挂载时图谱会自动加载，随后立即居中并适配到当前视口。\n- 点击节点会触发 `onNodeClick`，但处理函数只会记录节点对象。\n- 点击连线会触发 `onLineClick`，但处理函数只会记录连线对象。\n- 这个示例没有工具栏、展开/收起流程、编辑模式或选择工作流。\n\n## 关键代码片段\n\n这段选项配置表明，该示例依赖 relation-graph 内置的圆形布局以及圆形节点默认值。\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: false,\n    defaultJunctionPoint: RGJunctionPoint.border,\n    defaultNodeShape: RGNodeShape.circle,\n    defaultNodeWidth: 60,\n    defaultNodeHeight: 60,\n    defaultLineWidth: 2,\n    layout: {\n        layoutName: 'circle'\n    }\n};\n```\n\n这段预处理是核心变通方案：它先推导出一个根节点，再在图谱加载前追加隐藏的辅助连线。\n\n```tsx\nconst rootId = myJsonData.nodes[0].id;\nmyJsonData.rootId = rootId;\nlet lineIndex = myJsonData.lines.length + 1;\nmyJsonData.nodes.forEach(n => {\n    if (n.id !== rootId) {\n        myJsonData.lines.push({\n            id: `l${lineIndex++}`,\n            from: rootId,\n            to: n.id,\n            opacity: 0\n        });\n    }\n});\n```\n\n这段挂载时序列说明，增强后的数据集会被自动加载并自动完成取景，而不是等待手动操作。\n\n```tsx\nuseEffect(() => {\n    initializeGraph();\n}, []);\n\n// ...\n\nawait graphInstance.setJsonData(myJsonData);\ngraphInstance.moveToCenter();\ngraphInstance.zoomToFit();\n```\n\n这组处理函数表明，用户交互仅限于面向检查的日志输出。\n\n```tsx\nconst onNodeClick = (nodeObject: RGNode, $event: RGUserEvent) => {\n    console.log('onNodeClick:', nodeObject);\n};\n\nconst onLineClick = (lineObject: RGLine, linkObject: RGLink, $event: RGUserEvent) => {\n    console.log('onLineClick:', lineObject);\n};\n```\n\n## 这个示例的独特之处\n\n根据准备好的对比数据，这个示例是一个朴素的基线参考，用来展示一个特定的变通方案：在调用 `setJsonData()` 之前，先人为制造一条不可见的连接骨架，从而让看似孤立的节点仍能保留在 `circle` 布局中。真正少见的部分，是内联静态数据、加载时增强、仅记录日志的点击处理函数，以及一个大体保持默认设置的全高度画布的组合，而不是单独使用 `RGProvider` 或标准的加载-居中-适配 API 时序。\n\n与 `show-single-nodes3` 相比，这个版本刻意保持朴素，没有把可见连线样式变成讲解重点。与 `show-single-nodes2` 相比，它使用了相同的隐藏辅助思路，但节点位置严格保持为圆形布局，而不是切换到力导向布局。与 `multi-group-2` 相比，它不会原样渲染彼此断开的分组；它会改写载荷，让节点在参与同一个指定布局的同时，仍然看起来像是孤立的。\n\n## 这一模式还适用于哪里\n\n这一模式也很适合导入审核和监控类界面：某些实体虽然没有可见关系，但仍需要留在画布中，例如组织数据里尚未分配的员工、未声明依赖关系的服务、部分匹配的客户记录，或等待确认链接的知识图谱实体。当团队希望传达“这些项目当前是孤立的”这一视觉信息，同时又不想放弃某一种内置布局算法所带来的稳定性时，这种做法也很有用。\n",false,500,1782615418085]