[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:switchable-node-slot-templates":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Switching Node Slot Templates Across One Graph\n\n## What This Example Builds\n\nThis example builds a centered relation-graph scene that reuses one small people dataset while swapping the visible node body across several custom slot templates. The viewer sees the same topology rendered as a green badge, a holographic profile card, an icon pill, a yellow metrics card, or a circular borrower badge, with a floating mini view and a floating utility window above the canvas.\n\nThe graph is structurally read-only. The main interaction is template switching: tabs in the helper window rewrite every live node's `type`, then the graph recenters and refits so large templates such as the `300 x 450` profile card remain readable. The most important lesson is that the demo treats node-slot customization as a runtime orchestration pattern, not as five separate graph examples.\n\n## How the Data Is Organized\n\nThe example imports one shared `RGJsonData` payload from `users01.json`. It uses `rootId: 'a'`, defines seven nodes, and connects them with six lines in a hub-and-spoke structure from `a` to `b` through `g`.\n\nThere is no preprocessing before `setJsonData()`. The JSON is handed directly to relation-graph, and the slot renderers later read `node.data.pic`, `node.data.name`, and `node.data.myicon` for avatars, labels, and icon selection. After the data is loaded, the runtime updates only change `node.type`; the graph structure and business fields stay fixed.\n\nIn a real product, the same structure could represent employees, customers, assets, devices, or cases. The custom data fields could hold avatar URLs, display names, role icons, scores, or status metadata that need several visual treatments on one graph.\n\n## How relation-graph Is Used\n\nThe example keeps layout and graph mechanics inside relation-graph while moving almost all node appearance into slots and SCSS. `MyGraph.tsx` configures a `center` layout with explicit `levelGaps`, centered alignment, `force_node_repulsion`, `force_line_elastic`, and `maxLayoutTimes`, while the default node body is made transparent with `RGNodeShape.rect` and `defaultNodeBorderWidth: 0`. That makes the slot renderer the visible node surface.\n\n`RGHooks.useGraphInstance()` drives the lifecycle. On mount, it loads the imported JSON with `setJsonData()`, then calls `moveToCenter()` and `zoomToFit()`. The same instance later powers graph-wide `getNodes()` plus `updateNode(...)` mutations, temporary canvas animation during size changes, and the shared export flow in `CanvasSettingsPanel`.\n\nCustomization is split across two slots. `RGSlotOnNode` branches on `node.type` and selects `NodeSlot1` through `NodeSlot5`, while `RGSlotOnView` mounts `RGMiniView` as a viewport overlay. Around the graph, `RGProvider` supplies context, `DraggableWindow` hosts the selector and settings shell, `SimpleUIVTabs` renders the slot tabs, and the wrapper class `slot-style-${slotTeamplateId}` activates slot-specific checked-state and theme overrides in SCSS.\n\nThis remains a viewer example, not an editor. Runtime APIs change presentation and interaction options, but they do not add, remove, or reconnect graph elements.\n\n## Key Interactions\n\n- Choosing `Slot2`, `Slot3`, `Slot4`, `Slot5`, or `Random` rewrites every live node's `type`, then recenters and refits the graph after a short animation-assisted delay.\n- `Random` mode samples from the same tab list, so some nodes can still fall back to the default `NodeSlot1` branch when the sampled value is the literal `random`.\n- The floating window can be dragged from its header, minimized, and switched into a settings overlay without unmounting the graph.\n- The settings overlay changes `wheelEventAction` and `dragEventAction` on the live graph instance, so the same canvas can switch between scroll, zoom, selection, move, or no input handling.\n- The `Download Image` action prepares the graph DOM for export, renders it to a blob with `modern-screenshot`, downloads it, and restores the graph afterward.\n- `NodeSlot3` reacts to relation-graph's `checked` flag and adds an animated gradient plus a custom halo, so selection feedback changes with the active slot family.\n- `RGMiniView` gives the larger card modes a stable navigation aid when node dimensions expand substantially.\n\n## Key Code Fragments\n\nThis fragment shows that the example hides the built-in node surface so the slot renderer becomes the visible body.\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: true,\n    defaultJunctionPoint: RGJunctionPoint.border,\n    defaultNodeColor: 'transparent',\n    defaultNodeShape: RGNodeShape.rect,\n    defaultNodeBorderWidth: 0,\n    defaultLineShape: RGLineShape.StandardStraight,\n    // ...\n};\n```\n\nThis fragment shows the centered layout configuration that gives the template gallery enough spacing for large node bodies.\n\n```tsx\nlayout: {\n    layoutName: 'center',\n    levelGaps: [500, 500, 500],\n    alignItemsX: 'center',\n    alignItemsY: 'center',\n    force_node_repulsion: 2,\n    force_line_elastic: 0.1,\n    maxLayoutTimes: Number.MAX_VALUE\n}\n```\n\nThis fragment shows that the shared dataset is loaded once and the viewport is normalized before any slot switching happens.\n\n```tsx\nconst initializeGraph = async () => {\n    const myJsonData: RGJsonData = graphJsonData;\n    await graphInstance.setJsonData(myJsonData);\n    graphInstance.moveToCenter();\n    graphInstance.zoomToFit();\n    await changeNodeSlot(slotTeamplateId);\n};\n```\n\nThis fragment shows the graph-wide mutation pattern: every live node gets a new renderer type, then the graph refits after size changes settle.\n\n```tsx\nconst allNodes: RGNode[] = graphInstance.getNodes();\nfor (const node of allNodes) {\n    const randomSlot = allSlotIds[Math.floor(Math.random() * allSlotIds.length)];\n    graphInstance.updateNode(node, {\n        type: newSlotId === 'random' ? randomSlot.value : newSlotId\n    });\n}\ngraphInstance.enableCanvasAnimation();\nawait graphInstance.sleep(50);\ngraphInstance.moveToCenter();\ngraphInstance.zoomToFit();\n```\n\nThis fragment shows that one `RGSlotOnNode` switch fans out into five unrelated node bodies instead of one fixed custom node.\n\n```tsx\n\u003CRGSlotOnNode>\n    {({ node, checked }: RGNodeSlotProps) => {\n        switch (node.type) {\n        case 'slot2': return \u003CNodeSlot2 node={node} />;\n        case 'slot3': return \u003CNodeSlot3 node={node} checked={checked} />;\n        case 'slot4': return \u003CNodeSlot4 node={node} />;\n        case 'slot5': return \u003CNodeSlot5 node={node} />;\n        default: return \u003CNodeSlot1 node={node} />;\n        }\n    }}\n\u003C/RGSlotOnNode>\n```\n\nThis fragment shows that selection styling in slot 3 depends on relation-graph's `checked` state, not on a separate local flag.\n\n```tsx\nexport const NodeSlot3: React.FC\u003CRGNodeSlotProps> = ({ node, checked }) => {\n    return (\n        \u003Cdiv className={`my-slot-3-content ${checked ? 'my-node-animation-01 text-white' : ''}`}>\n            \u003CIconSwitcher iconName={node.data?.myicon} size={60} />\n        \u003C/div>\n    );\n};\n```\n\nThis fragment shows how the wrapper class changes the graph chrome and checked-state treatment for the active slot family.\n\n```scss\n.slot-style-slot2 {\n    .relation-graph {\n        background-color: #050505;\n        font-family: 'Orbitron', 'Noto Sans SC', sans-serif;\n        --rg-checked-item-bg-color: rgba(244, 60, 229, 0.3);\n        .rg-toolbar {\n            background-color: rgba(248, 246, 246, 0.53);\n            border: none;\n        }\n        .rg-miniview {\n            background-color: #050505;\n        }\n    }\n}\n```\n\nThis fragment shows that the export flow uses relation-graph's preparation and restore APIs instead of screenshotting the canvas blindly.\n\n```tsx\nconst canvasDom = await graphInstance.prepareForImageGeneration();\nlet graphBackgroundColor = graphInstance.getOptions().backgroundColor;\nif (!graphBackgroundColor || graphBackgroundColor === 'transparent') {\n    graphBackgroundColor = '#ffffff';\n}\nconst imageBlob = await domToImageByModernScreenshot(canvasDom, {\n    backgroundColor: graphBackgroundColor\n});\nawait graphInstance.restoreAfterImageGeneration();\n```\n\n## What Makes This Example Distinct\n\nThe comparison data places this example near `node`, `hand-drawn-style`, `css-theme`, and `custom-line-style`, but its emphasis is different from each of those neighbors. Its clearest distinguishing trait is that it rewrites the loaded graph's `node.type` across every live node at runtime, then recenters and refits after slot-driven size changes settle.\n\nAgainst `node`, the main lesson is not a side-by-side catalog of per-node JSON styling tricks. `node-slot-list` goes further into graph-wide template switching, where one mounted graph can move among five custom node bodies plus a mixed random mode without rebuilding the dataset.\n\nAgainst `hand-drawn-style`, the reusable idea is renderer orchestration more than one themed skin. Against `css-theme` and `custom-line-style`, the example is not primarily about recoloring built-in graph surfaces or mutating line presets. It is about swapping node markup itself while keeping the same centered dataset, minimap, and floating workspace shell.\n\nThe strongest feature combination is the transparent rectangular base node, center-layout tuning, wrapper-class-driven checked-state themes, and graph-wide `updateNode(...)` switching on one people dataset. That combination makes the example work more like a runtime node-template gallery than a static custom-node demo.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to products that need multiple node presentations for the same relationships. Examples include staff maps that switch between compact badges and profile cards, risk graphs that switch between icon states and scorecards, or infrastructure views that switch between service icons and detail tiles.\n\nIt is also useful for design review and white-label workflows. A team can keep one prepared graph instance, compare alternate node densities or branded skins, and verify how a minimap, selection styling, and export behave before choosing a production template.\n\nThe same structure can serve as a regression board for slot systems. Because the topology stays fixed while the renderer changes, it is a practical way to test whether new node templates still fit the layout, selection treatment, and export pipeline.\n",false,500,1782615371219]