[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:zh:line-shape-junctions-and-label-placement":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# 运行时线条形状、连接点与标签放置控制\n\n## 这个示例构建了什么\n这个示例构建了一个全屏关系图，同一份已加载的图数据可以在运行时实时切换样式。画布在平铺背景上展示圆形头像节点、按颜色区分的关系边，以及一个悬浮控制窗口。该窗口可以把每条线在直线与曲线走线之间切换、改变曲线与节点的连接方式，并在带框文本标签与沿路径放置的文本之间切换。\n\n图本身的内容在加载后保持不变。它的主要亮点是，用户无需重建数据集或更改节点位置，就可以在一张稠密的头像关系图上比较多种边渲染行为。\n\n## 数据如何组织\n数据来自 `mock-data-api.ts` 中的本地 `RGJsonData` 对象。它声明了 `rootId: \"N13\"`、21 个节点以及更多的连线记录。每个节点都带有可见样式字段，例如 `color`、`borderColor` 和 `data.icon`；每条线都带有 `from`、`to`、`text`、`color`、`fontColor` 以及一个类型化的 `data` 载荷。\n\n布局之前没有真正的预处理。`fetchJsonData()` 只是用一个简短的 Promise 包装这个静态对象，而 `initializeGraph()` 会把结果直接传给 `setJsonData()`。有些节点对会被有意重复出现，例如 `N1 -> N15` 和 `N13 -> N8`，这有助于示例展示在线条重复连接时，线条形状和连接方式的选择会如何表现。在实际项目中，同样的结构可以表示人物网络、调查链路、利益相关方地图，或同一对实体之间存在多种连接类型的服务关系。\n\n## 如何使用 relation-graph\n`RGProvider` 包裹整个页面，`RGHooks.useGraphInstance()` 则是 `MyGraph` 内部的主要运行时控制接口。图选项使用内置的力导向布局，关闭调试模式，设置圆形节点，将 `multiLineDistance` 保持为 `20`，把布局迭代次数上限设为 `50`，并提供节点颜色和边框的兜底设置。\n\n这里重要的实现细节在于，当选择器发生变化时，示例不会重建 `RGJsonData`。异步加载完成后，`initializeGraph()` 会调用 `loading()`、`setJsonData()`、`updateMyGraphData()`、`clearLoading()`、`moveToCenter()` 和 `zoomToFit()`。之后，第二个 effect 会监听 `lineShape`、`lineJunctionPoint` 和 `textOnPath`，然后遍历 `graphInstance.getLines()`，并用 `updateLine(...)` 重写每一条已经渲染出来的线。\n\n这一步线条更新流程正是 relation-graph 功能组合使用的地方。`lineShape` 会在 `RGLineShape.StandardStraight` 与 `RGLineShape.StandardCurve` 之间切换。启用直线模式时，两个端点都会被强制恢复为 `RGJunctionPoint.border`；启用曲线模式时，选中的连接点值会同时写入 `fromJunctionPoint` 和 `toJunctionPoint`。同一轮更新还会切换 `useTextOnPath`，因此标签位置可以在不重新加载图的情况下发生变化。\n\n这个示例还使用了 slot 和共享辅助组件。`RGSlotOnNode` 用圆形肖像头像和位于节点下方的标签替换了默认节点主体。`DraggableWindow` 承载线条控制项，并且可以打开共享的 `CanvasSettingsPanel`，其中 `RGHooks.useGraphStore()` 和 `graphInstance.setOptions()` 用于切换滚轮与拖拽行为。这个共享面板还可以通过 `prepareForImageGeneration()`、`domToImageByModernScreenshot()` 和 `restoreAfterImageGeneration()` 导出当前图像。\n\n本地 SCSS 则完成了最终的视觉呈现，包括平铺画布背景、白色带框线条标签，以及被选中节点的蓝色光晕。\n\n## 关键交互\n- `Line Shape` 选择器会把所有已加载的边改写为直线或曲线走线。\n- `Line JunctionPoint` 选择器只会在启用曲线走线时出现，让用户比较 border、paired-side 和 single-side 锚点模式。\n- `Line Text On Path` 选择器会在普通带框标签与直接渲染在线条路径上的文本之间切换。\n- 点击空白画布区域会调用 `clearChecked()`，从图中移除选中高亮。\n- 悬浮辅助窗口可以拖拽、最小化、切换为画布设置覆盖层，并可用于下载当前图像。\n\n## 关键代码片段\n这个数据片段表明，示例从一个固定的 `RGJsonData` 对象开始，其中包含根节点、每个节点的样式以及自定义头像 URL。\n\n```ts\nconst jsonData = {\n    \"rootId\": \"N13\",\n    \"nodes\": [\n        {\n            \"id\": \"N1\",\n            \"text\": \"Liangping.Hou\",\n            \"color\": \"#ec6941\",\n            \"borderColor\": \"#ff875e\",\n            \"data\": {\n```\n\n这个选项片段证明，该图在运行时线条更新开始前，使用了力导向布局、圆形节点以及固定的重复边间距。\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: false,\n    defaultLineShape: RGLineShape.StandardStraight,\n    defaultNodeShape: RGNodeShape.circle,\n    multiLineDistance: 20,\n    layout: {\n        layoutName: 'force',\n        maxLayoutTimes: 50\n    },\n    defaultNodeBorderWidth: 2,\n```\n\n这段初始化流程表明，图只加载一次，应用当前线条设置，然后再将视口居中并适配到合适大小。\n\n```tsx\nconst initializeGraph = async () => {\n    const myJsonData: RGJsonData = await fetchJsonData();\n\n    graphInstance.loading();\n    await graphInstance.setJsonData(myJsonData);\n    await updateMyGraphData();\n    graphInstance.clearLoading();\n    graphInstance.moveToCenter();\n    graphInstance.zoomToFit();\n};\n```\n\n这个更新函数是核心技巧：它重写每一条已经渲染的线，而不是重新生成数据集。\n\n```tsx\nconst updateMyGraphData = async () => {\n    graphInstance.getLines().forEach((line) => {\n        graphInstance.updateLine(line, {\n            lineShape,\n            fromJunctionPoint: lineShape === RGLineShape.StandardStraight ? RGJunctionPoint.border : lineJunctionPoint,\n            toJunctionPoint: lineShape === RGLineShape.StandardStraight ? RGJunctionPoint.border : lineJunctionPoint,\n            useTextOnPath: textOnPath\n        });\n    });\n};\n```\n\n这个控制片段证明，连接点选择是有条件的，只有图正在显示曲线时它才有意义。\n\n```tsx\n{\n    lineShape !== RGLineShape.StandardStraight &&\n    \u003Cdiv>\n        \u003Cdiv className=\"text-base py-2\">Line JunctionPoint:\u003C/div>\n        \u003CSimpleUISelect\n            data={[\n                { value: RGJunctionPoint.border, text: 'Border' },\n                { value: RGJunctionPoint.ltrb, text: 'Left/Top/Right/Bottom' },\n                { value: RGJunctionPoint.lr, text: 'Left/Right' },\n                { value: RGJunctionPoint.tb, text: 'Top/Bottom' },\n```\n\n这个节点 slot 表明，示例把图级线条控制与自定义头像节点渲染结合在了一起。\n\n```tsx\n\u003CRGSlotOnNode>\n    {({ node }: RGNodeSlotProps) => (\n        \u003Cdiv className=\"w-12 h-12 flex place-items-center justify-center\">\n            \u003Cdiv className=\"my-node-avatar\" style={{ backgroundImage: `url(${node.data?.icon})` }} />\n            \u003Cdiv className=\"absolute transform translate-y-[35px]\" style={{ color: node.color }}>{node.text}\u003C/div>\n        \u003C/div>\n    )}\n\u003C/RGSlotOnNode>\n```\n\n这个共享设置片段表明，这个悬浮工作区也可以在不更改图数据的情况下导出当前图像。\n\n```tsx\nconst downloadImage = async () => {\n    const canvasDom = await graphInstance.prepareForImageGeneration();\n    let graphBackgroundColor = graphInstance.getOptions().backgroundColor;\n    if (!graphBackgroundColor || graphBackgroundColor === 'transparent') {\n        graphBackgroundColor = '#ffffff';\n    }\n    const imageBlob = await domToImageByModernScreenshot(canvasDom, {\n        backgroundColor: graphBackgroundColor\n    });\n    if (imageBlob) {\n        downloadBlob(imageBlob, 'my-image-name');\n    }\n```\n\n## 这个示例的独特之处\n比较记录表明，这个示例最接近 `line-multi-lines-gap`、`custom-line-style`、`search-and-focus` 和 `use-dagre-layout-2`，但它们也揭示了一个更聚焦的要点。这里的主要重点是在图已经加载完成后，对内置边行为进行图级控制：形状切换、曲线连接点选择，以及沿路径文本切换。\n\n与 `line-multi-lines-gap` 相比，这个示例在重复边间距上的着力较少，而更关注曲线连接器如何附着到节点上。与 `custom-line-style` 相比，它的区别价值不在于 CSS 外观换肤，而在于对内置线条几何和标签放置的运行时控制。与 `search-and-focus` 和 `use-dagre-layout-2` 相比，这个图的重点也不是导航或重新布局；节点位置保持在力导向布局中，变化的只有边的渲染方式。\n\n比较文件也限制了可以安全提出的结论。悬浮辅助窗口、画布设置、图像导出以及头像风格的关系场景，并不是这个示例独有的，它也不是一个结构编辑器。真正让它突出的，是稠密头像关系图、图级 `getLines()` 加 `updateLine()` 更新、仅在曲线模式下出现的连接点选择器，以及在带框标签和沿路径文本之间进行运行时切换的组合。\n\n## 这种模式还适用于哪里\n- 关系图或社交图场景中，团队需要在固定数据集上比较更易读的连接器样式，再决定生产环境默认值。\n- 调查、风险或欺诈图谱中，一对实体之间可能存在多种关系类型，而边的可读性比结构编辑更重要。\n- 服务和依赖关系图中，需要一个紧凑的控制界面来调整连接器走线、锚点策略和标签放置，而无需重新运行布局逻辑。\n- 内部演示或 QA 工作台中，设计师和工程师需要在真实的图场景中审查线条行为，并导出当前状态的快照。\n",false,500,1782615374163]