[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:built-in-toolbar-position-and-theme":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Runtime Built-in Toolbar Placement and Theme Switching\n\n## What This Example Builds\n\nThis example builds a full-height graph viewer whose main subject is relation-graph's built-in toolbar rather than the graph data itself. The canvas loads a single node, keeps the default toolbar visible, and places a floating white control window above the graph.\n\nUsers can switch the toolbar between vertical and horizontal orientation, move it across three horizontal and three vertical anchor positions, and apply three wrapper-driven color themes. The same helper window can also be dragged, minimized, opened into a shared canvas-settings overlay, and used to export an image. The main point is that the toolbar is customized in place instead of being replaced by custom slot content.\n\n## How the Data Is Organized\n\nThe graph data is created inline inside `initializeGraph()` as one `RGJsonData` object with `rootId: 'a'`, one node, and no lines. There is no external fetch, no derived layout payload, and no preprocessing stage beyond assembling that literal object.\n\nAfter `setJsonData()` runs, the graph instance recenters the view with `moveToCenter()` and `zoomToFit()`. Every later change operates on toolbar options or wrapper classes, not on nodes or edges. In a real application, the same pattern could front a larger dataset, but this nearly empty graph keeps attention on toolbar behavior and CSS skinning.\n\n## How relation-graph Is Used\n\n`index.tsx` wraps the demo in `RGProvider`, and `MyGraph.tsx` reads the active instance with `RGHooks.useGraphInstance()`. The example keeps its graph options narrow: `debug: false`, plus `toolBarDirection`, `toolBarPositionH`, and `toolBarPositionV` derived from React state. No custom layout, node slot, line slot, or editing API is introduced, because the graph content is intentionally minimal.\n\nInitialization happens through graph-instance APIs. The component assembles one inline dataset, calls `setJsonData()`, then `moveToCenter()` and `zoomToFit()`. A second effect watches the toolbar direction and position states and pushes those values into the live graph through `graphInstance.updateOptions(...)`.\n\nToolbar styling is handled outside the options object. The outer wrapper class `my-toolbar-style-*` changes with local state, and the SCSS file scopes red, green, and blue overrides to `.rg-toolbar`. The floating helper window comes from the shared `DraggableWindow` component. That helper uses `RGHooks.useGraphStore()` and `graphInstance.setOptions()` for wheel and drag settings, and it uses `prepareForImageGeneration()` plus `restoreAfterImageGeneration()` for image export. Those utilities are real interactions in this demo, but they are shared scaffolding rather than the unique lesson of this example.\n\n## Key Interactions\n\n- The style selector switches between the default toolbar skin and three wrapper-driven theme variants.\n- The horizontal, vertical, and direction selectors update React state, and a dependent effect pushes the new toolbar placement options into the live graph with `updateOptions(...)`.\n- The floating control window can be dragged by its title bar, minimized, and opened into a settings overlay.\n- The shared settings overlay can change wheel behavior, change canvas drag behavior, and download an image of the current graph.\n\n## Key Code Fragments\n\nThis options block shows that the example's own graph configuration is almost entirely about the built-in toolbar.\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: false,\n    toolBarDirection: toolBarDirection as 'v' | 'h',\n    toolBarPositionH: toolBarPositionH as 'left' | 'center' | 'right',\n    toolBarPositionV: toolBarPositionV as 'top' | 'center' | 'bottom'\n};\n```\n\nThis initialization code proves that the dataset is a one-node inline payload and that the viewport is normalized immediately after load.\n\n```tsx\nconst myJsonData: RGJsonData = {\n    rootId: 'a',\n    nodes: [\n        { id: 'a', text: 'Set Toolbar Position' },\n    ],\n    lines: [\n    ]\n};\n\nawait graphInstance.setJsonData(myJsonData);\ngraphInstance.moveToCenter();\ngraphInstance.zoomToFit();\n```\n\nThis effect pair is the core runtime pattern: load once, then update toolbar direction and placement on the existing graph instance.\n\n```tsx\nconst updateGraphOptions = () => {\n    graphInstance.updateOptions({\n        toolBarDirection: toolBarDirection as 'v' | 'h',\n        toolBarPositionH: toolBarPositionH as 'left' | 'center' | 'right',\n        toolBarPositionV: toolBarPositionV as 'top' | 'center' | 'bottom'\n    });\n};\n\nuseEffect(() => {\n    updateGraphOptions();\n}, [toolBarDirection, toolBarPositionH, toolBarPositionV]);\n```\n\nThis render fragment shows that the control surface lives outside the graph and that style switching happens by changing the wrapper class suffix.\n\n```tsx\n\u003Cdiv className={`my-graph my-toolbar-style-${toolBarStyle}`} style={{ height: '100vh' }}>\n    \u003CDraggableWindow initialLeft={200} initialTop={150}>\n        \u003Cdiv className=\"c-option-name\">Toolbar Style:\u003C/div>\n        \u003CSimpleUISelect\n            data={[\n                { value: '', text: 'Default' },\n                { value: '1', text: 'Style 1' },\n                { value: '2', text: 'Style 2' },\n                { value: '3', text: 'Style 3' }\n            ]}\n            currentValue={toolBarStyle}\n            onChange={(newValue: string) => setToolBarStyle(newValue)}\n        />\n```\n\nThis SCSS fragment is the proof that theme changes target the built-in `.rg-toolbar` instead of replacing the toolbar with custom markup.\n\n```scss\n&.my-toolbar-style-1 .relation-graph {\n    .rg-toolbar {\n        background-color: rgba(203, 7, 7, 0.2);\n        color: #d9001b;\n    }\n}\n\n&.my-toolbar-style-2 .relation-graph {\n    .rg-toolbar {\n        background-color: rgba(61, 150, 2, 0.8);\n        color: #ffffff;\n    }\n}\n```\n\nThis shared helper code shows how image export is implemented through graph-instance APIs rather than through a custom canvas wrapper.\n\n```tsx\nconst downloadImage = async () => {\n    const canvasDom = await graphInstance.prepareForImageGeneration();\n    let graphBackgroundColor = graphInstance.getOptions().backgroundColor;\n    if (!graphBackgroundColor || graphBackgroundColor === 'transparent') {\n        graphBackgroundColor = '#ffffff';\n    }\n    const imageBlob = await domToImageByModernScreenshot(canvasDom, {\n        backgroundColor: graphBackgroundColor\n    });\n    if (imageBlob) {\n        downloadBlob(imageBlob, 'my-image-name');\n    }\n    await graphInstance.restoreAfterImageGeneration();\n};\n```\n\n## What Makes This Example Distinct\n\nThe comparison record places this demo near `layout-center`, `gee-thumbnail-diagram`, `diy-line-arrow`, `center-layout-options`, and `line-style2`, but it teaches a different layer of customization. Against `gee-thumbnail-diagram`, it keeps the built-in toolbar visible and repositions that widget directly, instead of hiding the toolbar and mounting a separate `RGMiniView` overlay.\n\nAgainst `layout-center`, `center-layout-options`, and `diy-line-arrow`, the runtime controls do not relayout the graph, change line markers, or batch-update nodes and edges. They only update `toolBarDirection`, `toolBarPositionH`, and `toolBarPositionV` on an already loaded graph. The comparison and rarity records also call out the nearly empty one-node canvas as part of the point: it removes graph-structure noise so toolbar behavior is easier to inspect.\n\nAgainst `line-style2`, the wrapper classes target `.rg-toolbar` rather than checked-line selectors. That makes this example a stronger starting point when a project wants to keep relation-graph's default toolbar, move it at runtime, and reskin it with scoped CSS instead of replacing it with custom slot content.\n\n## Where Else This Pattern Applies\n\n- White-label graph embeds that need brand-specific toolbar skins without rebuilding the toolbar.\n- Dashboards or admin tools where toolbar position must move to avoid overlapping other floating panels or legends.\n- Internal playgrounds used to validate interaction defaults such as wheel zoom, drag mode, and export behavior around a standard graph viewer.\n- Documentation or design-system pages that need a minimal dataset so teams can judge control chrome without layout noise.\n",false,500,1782615420240]