[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:zh:view-and-canvas-slots-overview":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# 在同一张图中比较内置视图槽位与画布槽位\n\n## 这个示例构建了什么\n\n这个示例构建了一个全高度的 relation graph，同时它也充当一个槽位承载面对比面板。图本身是一个小型静态网络，但真正可见的教学内容，是通过 `RGSlotOnView`、`RGSlotOnCanvasAbove` 和 `RGSlotOnCanvas` 渲染出来的三个大型、带颜色区分的 HTML 面板。\n\n用户可以在视图层面板中的文本输入框里输入内容，然后看到同样的文本出现在另外两个基于画布的面板中。画布上方面板里的一个 `Show More Info` 按钮会显示额外内容块，因此这个示例同时演示了共享状态，以及图组件持有层中的一个简单条件覆盖层。\n\n这里的重点不是图数据编辑或业务语义。真正重要的结果，是把内置视图槽位与画布槽位如何承载普通交互式 HTML，以一种明确的并排对比方式展示出来。\n\n## 数据是如何组织的\n\n图数据直接在 `initializeGraph()` 内联创建，为一个 `RGJsonData` 对象，其中包含 `rootId: '2'`、扁平的 `nodes` 数组和扁平的 `lines` 数组。每个节点都带有 `id`、`text` 和 `data.myicon` 字段。每条连线也都已经包含各自的 `id`、`from`、`to` 和 `text`。\n\n在调用 `setJsonData()` 之前，没有单独的数据预处理步骤。这个对象是直接按照 relation-graph 期望的结构组装好的，然后原样加载到实例中。在真实应用里，同样的结构也可以表示组织关系、系统关系、依赖关系、归属关系，或任何其他小型关系集合，而图本身主要作为分层 UI 的承载面。\n\n## relation-graph 的使用方式\n\n`index.tsx` 用 `RGProvider` 包裹整个示例，而 `MyGraph.tsx` 通过 `RGHooks.useGraphInstance()` 获取当前活动实例。一个只在挂载时运行的 `useEffect()` 会调用 `initializeGraph()`，该函数加载内联数据集，并立即调用 `moveToCenter()` 和 `zoomToFit()`，让演示从一个规整的初始视图开始。\n\n`RelationGraph` 本身的配置很轻。唯一显式设置的图选项是 `defaultJunctionPoint: RGJunctionPoint.border` 和 `defaultLineColor: '#666'`。在当前审查的源码中，没有显式设置 `layout`，因此节点排列来自 relation-graph 针对这份数据的默认行为。\n\n实现中的核心细节是，这三个槽位演示都属于同一个 `RelationGraph` 实例。`RGSlotOnView` 承载一个带文本输入框的固定说明面板。`RGSlotOnCanvasAbove` 承载第二个面板，其中包含切换按钮和一个有条件显示的额外内容块。`RGSlotOnCanvas` 承载第三个面板，它会持续显示镜像后的文本。每个面板都使用 `pointer-events-auto`，这让普通 HTML 控件在图场景内部依然可以交互。\n\n这里没有使用图编辑 API、节点事件或连线事件。本地 SCSS 文件主要只是提供了空的选择器骨架，因此可见的教学效果主要来自内联绝对定位、鲜艳的背景色，以及这些内置槽位承载面本身。`Show More Info` 控件是从 `DraggableWindow.tsx` 导入的共享本地 `SimpleUIButton` 组件，而不是特殊的 relation-graph 小部件。\n\n## 关键交互\n\n- 在 `RGSlotOnView` 的输入框中输入内容会更新 `searchText`。\n- 当前的 `searchText` 值会再次渲染到 `RGSlotOnCanvasAbove` 的展开区域中，以及 `RGSlotOnCanvas` 的预览区域中。\n- 点击 `Show More Info` 会切换画布上方槽位中的条件内容块。\n- 这个示例的结构使用户能够在同一个图场景里，对比一个视图层面板和两个画布层面板，而不需要为每一种承载面分别打开单独的演示。\n\n## 关键代码片段\n\n这个包装层说明，整个演示都运行在同一个 relation-graph provider 上下文中。\n\n```tsx\nconst Demo = () => {\n    return (\n        \u003CRGProvider>\n            \u003CMyGraph />\n        \u003C/RGProvider>\n    );\n};\n```\n\n这段代码表明，该示例通过 hook 获取实例访问能力，并且只设置了极少量的图级选项。\n\n```tsx\nconst MyGraph = () => {\n  const [searchText, setSearchText] = useState('You can use this search box to search for nodes');\n  const [showBackgroundGraph, setShowBackgroundGraph] = useState(false);\n\n  const graphInstance = RGHooks.useGraphInstance();\n\n  const graphOptions: RGOptions = {\n    defaultJunctionPoint: RGJunctionPoint.border,\n    defaultLineColor: '#666'\n  };\n```\n\n这个片段证明，图数据载荷是以内联方式组装的，并且使用了扁平的 `nodes` 和 `lines`。\n\n```tsx\nconst myJsonData: RGJsonData = {\n  rootId: '2',\n  nodes: [\n    { id: '1', text: 'Node-1', data: { myicon: 'el-icon-star-on' } },\n    { id: '2', text: 'Node-2', data: { myicon: 'el-icon-setting' } },\n    { id: '3', text: 'Node-3', data: { myicon: 'el-icon-setting' } },\n    // ... more nodes ...\n  ],\n  lines: [\n    { id: 'l1', from: '7', to: '71', text: 'Investment' },\n    { id: 'l2', from: '7', to: '72', text: 'Investment' },\n    // ... more lines ...\n  ]\n};\n```\n\n这个初始化流程就是唯一的图实例工作流：加载数据、居中，然后自适应显示。\n\n```tsx\nif (graphInstance) {\n  await graphInstance.setJsonData(myJsonData);\n  await graphInstance.moveToCenter();\n  await graphInstance.zoomToFit();\n}\n```\n\n这个槽位片段展示了视图层面板，以及驱动共享 React 状态的输入框。\n\n```tsx\n\u003CRGSlotOnView>\n  \u003Cdiv className=\"pointer-events-auto\" style={{ top: '0px', left: '0px', position: 'absolute', width: '600px', border: '#efefef solid 1px', zIndex: 22 }}>\n    \u003Cdiv style={{ backgroundColor: '#fa7b7e', padding: '10px', width: '100%', fontSize: '18px' }}>This is the view slot(RGSlotOnView)\u003C/div>\n    \u003Cdiv style={{ backgroundColor: '#7a9ef8', padding: '10px', width: '100%', fontSize: '12px' }}>\n      You can customize the content here, such as putting a search box:\n      \u003Cinput type=\"text\" defaultValue={searchText} onChange={(e) => { setSearchText(e.target.value); }} />\n    \u003C/div>\n  \u003C/div>\n\u003C/RGSlotOnView>\n```\n\n这个片段展示了画布上方槽位如何使用本地按钮来显示额外内容，而该内容复用了同一个文本状态。\n\n```tsx\n\u003CRGSlotOnCanvasAbove>\n  \u003Cdiv className=\"pointer-events-auto\" style={{ top: '-300px', left: '-300px', position: 'absolute', width: '600px', border: '#efefef solid 1px' }}>\n    \u003Cdiv style={{ backgroundColor: '#f5df7a', padding: '10px', width: '100%', fontSize: '12px' }}>\n      You can put anything here, these contents will move and scale with the canvas.\n      \u003CSimpleUIButton onClick={toggleGraph}>Show More Info\u003C/SimpleUIButton>\n    \u003C/div>\n    {showBackgroundGraph && (\n      \u003Cdiv className=\"flex justify-center place-items-center text-2xl text-red-900\" style={{ backgroundColor: '#cb7ffd', width: '600px', height: '600px', overflow: 'hidden' }}>\n        \u003Cdiv>{searchText}\u003C/div>\n      \u003C/div>\n    )}\n  \u003C/div>\n\u003C/RGSlotOnCanvasAbove>\n```\n\n最后这个槽位会在画布层面板中始终显示镜像文本。\n\n```tsx\n\u003CRGSlotOnCanvas>\n  \u003Cdiv className=\"pointer-events-auto\" style={{ top: '100px', left: '-100px', position: 'absolute', width: '600px', border: '#efefef solid 1px' }}>\n    \u003Cdiv style={{ backgroundColor: '#f5df7a', padding: '10px', width: '100%', fontSize: '12px' }}>\n      You can put anything here, even another graph, these contents will move and scale with the canvas.\n    \u003C/div>\n    \u003Cdiv className=\"flex justify-center place-items-center text-2xl text-red-900\" style={{ backgroundColor: 'rgba(127,201,253)', width: '600px', height: '400px', overflow: 'hidden' }}>\n      \u003Cdiv>{searchText}\u003C/div>\n    \u003C/div>\n  \u003C/div>\n\u003C/RGSlotOnCanvas>\n```\n\n## 这个示例的独特之处\n\n从对比内容本身就能明确看出它的差异点：这个示例的不同寻常之处，在于它把 `RGSlotOnView`、`RGSlotOnCanvasAbove` 和 `RGSlotOnCanvas` 并排放在同一个 `RelationGraph` 中进行比较。附近的示例，例如 `node-menu` 和 `node-menu-2`，也使用了视图层 HTML，但它们关注的是由节点触发的菜单和瞬时覆盖层。而这个示例会同时保持多个教学面板可见，并且不依赖选中节点、连线或画布目标。\n\n它也不同于 `scene-network-use-canvas-slot`，后者把画布槽位作为一个完整仪表板式组合的一部分来使用。在这里，画布槽位只是三种承载面的对比之一，而且其中的内容被刻意保持得很简单，以便图层行为足够直观。与 `customize-fullscreen-action` 相比，这里的主要集成经验发生在图容器内部，而不是在外围包装布局中围绕图容器展开。\n\n最有辨识度的特征组合，是一份共享的 React 状态同时流经三个内置槽位承载面：视图槽位输入框、画布上方展开面板，以及画布槽位读出区域。因此，当需求是跨图层协调 HTML 覆盖层，而不是菜单、全屏行为或图编辑时，这个示例会是一个更好的起点。\n\n## 这种模式还能用在哪里\n\n这种模式适合那些同时需要固定控件和随图移动覆盖层的图页面。比如固定在视口上的搜索框或筛选框、需要随画布一起移动的注释卡片，以及直接放在图场景内部、用于解释缩放或平移行为的说明面板。\n\n它也很适合迁移到监控看板、架构图、关系检查工具和引导演示中。在这些场景里，底层的节点和连线可以来自真实业务数据，而槽位组合模式保持不变：一个状态来源、普通 HTML 控件，以及针对视图级内容和画布级内容分别制定的放置规则。\n",false,500,1782615420030]