[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:bidirectional-tree-line-direction-faq":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Explaining Bidirectional Tree Arrow Direction with Two Matched Graph Views\n\n## What This Example Builds\n\nThis example builds a full-height comparison page with two relation-graph canvases and a fixed explanatory column between them. Both canvases render the same root-centered bidirectional tree: one branch set grows upward toward the `R-*` nodes, and another grows downward toward the child nodes below `a`.\n\nThe visible difference is concentrated in the upper half of the tree. The left graph shows the baseline presentation, while the right graph colors the upper links red and changes their visible arrowheads so those links appear to point upward. Users can click nodes and lines to inspect the underlying objects in the console, but the main experience is the side-by-side visual comparison. The key point is that the example changes perceived line direction without changing the top-down relationship structure required by the tree layout.\n\n## How the Data Is Organized\n\nThe graph data is created inline by `getMyJsonData(forRightPanel)` in `MyGraph.tsx`. It returns one `RGJsonData` object with `rootId: 'a'`, a `nodes` array, and a `lines` array. There is no external fetch and no preprocessing pipeline before `setJsonData()`. The only transformation is inside that helper: when `forRightPanel` is `true`, it assigns `showStartArrow = true`, `showEndArrow = false`, and `color = '#ff0000'` before constructing the upper-branch lines.\n\nThat structure keeps the comparison narrow. The same rooted tree model is reused in both panes, and only the line metadata for the upper branch changes. The dataset also sets `expandHolderPosition: 'top'` on `R-c` and `expandHolderPosition: 'bottom'` on `c`, which reinforces the bidirectional tree behavior around the same root.\n\nIn a real project, this data shape could represent upstream and downstream services, parent and child records in a genealogy or org chart, prerequisites and follow-up tasks, or causes and effects in an incident analysis tree. The important transferable idea is that the graph can keep one consistent relationship model while varying the rendered arrow semantics on selected branches.\n\n## How relation-graph Is Used\n\n`index.tsx` creates the page shell and wraps each graph pane in its own `RGProvider`, so the left and right canvases have separate graph-instance contexts. `MyGraph.tsx` uses `RGHooks.useGraphInstance()` inside each pane component, then runs the same mount-time initialization sequence: `updateOptions()`, `setJsonData()`, `moveToCenter()`, and `zoomToFit()`.\n\nThe shared `graphOptions` object uses a tree layout with `layoutName: 'tree'` and `from: 'top'`, so the structure is arranged vertically. It also sets `treeNodeGapH: 20`, `treeNodeGapV: 100`, rectangular nodes, `RGLineShape.SimpleOrthogonal`, fixed default node dimensions, and `RGJunctionPoint.tb` so vertical connections stay legible in the two-way tree.\n\nThis example does not use node slots, line slots, canvas slots, editing APIs, or runtime mode switches. It relies on built-in rendering plus per-line metadata inside the dataset. Styling is minimal and local: `my-relation-graph.scss` scopes node text to black, `14px` text inside the `.my-graph` wrapper, while most of the page framing comes from inline layout styles in `index.tsx`.\n\n## Key Interactions\n\nThe primary interaction is comparison rather than manipulation. The page presents two pre-rendered graph states at the same time, so the viewer can inspect how one line-option change affects only the upper branch.\n\nNode clicks and line clicks are wired in both graphs, but they only log the selected `RGNode` or `RGLine` object. They do not expand branches, edit the graph, or switch between variants. The two panes are also initialized automatically on mount, so the comparison is ready without any setup controls.\n\n## Key Code Fragments\n\nThis fragment shows that the right-hand variant is created by toggling arrow flags and color before the dataset is built.\n\n```tsx\nconst getMyJsonData = (forRightPanel = false): RGJsonData => {\n    let showStartArrow, showEndArrow, color;\n    if (forRightPanel) {\n        showStartArrow = true;\n        showEndArrow = false;\n        color = '#ff0000';\n    }\n```\n\nThis fragment shows that the upper branch keeps the same `from` and `to` structure while reusing those variant-specific line properties.\n\n```tsx\nlines: [\n    { from: 'R-b', to: 'a', showStartArrow, showEndArrow, color },\n    { from: 'R-c', to: 'a', showStartArrow, showEndArrow, color },\n    { from: 'R-c-1', to: 'R-c', showStartArrow, showEndArrow, color },\n    { from: 'R-c-2', to: 'R-c', showStartArrow, showEndArrow, color },\n    { from: 'R-d', to: 'a', showStartArrow, showEndArrow, color },\n    { from: 'a', to: 'b' },\n```\n\nThis fragment shows the shared tree configuration that both panes use.\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: false,\n    layout: {\n        layoutName: 'tree',\n        from: 'top',\n        treeNodeGapH: 20,\n        treeNodeGapV: 100,\n    },\n    defaultNodeShape: RGNodeShape.rect,\n    defaultLineShape: RGLineShape.SimpleOrthogonal,\n    defaultNodeWidth: 80,\n    defaultNodeHeight: 40,\n    defaultJunctionPoint: RGJunctionPoint.tb\n};\n```\n\nThis fragment shows that each pane uses the graph instance API to load data and fit the viewport, with the right pane selecting the variant dataset.\n\n```tsx\nuseEffect(() => {\n    const init = async () => {\n        graphInstance.updateOptions(graphOptions);\n        await graphInstance.setJsonData(getMyJsonData(true));\n        graphInstance.moveToCenter();\n        graphInstance.zoomToFit();\n    };\n    init();\n}, []);\n```\n\nThis fragment shows that the page is intentionally composed as a left graph, an explanatory note column, and a right graph.\n\n```tsx\n\u003Cdiv className=\"my-graph\" style={{ display: 'flex' }}>\n    \u003Cdiv style={{ height: 'calc(100vh)', width: 'calc((100% - 300px) / 2)' }}>\n        \u003CRGProvider>\n            \u003CMyGraphLeft />\n        \u003C/RGProvider>\n    \u003C/div>\n\n    \u003Cdiv style={{ height: 'calc(100vh)', width: '300px', borderLeft: '#efefef solid 1px', borderRight: '#efefef solid 1px', padding: '15px', fontSize: '14px', lineHeight: '25px', overflowY: 'auto' }}>\n```\n\n## What Makes This Example Distinct\n\nThe comparison analysis makes this example's role clear: it is not a general tree demo and not a broad line-feature catalog. Its distinctive value is that it answers one specific bidirectional-tree FAQ by showing two nearly identical graph instances at once. The only intended lesson is how parent-side links can look reversed by changing `showStartArrow` and `showEndArrow`, while the underlying top-down relationship data still stays compatible with the layout.\n\nCompared with `bothway-tree2`, this example is much narrower and more static. `bothway-tree2` explores orientation switching and branch-specific tuning inside one graph, while this example hard-codes two states in separate panes so the arrow-direction lesson is easier to isolate. Compared with `advanced-line-usage` and `line`, this example is more hierarchy-specific: it is not teaching a catalog of line shapes, junction anchors, or label styles, but one ambiguity that only becomes meaningful in a root-centered two-way tree.\n\nAnother uncommon detail is the surrounding scaffold. The fixed center note column, duplicated providers, opposite expand-holder positions on the upper and lower branches, and red upper-line variant together make the example read like a FAQ answer rather than a playground. That makes it a stronger starting point when the requirement is to explain one rendering rule clearly instead of exposing many controls.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to technical documentation, QA samples, and onboarding material where a team needs to prove the visual effect of one graph option change. A before-and-after pair of canvases is often clearer than a runtime toggle when the goal is to explain why one rendering is correct.\n\nThe same structure also fits upstream and downstream dependency trees, parent and child entity diagrams, lineage views, approval hierarchies, and fault-analysis trees. In those cases, the graph can preserve one stable data direction for layout and processing while using line metadata to present branch direction in the way users expect to read it.\n",false,500,1782615384270]