[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:basic-custom-node-and-minimap":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Building a Basic Custom-Node Viewer with a Persistent Minimap\n\n## What This Example Builds\n\nThis example builds a full-height relation graph viewer for a small fictional company network. The finished scene shows one larger root node in the middle, rendered as an animated circular badge, while the surrounding nodes become smaller icon circles with their labels placed underneath. Link labels such as `Invest` and `Executive` are drawn on the connection paths, and a minimap stays visible inside the graph view.\n\nUsers can inspect the network immediately because the graph is loaded, centered, and fitted on mount. The most important teaching point is not the sample business labels. It is the compact combination of provider-scoped graph startup, custom node rendering, and an embedded overview widget in one very small React example.\n\n## How the Data Is Organized\n\nThe data lives in one inline `staticJsonData` constant inside `MyGraph.tsx`. It uses the standard `RGJsonData` shape with `rootId`, `nodes`, and `lines`. The reviewed payload contains 19 nodes and 18 labeled lines. Most nodes rely on the global default size of `60 x 60`, while the root node sets `width: 100` and `height: 100` directly in the data so the custom root renderer has more space.\n\nThere is no preprocessing step before `setJsonData()`. The component declares the final graph payload in code and passes it directly into the graph instance during startup. The reusable part is the per-node metadata pattern: each node stores an icon key in `data.myicon`, and the custom node component turns that field into different Lucide icons. In a real application, the same structure could represent organizations, systems, people, assets, or workflow steps, while `data.myicon` could be replaced by type, status, or category information.\n\n## How relation-graph Is Used\n\n`index.tsx` wraps the example in `RGProvider`, and `MyGraph.tsx` calls `RGHooks.useGraphInstance()` to access the active instance from provider context. A mount-time `useEffect()` runs `initializeGraph()`, which loads the inline JSON, then calls `moveToCenter()` and `zoomToFit()` so the viewer opens in a usable state without extra user setup.\n\nThe graph options keep the setup narrow but explicit. The example enables debug mode, uses circular nodes, sets `defaultNodeWidth` and `defaultNodeHeight` to `60`, places line text on the path, and configures the built-in `center` layout with `maxLayoutTimes: 3000`. It also sets `defaultExpandHolderPosition: 'right'` and `reLayoutWhenExpandedOrCollapsed: true`, even though the local example remains a read-only viewer rather than an editor.\n\nThe main customization comes from two relation-graph slots. `RGSlotOnNode` replaces the default node body with `CustomNode`, which branches between a dedicated root-node template and an icon-based child-node template. `RGSlotOnView` mounts `RGMiniView`, so the minimap lives inside the graph scene instead of in an external panel. Local SCSS then overrides relation-graph's checked-state classes to recolor selected nodes, node labels, line strokes, and line labels with a magenta accent.\n\n## Key Interactions\n\n- The graph initializes itself on mount by loading the JSON payload, centering the canvas, and fitting the viewport.\n- A permanent `RGMiniView` gives the user an always-visible overview and a second navigation surface inside the same graph scene.\n- Node clicks and line clicks are wired for inspection only. They log the clicked item to the console and return `true`, but they do not update React state or mutate the graph.\n\n## Key Code Fragments\n\nThis wrapper shows that the example depends on provider context before any graph instance API is used.\n\n```tsx\nconst MyApp: React.FC = () => {\n    return (\n        \u003CRGProvider>\n            \u003CMyGraph />\n        \u003C/RGProvider>\n    );\n};\n```\n\nThis inline dataset proves that the graph payload is assembled directly in the component and that icon selection comes from node metadata.\n\n```tsx\nconst staticJsonData: RGJsonData = {\n    rootId: '2',\n    nodes: [\n        { id: '2', text: 'Initrode', width: 100, height: 100, data: { myicon: 'delivery_truck' } },\n        { id: '1', text: 'Paper Street Soap Co.', data: { myicon: 'fries' } },\n        { id: '3', text: 'Cyberdyne Systems', data: { myicon: 'football' } },\n        // ...\n    ],\n    lines: [\n        { from: '7', to: '71', text: 'Invest' },\n```\n\nThis startup sequence is the core bootstrapping pattern: load the JSON, then center and fit the graph after mount.\n\n```tsx\nconst graphInstance = RGHooks.useGraphInstance();\n\nconst initializeGraph = async () => {\n    await graphInstance.setJsonData(staticJsonData);\n    graphInstance.moveToCenter();\n    graphInstance.zoomToFit();\n};\n\nuseEffect(() => {\n    initializeGraph();\n}, []);\n```\n\nThis options block shows the example's layout and default graph styling choices.\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: true,\n    defaultLineShape: 1,\n    defaultNodeShape: RGNodeShape.circle,\n    defaultNodeWidth: 60,\n    defaultNodeHeight: 60,\n    defaultLineTextOnPath: true,\n    layout: { layoutName: 'center', maxLayoutTimes: 3000 },\n    defaultExpandHolderPosition: 'right',\n    reLayoutWhenExpandedOrCollapsed: true\n};\n```\n\nThis graph body shows that custom node rendering and the minimap are both attached through relation-graph slots.\n\n```tsx\n\u003CRelationGraph\n    options={graphOptions}\n    onNodeClick={onNodeClick}\n    onLineClick={onLineClick}\n>\n    \u003CRGSlotOnNode>\n        {({ node, checked, dragging }: RGNodeSlotProps) => (\n            \u003CCustomNode node={node} checked={checked} dragging={dragging} />\n        )}\n    \u003C/RGSlotOnNode>\n    \u003CRGSlotOnView>\n        \u003CRGMiniView />\n    \u003C/RGSlotOnView>\n\u003C/RelationGraph>\n```\n\nThis branch in `CustomNode` proves that the root node and child nodes intentionally use different visual templates.\n\n```tsx\nconst CustomNode: React.FC\u003CRGNodeSlotProps> = ({ node }) => {\n    if (node.id === '2') {\n        return (\n            \u003Cdiv className=\"my-node-animation-01 z-[555] h-full w-full rounded-full relative text-lg flex place-items-center justify-center overflow-hidden\">\n                \u003Cdiv className=\"py-2 w-full text-center text-white bg-gray-100 bg-opacity-40 border-t border-b border-gray-500\">\n                    {node.text}\n                \u003C/div>\n            \u003C/div>\n        );\n    }\n```\n\nThis child-node fragment shows how the same slot renderer turns `node.data.myicon` into icon-based circular nodes with detached labels below.\n\n```tsx\nreturn (\n    \u003Cdiv className=\"h-full w-full rounded-full flex place-items-center justify-center shadow-md\">\n        \u003CIconSwitcher iconName={node.data?.myicon} size={30} />\n        \u003Cdiv\n            className=\"bg-gray-200 text-black px-2 rounded-lg absolute my-node-text\"\n            style={{ marginTop: '100%', transform: 'translateY(15px)' }}\n        >\n            {node.text}\n        \u003C/div>\n    \u003C/div>\n);\n```\n\nThis SCSS fragment proves that the example customizes relation-graph's checked-state styling instead of leaving the default selection colors unchanged.\n\n```scss\n.rg-node-peel.rg-node-checked {\n    .rg-node {\n        color: #f43ce5;\n        .my-node-text {\n            color: #f43ce5;\n        }\n    }\n}\n\n.rg-line-peel.rg-line-checked {\n    .rg-line {\n        stroke: #f43ce5;\n```\n\n## What Makes This Example Distinct\n\nThe comparison data describes this example as a low-friction starter rather than a menu demo, tooltip demo, or toolbar demo. Its most distinctive trait is the compact combination of provider-scoped startup, one inline `RGJsonData` payload, root-versus-child custom node rendering, checked-state style overrides, and an always-mounted minimap in the same read-only viewer.\n\nCompared with `node-menu-2` and `node-menu`, this example uses `RGSlotOnView` as a passive navigation aid through `RGMiniView`, not as a contextual action surface. Compared with `node-tips`, it emphasizes persistent overview navigation and a stronger visual identity instead of hover inspection. Compared with `toolbar-buttons`, its main lesson is custom node composition rather than custom graph chrome or minimap toggling.\n\nIt is important to keep the claim narrow. The comparison record does not support saying this is the only example with custom node slots or the only example with a minimap. What it does support is that this example is a particularly compact reference when a team wants one small baseline that combines those pieces without also introducing menu state, tooltip state, or toolbar state.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to lightweight ownership maps, service dependency viewers, ecosystem maps, organization diagrams, and product-relationship screens where the immediate need is a readable branded viewer rather than an editor. The same inline-data-plus-slot structure can be replaced with API data while keeping the startup sequence unchanged.\n\nIt also scales into richer interfaces. A team could keep the same `RGProvider` setup, graph-instance initialization flow, and `RGSlotOnNode` customization, then add detail drawers, hover panels, filter controls, or business-specific click actions later. The example is useful precisely because those extensions are not implemented yet, so the baseline remains easy to copy and extend.\n",false,500,1782615370605]