[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:force-layout-icon-button-nodes":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Force Layout Icon Button Nodes\n\n## What This Example Builds\n\nThis example builds a styling-focused relationship viewer on top of a force-directed `relation-graph`. The canvas fills the screen with a mustard background, the links are semi-transparent white straight lines, and every visible node is replaced with the same layered icon-button treatment instead of the library's default label body.\n\nUsers can inspect the graph visually, hover or focus a node to reveal its label, open a floating settings panel, switch wheel and drag behavior, and export the canvas as an image. The main point is not graph editing; it is how one reusable node slot can turn a generic graph dataset into a consistent, product-like icon surface.\n\n## How the Data Is Organized\n\nThe graph data is declared inline as one `RGJsonData` object. It uses a simple `rootId`, a flat `nodes` array, and a flat `lines` array with `from` and `to` references. Each node also carries `data.icon`, which is the key piece of metadata for this example because it drives both the rendered icon and the CSS modifier class.\n\nThere is no preprocessing step before `setJsonData(...)`. The example loads the literal dataset directly, then centers and fits the graph. In a real application, the same shape could represent service categories, device groups, product families, feature clusters, or any entity network where each node type needs a branded but consistent visual skin.\n\n## How relation-graph Is Used\n\n`RGProvider` wraps the example, and `RGHooks.useGraphInstance()` provides the live graph instance. The local `graphOptions` switch the layout to `force`, raise `maxLayoutTimes` to `80000`, make default node chrome transparent, keep the default node shape rectangular, set the background color, and place the built-in toolbar horizontally at the lower-right corner.\n\nThe key rendering hook is `RGSlotOnNode`. Instead of mixing several slot branches, the example uses one slot template for every node. That template reads `node.data.icon`, adds it to the button class name, and passes the same value into `MyNodeIcon`, where a Lucide icon map selects the glyph. The result is metadata-driven theming with one renderer rather than many node-specific components.\n\nThe surrounding UI comes from shared helper components. `DraggableWindow` adds the floating description shell, minimize behavior, and a settings overlay. Inside that helper, `CanvasSettingsPanel` reads graph state from the store, updates runtime options with `setOptions(...)`, prepares the graph for image generation, captures the canvas DOM, and restores the graph afterward. SCSS overrides then remove built-in node borders, soften toolbar chrome, and define the layered icon-button visuals and hover motion.\n\n## Key Interactions\n\nThe most visible interaction is on the node itself: hover or keyboard focus rotates the back plate, pushes the front plate forward in 3D space, and fades in the text label below the icon. That interaction is what makes the graph feel like a button-based viewer instead of a static network.\n\nThe example also binds `onNodeClick` and `onLineClick`, but those handlers only log ids to the console. They are inspection hooks, not state-changing features. The floating helper window is more functional: it can be dragged, minimized, opened into a settings overlay, used to switch wheel behavior between scroll, zoom, and none, used to switch canvas drag behavior between selection, move, and none, and used to download an image of the graph.\n\n## Key Code Fragments\n\nThis fragment shows the core slot renderer: one node template uses `node.data.icon` for both theming and icon selection.\n\n```tsx\nconst CustomNodeComponent: React.FC\u003CRGNodeSlotProps> = ({ node }) => {\n    return (\n        \u003Cdiv>\n            \u003Cbutton className={`icon-btn icon-btn--${node.data?.icon}`} type=\"button\">\n                \u003Cspan className=\"icon-btn__back\">\u003C/span>\n                \u003Cspan className=\"icon-btn__front\">\n                    \u003CMyNodeIcon color=\"#ffffff\" size=\"30px\" name={node.data?.icon} />\n                \u003C/span>\n                \u003Cspan className=\"icon-btn__label\">{node.text}\u003C/span>\n            \u003C/button>\n        \u003C/div>\n    );\n};\n```\n\nThis fragment shows how the graph skin is configured at the library level before any custom slot rendering happens.\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: true,\n    defaultLineColor: 'rgba(255, 255, 255, 0.6)',\n    defaultNodeColor: 'transparent',\n    defaultNodeShape: RGNodeShape.rect,\n    backgroundColor: '#d2a904',\n    toolBarDirection: 'h',\n    toolBarPositionH: 'right',\n    toolBarPositionV: 'bottom',\n    defaultLineShape: RGLineShape.StandardStraight,\n    layout: {\n        layoutName: 'force',\n        maxLayoutTimes: 80000\n    }\n};\n```\n\nThis fragment shows that the example keeps the data model simple and uses `data.icon` as reusable presentation metadata.\n\n```tsx\nconst myJsonData: RGJsonData = {\n    rootId: 'a',\n    nodes: [\n        { id: 'a', text: 'a', data: { icon: 'football' } },\n        { id: 'b', text: 'b', data: { icon: 'fries' } },\n        { id: 'b1', text: 'b1', data: { icon: 'delivery_truck' } },\n        { id: 'b1-1', text: 'b1-1', data: { icon: 'burger' } }\n        // ...\n    ],\n    lines: [\n        { from: 'a', to: 'b', text: '' },\n        { from: 'b', to: 'b1', text: '' }\n        // ...\n    ]\n};\n```\n\nThis fragment shows the mount-time graph initialization workflow.\n\n```tsx\nif (graphInstance) {\n    console.log('Instance ID:', graphInstance.options.instanceId);\n\n    await graphInstance.setJsonData(myJsonData);\n    graphInstance.moveToCenter();\n    graphInstance.zoomToFit();\n}\n```\n\nThis fragment shows the SCSS rules that create the hover-revealed label and depth effect.\n\n```scss\n.icon-btn:focus-visible .icon-btn__back, .icon-btn:hover .icon-btn__back {\n    transform: rotate(22.5deg)\n}\n\n.icon-btn:focus-visible .icon-btn__front, .icon-btn:hover .icon-btn__front {\n    transform: translateZ(3em) rotateX(20deg) rotateY(20deg)\n}\n\n.icon-btn:focus-visible .icon-btn__label, .icon-btn:hover .icon-btn__label {\n    opacity: 1;\n    transform: translateY(20%)\n}\n```\n\nThis fragment shows the shared runtime controls that change canvas behavior and trigger image export.\n\n```tsx\n\u003CSettingRow\n    label=\"Wheel Event:\"\n    options={[\n        { label: 'Scroll', value: 'scroll' },\n        { label: 'Zoom', value: 'zoom' },\n        { label: 'None', value: 'none' },\n    ]}\n    value={wheelMode}\n    onChange={(newValue: string) => { graphInstance.setOptions({ wheelEventAction: newValue }); }}\n/>\n```\n\n## What Makes This Example Distinct\n\nAccording to the comparison data, this example stands out less because it introduces many different node templates and more because it stays disciplined around one repeatable pattern. Compared with `node-style4` and `node-style`, it keeps a single icon-button family and lets `node.data.icon` control the variation, instead of branching into several unrelated slot designs or a fixed chip theme.\n\nCompared with `node-style2`, it moves the same general viewer shell away from CSS refinement of built-in tree nodes and toward full node-body replacement with `RGSlotOnNode` on a force layout. Compared with the broader `node` example, it is a narrower, more product-oriented reference: one metadata-driven slot family, one mustard showcase canvas, hover-only labels, and icon-specific gradient back plates rather than a catalog of styling techniques.\n\nThe shared floating helper, runtime settings, and image export are useful here, but they are not the distinguishing claim because the comparison data shows those utilities appear in nearby examples too. The more defensible distinction is the combination of metadata-driven icon mapping, icon-specific gradients, transparent graph chrome, and 3D-like hover motion inside one coherent node renderer.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to any viewer where nodes need a small set of recognizable visual identities without turning the graph into a full editor. Examples include service maps where each service category gets its own icon treatment, product navigation graphs where each family uses a branded chip, restaurant or retail catalogs where item groups need a compact visual marker, and device or capability maps where hover can reveal labels only when the user needs detail.\n\nIt also fits teams that want a reusable rendering contract between data and design. If a backend can provide a stable metadata key such as `icon`, the frontend can keep one `RGSlotOnNode` implementation and expand the icon map and SCSS theme library over time without changing the graph structure itself.\n",false,500,1782615372267]