[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:custom-line-arrow-presets":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Comparing Custom Arrowhead Presets Across Tree and Center Layouts\n\n## What This Example Builds\n\nThis example builds a small subsystem hierarchy viewer and turns it into an arrowhead comparison playground. The graph starts as a left-to-right tree with rectangular nodes, curved connectors, rounded line corners, and labels rendered along the line path. A floating panel lets the user switch among four custom SVG arrow presets and re-render the same hierarchy in either `tree` or `center` layout, while the shared panel shell also adds drag, minimize, settings, and image export controls.\n\nThe main point is not custom line rendering. It is a focused demonstration of how far the built-in relation-graph line renderer can be pushed by supplying marker objects through `defaultLineMarker` and updating those options on an already loaded graph instance.\n\n## How the Data Is Organized\n\nThe graph data is assembled inline as one `RGJsonData` object inside `initializeGraph()`. It has a fixed `rootId`, fifteen named nodes, and fourteen lines, all labeled `Subsystem`. There is no fetch step, no external normalization step, and no per-line styling payload.\n\nThe only preprocessing is the module-level `myArrows` array. Each entry is a raw SVG marker definition with its own `viewBox`, marker size, reference point, and path data. React state selects one of those definitions, and that marker becomes the graph-wide default arrowhead.\n\nIn a real system, the same data shape could represent equipment hierarchies, service dependencies, workflow stages, or any small rooted structure where a single line-end convention should be evaluated across the whole graph.\n\n## How relation-graph Is Used\n\n`index.tsx` wraps the example in `RGProvider`, and `MyGraph.tsx` renders a single `RelationGraph` instance with one `graphOptions` object. Those options establish the initial left-to-right tree, set explicit node spacing, place the built-in toolbar at the bottom center, enable rounded polyline corners, and keep line labels attached to the line path.\n\nThe example relies on `RGHooks.useGraphInstance()` instead of rebuilding the graph component. On mount it calls `setJsonData(...)`, then `moveToCenter()` and `zoomToFit()`. When the layout mode changes it calls `updateOptions(...)`, `doLayout()`, `moveToCenter()`, and `zoomToFit()` again. When the selected arrow preset changes it updates only `defaultLineMarker`, which keeps the dataset intact and changes presentation in place.\n\nThis demo does not use node slots, line slots, canvas slots, or editing APIs. It stays on the built-in relation-graph renderer and customizes it through options plus a local stylesheet override. The SCSS keeps the graph under `.my-graph` and forces `.rg-node` to render with a white background, which makes the different marker shapes easier to read on a light canvas.\n\nThe floating panel is also part of the implementation pattern. `DraggableWindow` supplies the movable shell, `SimpleUISelect` supplies the chip-style selectors, and the shared `CanvasSettingsPanel` adds wheel-mode switching, drag-mode switching, and image export through graph-instance APIs. Those utilities are real features in the page, but they are inherited scaffolding rather than the distinctive lesson of this example.\n\n## Key Interactions\n\n- Selecting `My Arrow 1` through `My Arrow 4` updates `myArrowIndex` and immediately replaces `defaultLineMarker` on the live graph.\n- Switching between `Tree` and `Center` changes `layoutName` and also remaps node shape, line shape, and junction behavior before calling `doLayout()`.\n- The floating control window can be dragged by its title bar and collapsed with the minimize button.\n- The gear button opens a shared settings overlay where wheel behavior can switch between `scroll`, `zoom`, and `none`, and canvas drag behavior can switch between `selection`, `move`, and `none`.\n- The shared settings overlay can export the current graph image by preparing the graph DOM, rendering it to a blob with `modern-screenshot`, and downloading the result.\n\n## Key Code Fragments\n\nThis marker array is the core customization input: the example defines raw SVG arrowheads instead of replacing relation-graph's line renderer.\n\n```tsx\nconst myArrows = [\n    {\n        viewBox: '0 0 12 12',\n        markerWidth: 30,\n        markerHeight: 30,\n        refX: 3,\n        refY: 3,\n        data: 'M 0 0, V 6, L 4 3, Z'\n    },\n    // ...\n];\n```\n\nThis options block shows that the initial tree layout and the custom marker are configured together on the main graph instance.\n\n```tsx\nconst graphOptions: RGOptions = {\n    defaultNodeShape: RGNodeShape.rect,\n    defaultLineShape: RGLineShape.StandardCurve,\n    defaultJunctionPoint: RGJunctionPoint.lr,\n    toolBarDirection: 'h',\n    toolBarPositionH: 'center',\n    toolBarPositionV: 'bottom',\n    defaultPolyLineRadius: 10,\n    defaultLineTextOnPath: true,\n    layout: {\n        layoutName: 'tree',\n        from: 'left',\n        treeNodeGapH: 200,\n        treeNodeGapV: 10\n    },\n    defaultLineMarker: myArrows[myArrowIndex]\n};\n```\n\nThis branch proves that layout switching is more than a layout name change: it also swaps node geometry and connector behavior before rerunning layout.\n\n```tsx\nif (layoutName === 'center') {\n    graphInstance.updateOptions({\n        defaultNodeShape: RGNodeShape.circle,\n        defaultLineShape: RGLineShape.StandardStraight,\n        defaultJunctionPoint: RGJunctionPoint.border,\n        layout: {\n            layoutName: layoutName\n        }\n    });\n}\nawait graphInstance.doLayout();\ngraphInstance.moveToCenter();\ngraphInstance.zoomToFit();\n```\n\nThis effect shows the live marker-switching pattern: only the selected arrowhead option changes, while the loaded data stays in place.\n\n```tsx\nuseEffect(() => {\n    graphInstance.updateOptions({\n        defaultLineMarker: myArrows[myArrowIndex]\n    });\n}, [myArrowIndex]);\n```\n\n## What Makes This Example Distinct\n\nThe comparison data marks arrow preset selection and layout selection as very rare features in this example set, and that combination is the main reason this page stands out. It does not just show custom line styling once. It defines four raw SVG marker objects locally, applies them through `defaultLineMarker`, and lets the same dataset be judged in both a curved left-to-right tree and a straight-line center layout.\n\nCompared with `custom-line-animation` and `custom-line-style`, this example puts much more emphasis on endpoint marker geometry than on CSS class switching, animation presets, or stroke-and-label skinning. Compared with `div-on-line`, it is a graph-wide arrow comparison demo rather than a selected-edge geometry or DOM-overlay demo. Compared with `node-style2`, it starts from a similar tree baseline but turns that baseline into a two-mode presentation comparison without changing the underlying hierarchy.\n\nThe result is a more focused starting point for teams that want to test arrow readability and direction semantics before they commit to deeper custom line rendering.\n\n## Where Else This Pattern Applies\n\nThis pattern can be reused when a team needs to validate line-end semantics on one stable dataset before building more specialized rendering. Examples include workflow diagrams that need different arrowheads for approval, rejection, or handoff states; equipment and network topologies that must be reviewed in both hierarchical and hub-style layouts; and design-system demo pages that compare connector presets without rewriting graph data.\n\nIt also fits internal QA or review tools where analysts need a small option panel, export capability, and fast visual comparison between multiple connector styles. The transferable lesson is to keep the data model simple, keep the built-in renderer, and use runtime option updates to compare presentation choices on the same graph.\n",false,500,1782615377415]