[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:zh:circle-layout-isolated-nodes-with-green-straight-links":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# 在带样式的圆形布局中保持孤立节点可见\n\n## 此示例构建了什么\n\n该示例构建了一个全高度的 relation-graph 查看器，将一组稀疏数据放入单一的圆形排列中。最终可见的结果是：一圈 60 x 60 的圆形节点、少量绿色直线连接，以及许多看起来彼此断开的节点，尽管它们仍然参与了已加载的图。核心要点在于把两个小技巧结合起来：先在加载前注入隐藏的结构性连线，再使用图选项让可见连线看起来是有意设计的，而无需添加自定义渲染。\n\n## 数据是如何组织的\n\n图数据在 `initializeGraph()` 中以内联方式声明为一个 `RGJsonData` 对象，其中包含 19 个节点和 5 条可见连线。在运行 `setJsonData()` 之前，代码会从第一个节点（`a`）推导出 `rootId`，将该值写回 `myJsonData.rootId`，然后为其余每个节点追加一条不可见的 root-to-node 辅助连线，通过生成连续的 `l6`、`l7` 以及后续 id，并设置 `opacity: 0` 来完成。\n\n这意味着加载后的图在结构上比可见图更连通。在真实应用中，同样的模式可以表示人员、账户、设备、产品或知识图谱实体；即使显式可见的关系缺失或不完整，它们仍需要被放置在同一个布局中。\n\n## relation-graph 是如何使用的\n\n`index.tsx` 使用 `RGProvider` 包裹该示例，而 `MyGraph.tsx` 通过 `RGHooks.useGraphInstance()` 获取已挂载的图实例。图选项定义了几乎所有可见行为：`layoutName: 'circle'`、`RGNodeShape.circle`、`RGLineShape.StandardStraight`、边框交汇点、60 x 60 的默认节点尺寸、2 像素线宽，以及绿色默认连线颜色。\n\n运行时流程非常精简且明确。一个只在挂载时执行的 `useEffect()` 会调用 `initializeGraph()`，内联数据集会先在内存中增强，然后图实例再运行 `setJsonData()`、`moveToCenter()` 和 `zoomToFit()`。该示例没有使用插槽、编辑器功能、视口工具，也没有使用 `RGProvider` 和 `RelationGraph` 之外的额外图子组件。它导入了一个本地 SCSS 文件，并用 `.my-graph` 包裹画布，但检查后的样式表基本只是空的选择器骨架，因此视觉结果主要来自图选项和 `height: '100vh'` 这个包装层。\n\n## 关键交互\n\n- 图会在挂载时自动加载，然后居中并自动适配到视口。\n- 点击节点会触发 `onNodeClick`，但该处理函数只会记录被点击的节点对象。\n- 点击连线会触发 `onLineClick`，但该处理函数只会记录被点击的连线对象。\n- 该示例没有编辑流程、没有展开或折叠行为、没有选择工作流，也没有工具栏交互。\n\n## 关键代码片段\n\n下面这段选项配置表明，该示例通过 `RGOptions` 展示了圆形布局以及显式的可见连线样式配置。\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: false,\n    defaultJunctionPoint: RGJunctionPoint.border,\n    defaultNodeShape: RGNodeShape.circle,\n    defaultLineShape: RGLineShape.StandardStraight,\n    defaultNodeWidth: 60,\n    defaultNodeHeight: 60,\n    defaultLineWidth: 2,\n    defaultLineColor: 'green',\n    layout: {\n        layoutName: 'circle'\n    }\n};\n```\n\n这份内联数据集在预处理之前规模很小且是静态的，因此后续的增强步骤很容易看清。\n\n```tsx\nconst myJsonData: RGJsonData = {\n    rootId: '',\n    nodes: [\n        { id: 'a', text: 'a' },\n        { id: 'b', text: 'b' },\n        { id: 'b1', text: 'b1' },\n        // ...\n        { id: 'e2', text: 'e2' }\n    ],\n    lines: [\n        { id: 'l1', from: 'b', to: 'b1' },\n        { id: 'l2', from: 'c2', to: 'b5' }\n        // ...\n    ]\n};\n```\n\n这一步预处理是核心变通方案：它先推导出一个 root，再在图加载前追加不可见的辅助边。\n\n```tsx\nconst rootId = myJsonData.nodes[0].id;\nmyJsonData.rootId = rootId;\n\nlet lineCounter = myJsonData.lines.length + 1;\nmyJsonData.nodes.forEach(n => {\n    if (n.id !== rootId) {\n        myJsonData.lines.push({\n            id: `l${lineCounter++}`,\n            from: rootId,\n            to: n.id,\n            opacity: 0\n        });\n    }\n});\n```\n\n这段启动序列证明了增强后的数据会被自动加载并完成取景，同时用户交互仍然仅限于查看。\n\n```tsx\nuseEffect(() => {\n    initializeGraph();\n}, []);\n\nawait graphInstance.setJsonData(myJsonData);\ngraphInstance.moveToCenter();\ngraphInstance.zoomToFit();\n\nconst onNodeClick = (nodeObject: RGNode, $event: RGUserEvent) => {\n    console.log('onNodeClick:', nodeObject);\n};\n```\n\n## 这个示例的独特之处\n\n根据准备好的对比数据，这个示例可以看作是孤立节点变通方案演示中更强调样式配置的同类版本。和 `show-single-nodes`、`show-single-nodes2` 一样，它会从第一个节点推导 root，并注入隐藏的辅助边，让那些看起来孤立的节点仍然参与布局。这个版本的突出之处在于，它还把可见连线样式本身纳入了示例重点，通过全局选项在 `circle` 布局中使用 2 像素的绿色直线连接。\n\n与 `show-single-nodes` 相比，这个版本不只是一个朴素基线，而更像是在同一变通方案之上，补充了选项级连线样式配置的紧凑参考。与 `show-single-nodes2` 相比，它保留了环绕式的圆形摆放，而不是切换到带排斥力调节的力导布局。与 `advanced-line-usage` 相比，它的连线配置是为了支持断开数据的布局变通方案，而不是充当更广泛的可见连线行为参考板。\n\n## 这种模式还适用于哪里\n\n这种模式很适合用于那些必须让不完整或当前尚未建立连接的记录仍然保持可见、但又不应凭空捏造可见业务关系的图视图：例如组织数据中尚未分配的员工、只导入了部分拓扑的设备、等待关系解析的客户或产品记录，或者在审查阶段仍需要稳定定位的知识图谱实体。\n\n当团队需要一个小型示例，把结构预处理与清晰可读的默认边样式结合起来时，它也是一个很实用的起点。隐藏的辅助连线可以继续作为内部加载策略保留，而标签、面板、过滤器或更丰富的交互则可以在后续再逐步加入。\n",false,500,1782615419227]