[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:top-down-tree-expand-relayout-toggle":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Live Expand/Collapse Relayout in a Top-Down Tree\n\n## What This Example Builds\n\nThis example builds a full-height top-down tree for comparing what happens after a user clicks relation-graph's built-in expand or collapse control. The canvas shows a narrow cyan hierarchy with curved teal connectors, bottom-positioned expand holders, and a floating white helper window that stays above the graph.\n\nUsers can expand or collapse branches directly on the graph, switch the post-expand behavior between `Re-layout` and `Do not re-layout`, drag the helper window to another screen position, minimize it, and open a secondary settings overlay. That overlay is inherited from a shared local helper and adds canvas wheel-mode, canvas drag-mode, and image-download controls, but the main lesson of this example is the runtime toggle for `reLayoutWhenExpandedOrCollapsed`, not custom transition timing.\n\n## How the Data Is Organized\n\nThe data is declared inline inside `initializeGraph()` as one `RGJsonData` object. It uses `rootId: 'a'`, defines 16 hard-coded nodes, and connects them with 15 explicit lines. The structure is a simple fixed hierarchy rather than a domain model with extra metadata, which keeps attention on expand or collapse behavior instead of on content semantics.\n\nThere is no preprocessing step before `setJsonData(...)`. The component does not fetch remote data, normalize records, or derive a second structure for layout. In a real application, the same shape could represent an org subtree, a product taxonomy, a folder tree, a dependency breakdown, or any other hierarchy where the product team needs to decide whether expanding one branch should trigger a fresh layout for the whole visible tree.\n\n## How relation-graph Is Used\n\n`index.tsx` wraps the example in `RGProvider`, and `MyGraph.tsx` uses `RGHooks.useGraphInstance()` to drive the graph through the instance API. The graph options configure a `tree` layout that grows from the top, uses `treeNodeGapH: 40` and `treeNodeGapV: 200`, renders narrow rectangular nodes, and connects them with `RGLineShape.StandardCurve` plus `RGJunctionPoint.tb`. The visual result is a tall one-direction hierarchy where branch movement is easy to notice when nodes are expanded or collapsed.\n\nThe component loads data with `setJsonData(...)`, then immediately calls `moveToCenter()` and `zoomToFit()` so the full tree starts centered in view. A second effect watches the React `relayout` state and pushes it into the mounted graph with `updateOptions({ reLayoutWhenExpandedOrCollapsed })`. That is the core relation-graph technique in this demo: the layout rule changes at runtime without rebuilding the dataset or remounting the graph component.\n\nThere are no custom node, line, canvas, or viewport slots in this example, and there are no explicit graph event handlers in the example-specific code. Expand or collapse behavior comes from relation-graph's built-in expand holder, which is positioned at the bottom of each node through `defaultExpandHolderPosition: 'bottom'`. The example also does not implement editing, authoring, or manual layout logic.\n\nThe floating control surface comes from the local `DraggableWindow` helper. That helper is not unique to this example, but it matters here because it makes the relayout selector movable and also provides a shared settings overlay. Inside that overlay, `CanvasSettingsPanel` uses `RGHooks.useGraphStore()` to read the current `wheelEventAction` and `dragEventAction`, then calls `graphInstance.setOptions(...)` to update those values on the live graph. It also uses `prepareForImageGeneration()`, `getOptions()`, and `restoreAfterImageGeneration()` to support a download action. The local SCSS file only defines empty wrapper selectors, so nearly all visible styling comes from graph options and the shared floating window rather than from custom relation-graph CSS overrides.\n\n## Key Interactions\n\n- Clicking a built-in expand holder opens or closes a branch in the tree.\n- Clicking `Re-layout` or `Do not re-layout` updates `reLayoutWhenExpandedOrCollapsed` on the mounted graph, so the next expand or collapse action either repacks the tree or preserves the current branch positions.\n- The helper window can be dragged by its title bar, which keeps the control surface movable instead of occupying a fixed part of the canvas.\n- The helper window can be minimized, so the example can switch between a teaching mode with visible controls and a cleaner viewing mode.\n- The settings button opens a secondary overlay that can switch wheel behavior, switch canvas drag behavior, and download the current graph as an image. Those controls come from the shared helper rather than from the example's own tree logic.\n\n## Key Code Fragments\n\nThis fragment shows that the example is deliberately configured as a top-down tree with wide vertical spacing and bottom expand controls so branch reflow is easy to observe:\n\n```tsx\nconst graphOptions: RGOptions = {\n    layout: {\n        layoutName: 'tree',\n        from: 'top',\n        treeNodeGapH: 40,\n        treeNodeGapV: 200\n    },\n    // ... visual defaults omitted\n    defaultLineShape: RGLineShape.StandardCurve,\n    defaultJunctionPoint: RGJunctionPoint.tb,\n    defaultExpandHolderPosition: 'bottom'\n};\n```\n\nThis fragment shows that the hierarchy is assembled inline rather than fetched or transformed from another source:\n\n```tsx\nconst myJsonData: RGJsonData = {\n    rootId: 'a',\n    nodes: [\n        { id: 'a', text: 'a' },\n        { id: 'b', text: 'b' },\n        { id: 'b1', text: 'b1' },\n        // ... more nodes\n    ],\n    lines: [\n        { id: 'l1', from: 'a', to: 'b' },\n        // ... more lines\n    ]\n};\n```\n\nThis fragment shows the mount-time loading pattern: load the data once, then center and fit the result:\n\n```tsx\nawait graphInstance.setJsonData(myJsonData);\ngraphInstance.moveToCenter();\ngraphInstance.zoomToFit();\n```\n\nThis fragment shows the runtime option-synchronization pattern that makes the example distinct:\n\n```tsx\nconst syncOptionsToGraph = () => {\n    graphInstance.updateOptions({\n        reLayoutWhenExpandedOrCollapsed: relayout\n    });\n};\n\nuseEffect(() => {\n    syncOptionsToGraph();\n}, [relayout]);\n```\n\nThis fragment shows that the UI exposes the relayout choice as a direct boolean selector instead of as a rebuild or reset action:\n\n```tsx\n\u003CSimpleUISelect\n    data={[\n        { value: true, text: 'Re-layout' },\n        { value: false, text: 'Do not re-layout' }\n    ]}\n    currentValue={relayout}\n    onChange={(newValue: boolean) => {\n        setRelayout(newValue);\n    }}\n/>\n```\n\nThis fragment shows how the shared floating window can reveal a secondary settings surface above the main selector:\n\n```tsx\n{\n    showSettingPanel &&\n    \u003Cdiv className=\"absolute w-full h-full left-0 top-[35px]\">\n        \u003Cdiv className=\"absolute z-10 w-full h-full left-0 bg-white/90\" onClick={() => { setShowSettingPanel(false); }}>\u003C/div>\n        \u003Cdiv className=\"absolute z-20 w-full bg-gray-50 border-b border-gray-200\">\n            \u003CCanvasSettingsPanel />\n        \u003C/div>\n    \u003C/div>\n}\n```\n\nThis fragment shows that the shared overlay updates graph interaction modes through the live instance rather than through a page reload:\n\n```tsx\nconst { options } = RGHooks.useGraphStore();\nconst dragMode = options.dragEventAction;\nconst wheelMode = options.wheelEventAction;\n\n\u003CSettingRow\n    label=\"Wheel Event:\"\n    value={wheelMode}\n    onChange={(newValue: string) => { graphInstance.setOptions({ wheelEventAction: newValue }); }}\n/>\n```\n\n## What Makes This Example Distinct\n\nThe comparison data shows that this example is closest to `expand-animation2`, `open-all-close-all`, `expand-gradually`, and `layout-tree`, but its scope is narrower than each of them. Against `expand-animation2`, it applies the same relayout decision to a one-direction top-down tree instead of a root-centered layout. Against `open-all-close-all`, it does not script timed whole-graph playback and does not teach animation orchestration. Against `expand-gradually`, it does not focus on initial collapse rules. Against `layout-tree`, it does not compare multiple layout presets or rewrite node properties before layout.\n\nWhat makes it stand out is the combination of a live `reLayoutWhenExpandedOrCollapsed` toggle, a top-down tree with bottom expand holders, top-bottom junction points, wide level spacing, and a minimal yes-or-no control panel. That combination makes it a strong starting point when a product team already knows it wants a vertical hierarchy and only needs to decide whether expanding a branch should preserve current positions or trigger a fresh reflow.\n\nThe comparison artifact also makes one boundary clear: this is not evidence of custom animation timing, easing, or transition code. The example is about post-expand relayout behavior in relation-graph, not about authoring bespoke animations.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to any hierarchical UI where disclosure behavior has to be chosen deliberately instead of accepted as a default. Examples include org charts, category trees, workflow breakdowns, policy trees, troubleshooting trees, and dependency views where users repeatedly open and close branches while keeping spatial orientation.\n\nIt is also a practical reference for configuration-heavy graph products. The same approach can be extended into user-facing behavior toggles, admin settings for hierarchy views, A/B comparisons of disclosure rules, or QA harnesses that verify how a tree feels when relayout is enabled versus disabled without changing the underlying dataset.\n",false,500,1782615433809]