[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:force-layout-isolated-nodes-with-hidden-helper-lines":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Keeping Isolated Nodes Visible in a Force Layout\n\n## What This Example Builds\n\nThis example builds a full-height relation-graph viewer for a sparse network that contains both small connected clusters and nodes that would otherwise be disconnected. The visible result is a force-driven canvas with uniform circular nodes, a few dark straight links, and many standalone-looking nodes that still remain part of the loaded graph. The main point is not domain modeling or editing. It is the preprocessing pattern that keeps isolated nodes present in a force layout without drawing the extra structural edges on screen.\n\n## How the Data Is Organized\n\nThe graph data is declared inline as one `RGJsonData` object inside `initializeGraph()`. It starts with 20 nodes and 5 visible lines, then the code performs one preprocessing pass before `setJsonData(...)` runs: it derives `rootId` from the first node in the array, assigns that value back to the dataset, and appends one hidden line from that root to every other node by using generated `l-hidden-*` ids and `opacity: 0`.\n\nThat means the runtime graph is more connected than the visible graph. In a real application, the same structure could represent people with no current collaboration links, devices with incomplete topology data, or catalog entities that should stay visible even when explicit relationships are missing.\n\n## How relation-graph Is Used\n\n`index.tsx` wraps the example in `RGProvider`, and `MyGraph.tsx` retrieves the mounted graph instance through `RGHooks.useGraphInstance()`. The graph options define the example's whole visual behavior: border junction points, circular nodes, straight lines, 60 by 60 default node size, dark gray visible edges, and the built-in `force` layout with `force_node_repulsion: 0.5`.\n\nThe example does not use slots, editing APIs, or custom subcomponents beyond the provider and the main `RelationGraph` canvas. Its runtime flow is deliberately small: a mount-only `useEffect(...)` calls `initializeGraph()`, the data is augmented in memory, then the graph instance runs `setJsonData(...)`, `moveToCenter()`, and `zoomToFit()`. The local SCSS file is only a scaffold of empty selectors, and `MyGraph.tsx` does not import it, so the visible presentation comes primarily from graph options and the inline `height: '100vh'` container.\n\n## Key Interactions\n\nThe first interaction is automatic rather than user-triggered: when the component mounts, the graph loads, centers itself, and fits to the viewport. After that, the example exposes node-click and line-click handlers, but both are inspection hooks only. They log the clicked object to the console and do not change the graph, open panels, or start editing.\n\n## Key Code Fragments\n\nThis options block shows that the example is explicitly a force-layout viewer with circular nodes and straight dark-gray visible links.\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: false,\n    defaultJunctionPoint: RGJunctionPoint.border,\n    defaultNodeShape: RGNodeShape.circle,\n    defaultLineShape: RGLineShape.StandardStraight,\n    defaultNodeWidth: 60,\n    defaultNodeHeight: 60,\n    defaultLineWidth: 2,\n    defaultLineColor: '#333333',\n    layout: {\n        layoutName: 'force',\n        force_node_repulsion: 0.5\n    }\n};\n```\n\nThis preprocessing step is the core workaround: it derives a root and injects invisible helper lines before the dataset is loaded.\n\n```tsx\nconst rootId = myJsonData.nodes[0].id;\nmyJsonData.rootId = rootId;\n\nmyJsonData.nodes.forEach(n => {\n    if (n.id !== rootId) {\n        myJsonData.lines.push({\n            id: `l-hidden-${n.id}`,\n            from: rootId,\n            to: n.id,\n            opacity: 0\n        });\n    }\n});\n```\n\nThis fragment shows the minimal graph-instance bootstrap that turns the prepared data into the initial viewport state.\n\n```tsx\nawait graphInstance.setJsonData(myJsonData);\ngraphInstance.moveToCenter();\ngraphInstance.zoomToFit();\n```\n\nThis wrapper is what makes the hook-based graph instance available to `MyGraph`.\n\n```tsx\nconst Demo = () => {\n    return (\n        \u003CRGProvider>\n            \u003CMyGraph />\n        \u003C/RGProvider>\n    );\n};\n```\n\n## What Makes This Example Distinct\n\nAccording to the prepared comparison data, this example is distinctive because it applies the hidden-helper-edge workaround specifically to relation-graph's built-in `force` layout. Its closest siblings, `show-single-nodes` and `show-single-nodes3`, use the same root-derivation and invisible-edge strategy, but they frame it around circle-layout variants instead of force behavior. That makes this example the stronger starting point when disconnected-looking nodes still need to survive inside a force-driven scene.\n\nThe comparison data also separates it from broader fragmented-graph examples such as `multi-group-2`. That example renders disconnected groups more directly, while this one rewrites the payload to manufacture an invisible connected backbone before load. Compared with `advanced-line-usage`, the emphasis is also different: here the extra lines are structural and hidden, not visible line-style features. The rare combination is a small inline dataset, log-only click handlers, circular 60 by 60 nodes, straight dark-gray visible edges, and a preprocessing pass that makes sparse data workable in a force layout.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to graph views where incomplete relationship data should not cause records to disappear from the layout. Examples include employee maps that must still show unassigned staff, infrastructure graphs with orphan devices, product or customer graphs with partially imported links, and analysis dashboards that need every candidate entity on screen before relationship cleanup is finished.\n\nIt also works as an extension point for richer viewers. The hidden helper lines can stay as an internal loading tactic while visible links, filtering, detail panels, or selection styling are added later on top of the same preprocessing step.\n",false,500,1782615418413]