[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:batch-css-line-styles":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Batch-Switching CSS Line Styles on a Relation Graph Tree\n\n## What This Example Builds\n\nThis example builds a small left-to-right tree viewer whose main purpose is comparing relation-graph line skins. The canvas shows circular icon nodes, a green gradient background, and nine links that start with different `className` values, label modes, and curve settings.\n\nUsers can open a floating control window and switch all current lines to one of six predefined CSS families. The visible result is not just a stroke change. The line halo, dash pattern, detached label chip, and text-on-path color all change together, while the graph structure stays fixed.\n\nThe most useful idea here is that the example keeps relation-graph's built-in line renderer and still achieves strong visual variation through CSS classes and runtime `updateLine()` calls.\n\n## How the Data Is Organized\n\nThe data is declared inline in `initializeGraph()` as one `RGJsonData` object with `rootId`, a flat `nodes` array, and a flat `lines` array. Each node stores an icon key in `node.data.icon`, and each line can carry its own presentation metadata such as `className`, `useTextOnPath`, `lineShape`, `fromJunctionPoint`, and `toJunctionPoint`.\n\nThere is one preprocessing step before `setJsonData()`: the code rewrites every line label to `className=...`, so the graph immediately shows which class family each edge is using. After that, the JSON is loaded directly with no external fetch, no layout-time transformation, and no structural editing step.\n\nIn a real system, the same shape could represent a feature tree, service dependency map, workflow family, or product taxonomy. `node.data.icon` can stand for category or status, while the per-line metadata can represent relationship types, risk levels, transport modes, or other edge categories that need consistent CSS-based styling.\n\n## How relation-graph Is Used\n\n`index.tsx` wraps the example in `RGProvider`, so both the graph and the shared utility window resolve the same graph context. Inside `MyGraph.tsx`, `RelationGraph` is rendered with a tree layout that grows from left to right and uses wide spacing (`treeNodeGapH: 310`, `treeNodeGapV: 70`) so the icon nodes and label variations remain easy to compare.\n\nThe graph options establish a neutral base that CSS can restyle. Nodes are circular, transparent by default, outlined in white, and checked items receive a translucent white background token. Lines default to translucent white and straight segments, while a subset of records overrides itself to `RGLineShape.StandardCurve` with left-right junction points.\n\nThe example uses `RGHooks.useGraphInstance()` to load the dataset, center and fit the viewport, read the current rendered lines, and update each line after a style switch. `RGSlotOnNode` replaces the default node body with a Lucide icon chosen from `node.data.icon`. The example does not use a custom line slot. Instead, `my-relation-graph.scss` targets built-in relation-graph elements such as `.rg-line-peel`, `.rg-line-bg`, `.rg-line`, `.rg-line-label`, and `.rg-line-text`.\n\nThe floating helper UI comes from the shared `DraggableWindow` component. Its settings overlay uses `RGHooks.useGraphStore()` to reflect the current wheel and drag modes, and `setOptions(...)` to change them at runtime. The same helper also exposes image export through `prepareForImageGeneration()`, `getOptions()`, and `restoreAfterImageGeneration()`.\n\n## Key Interactions\n\nThe central interaction is the six-style selector in the floating window. Clicking one option updates local state, iterates `graphInstance.getLines()`, and rewrites every current line's `className` and visible text. The whole tree switches to one visual family in one pass.\n\nThe floating window itself is interactive. Users can drag it, minimize it, and reopen it without affecting the graph state.\n\nThe settings overlay adds two viewer-level controls: switching the wheel between scroll, zoom, and none, and switching canvas dragging between selection, move, and none. It also provides a download action that captures the current graph view as an image.\n\n## Key Code Fragments\n\nThis options block shows that layout and core geometry stay inside relation-graph while the visible styling is meant to be overridden from CSS.\n\n```tsx\nconst graphOptions: RGOptions = {\n    defaultLineColor: 'rgba(255, 255, 255, 0.6)',\n    defaultNodeColor: 'transparent',\n    defaultNodeBorderWidth: 1,\n    defaultNodeBorderColor: '#fff',\n    checkedItemBackgroundColor: 'rgba(255,255,255,0.3)',\n    defaultNodeShape: RGNodeShape.circle,\n    toolBarDirection: 'h',\n    toolBarPositionH: 'right',\n    toolBarPositionV: 'bottom',\n    defaultLineShape: RGLineShape.StandardStraight,\n    layout: {\n        layoutName: 'tree',\n        from: 'left',\n        treeNodeGapH: 310,\n        treeNodeGapV: 70\n    }\n};\n```\n\nThis data fragment shows that line presentation metadata is stored directly on each record before the graph is loaded.\n\n```tsx\nconst myJsonData: RGJsonData = {\n    rootId: 'a',\n    nodes: [\n        { id: 'a', text: 'a', data: { icon: 'align_bottom' } },\n        { id: 'b', text: 'b', data: { icon: 'basketball' } },\n        // ...\n    ],\n    lines: [\n        { id: 'line-1', from: 'a', to: 'b', text: 'Relation description', className: 'my-line-class-01' },\n        { id: 'line-3', from: 'a', to: 'b2', useTextOnPath: true, text: 'Relation description', className: 'my-line-class-02' },\n        { id: 'line-4', from: 'b2', to: 'b2-1', lineShape: RGLineShape.StandardCurve, fromJunctionPoint: RGJunctionPoint.lr, toJunctionPoint: RGJunctionPoint.lr, text: 'Relation description', className: 'my-line-class-02' }\n    ]\n};\n```\n\nThis preprocessing step proves that the example turns the line label itself into a live reference for the active class name.\n\n```tsx\nmyJsonData.lines.forEach(line => {\n   line.text = `className=${line.className || ''}`;\n});\nawait graphInstance.setJsonData(myJsonData);\ngraphInstance.moveToCenter();\ngraphInstance.zoomToFit();\n```\n\nThis update function is the core runtime behavior: it batch-rewrites every rendered line to the selected CSS family instead of rebuilding the JSON.\n\n```tsx\nconst changeAllLineClassName = (newClassName: string) => {\n    setLineStyle(newClassName);\n    const allLines = graphInstance.getLines();\n    allLines.forEach(line => {\n        graphInstance.updateLine(line.id, {\n            className: `my-line-class-${newClassName}`,\n            text: `className=${newClassName}`\n        });\n    });\n}\n```\n\nThis render fragment shows that the example combines a floating selector with a custom node slot, while leaving line rendering to relation-graph itself.\n\n```tsx\n\u003CDraggableWindow width={500}>\n    \u003Cdiv className=\"pb-4 text-base\">Define line style via CSS\u003C/div>\n    \u003Cdiv className=\"pb-2\">Change the className property of all lines in batch:\u003C/div>\n    \u003CSimpleUISelect\n        data={[\n            { value: '01', text: 'Style 01' },\n            { value: '02', text: 'Style 02' },\n            { value: '03', text: 'Style 03' }\n        ]}\n        onChange={(newValue: string) => changeAllLineClassName(newValue)}\n        currentValue={lineStyle}\n        small={true}\n    />\n\u003C/DraggableWindow>\n\u003CRelationGraph options={graphOptions}>\n    \u003CRGSlotOnNode>{/* icon node renderer */}\u003C/RGSlotOnNode>\n\u003C/RelationGraph>\n```\n\nThis SCSS fragment shows how one class family restyles both the line layers and the two label modes provided by the built-in renderer.\n\n```scss\n.rg-line-peel.my-line-class-01 {\n    .rg-line-bg {\n        stroke: rgba(244, 60, 229, 0.68);\n        stroke-width: calc(var(--rg-line-width) + 6px);\n        stroke-dasharray: 20, 20, 20;\n        opacity: 1;\n    }\n\n    .rg-line-label {\n        color: rgba(244, 60, 229, 1);\n        background-color: rgb(205, 204, 204);\n    }\n\n    .rg-line-text {\n        fill: rgba(244, 60, 229, 1);\n    }\n}\n```\n\nThis shared settings code shows that canvas behavior and export are adjusted through graph-instance APIs rather than separate page state.\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 data places this example closest to `custom-line-animation`, `line-style1`, `line-style2`, `customer-line1`, and `ever-changing-tree`, but its emphasis is narrower and more CSS-centered than those neighbors. Its strongest distinguishing point is that it keeps relation-graph's native line renderer, assigns per-line `className` metadata, and then batch-switches every rendered edge among six SCSS families from one floating selector.\n\nCompared with `custom-line-animation`, this example is less about motion presets or filter effects and more about static CSS skinning of built-in strokes, label chips, and path text. Compared with `line-style1` and `line-style2`, it goes beyond fixed line properties or checked-line emphasis by rewriting every current line's class at runtime.\n\nCompared with `customer-line1`, the important difference is architectural: this example does not replace edges with `RGSlotOnLine` geometry. It shows how far CSS can go while keeping the stock line renderer. The comparison data also notes that it is unusual within this cluster to use the same class system across both detached labels and `useTextOnPath` labels in one graph.\n\n## Where Else This Pattern Applies\n\nThis pattern applies to products where edge appearance should be owned by a design system rather than by custom SVG line rendering. Examples include workflow viewers, product dependency maps, service relationship dashboards, and taxonomy graphs where relationship categories need visually consistent CSS families.\n\nIt is also useful when one line-style mechanism has to cover different label modes at the same time. Teams can adapt the same approach when they need detached chips for some edges, text on path for others, and a runtime switcher for demos, white-label themes, training tools, or stakeholder review screens.\n",false,500,1782615375822]