[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:selection-create-or-select-nodes":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Create or Select Nodes by Drag Selection\n\n## What This Example Builds\nThis example builds a full-height relation-graph workspace seeded with 14 standalone lettered nodes and overlays it with two authoring controls: a draggable helper window and a compact top-center shape palette. The user can inspect the current selection rectangle, switch canvas behavior, and export an image without leaving the canvas.\n\nThe main outcome is a dual-purpose drag gesture. When no creation mode is armed, dragging a selection box picks existing nodes inside the region. When circle or rectangle mode is armed, the same gesture becomes a one-shot node-creation action, with a dashed preview overlay during the drag and toast messages when the gesture completes.\n\n## How the Data Is Organized\nThe initial graph data is assembled inline in `initializeGraph()` as a local `RGJsonData` object. It contains a flat `nodes` array with ids `a` through `n` and an empty `lines` array, so the example starts from a neutral canvas rather than a domain-specific graph.\n\nThere is no fetch step and no preprocessing before `setJsonData(...)` other than constructing that object in memory. After the data is loaded, the example centers and fits the viewport with `moveToCenter()` and `zoomToFit()`.\n\nDuring interaction, the selection rectangle becomes temporary input data. In creation mode, the code converts the selection view back into canvas coordinates and uses the selection width and height to size the new node. In normal mode, the same selection view is passed to `getNodesInSelectionView(...)`, and each returned node is updated to `selected: true`.\n\nIn real products, this same data shape could stand in for sticky notes on a whiteboard, devices on a topology draft, rooms on a floor-plan editor, or generic assets on an annotation canvas.\n\n## How relation-graph Is Used\nThe demo is wrapped in `RGProvider`, and `MyGraph` relies on `RGHooks.useGraphInstance()` for initial data loading, selection handling, node insertion, and runtime option updates. It also uses `RGHooks.useSelection()` so the current selection rectangle can drive both the floating readout and the dashed preview layer. Inside the shared settings panel, `RGHooks.useGraphStore()` reads the active drag and wheel modes.\n\nThe graph options are minimal but intentional: `showToolBar` keeps the built-in toolbar visible, `checkedItemBackgroundColor` gives checked items a translucent green highlight, `defaultLineWidth` stays at `1`, and `defaultJunctionPoint` is set to `RGJunctionPoint.border`. The example does not define a custom layout; it loads simple disconnected data and normalizes the viewport after mount.\n\n`RelationGraph` is the event hub. `onCanvasClick` clears checked and selected state, `onCanvasSelectionEnd` branches between node creation and node picking, and `onKeyboardUp` arms temporary creation modes for `Q` and `W`. `RGSlotOnNode` replaces the default node body with a centered text container. `MyCreatingShapeLayer` adds an SVG overlay with `pointerEvents: 'none'` so preview shapes do not block canvas interaction.\n\nThe surrounding editor shell is built from local helper components rather than extra graph slots. `DraggableWindow` provides the floating instruction panel and can open a shared settings view that changes `wheelEventAction`, changes `dragEventAction`, and exports the current graph through `prepareForImageGeneration()`, `domToImageByModernScreenshot(...)`, and `restoreAfterImageGeneration()`.\n\n## Key Interactions\n- Clicking the circle or rectangle button in the top-center palette arms a temporary creation mode and switches the canvas drag action to `selection`.\n- `onKeyboardUp` on `RelationGraph` also arms creation mode for `KeyQ` and `KeyW`, giving the same flow a shortcut path when the graph receives keyboard events.\n- Dragging a selection box while creation mode is active shows a dashed preview overlay and creates a new circle or rectangle node when the drag ends.\n- Dragging the same selection box with no creation mode armed resolves the enclosed nodes, shows a count toast, and marks those nodes selected.\n- Clicking empty canvas space clears checked and selected state.\n- Opening the settings panel inside the draggable helper window lets the user change wheel behavior, change canvas drag behavior, and download the current graph image.\n\nNode-click and line-click handlers exist, but in this example they only log the clicked objects and do not change the visible behavior.\n\n## Key Code Fragments\nThe component keeps the graph instance, live selection rectangle, and current creation mode in hook and React state.\n\n```tsx\nconst graphInstance = RGHooks.useGraphInstance();\nconst selectionView = RGHooks.useSelection();\nconst [selectionForCreateNode, setSelectionForCreateNode] = React.useState\u003C'' | 'circle' | 'rect'>('');\n\nconst graphOptions: RGOptions = {\n    debug: false,\n    showToolBar: true,\n    checkedItemBackgroundColor: 'rgba(0, 128, 0, 0.2)',\n    defaultLineWidth: 1,\n    defaultJunctionPoint: RGJunctionPoint.border\n};\n```\n\nThis example intentionally starts with a small inline dataset and immediately normalizes the viewport after loading it.\n\n```tsx\nconst myJsonData: RGJsonData = {\n    nodes: [\n        {id: 'a', text: 'A'},\n        {id: 'b', text: 'B'},\n        {id: 'c', text: 'C'},\n        // ...\n    ],\n    lines: []\n};\n\nawait graphInstance.setJsonData(myJsonData);\ngraphInstance.moveToCenter();\ngraphInstance.zoomToFit();\n```\n\n`onCanvasSelectionEnd` turns the dragged region into a new node when a creation mode is armed.\n\n```tsx\nif (selectionForCreateNode === 'circle') {\n    const xyOnCanvas = graphInstance.getCanvasXyByViewXy(userSelectionView);\n    graphInstance.addNode({\n        id: graphInstance.generateNewNodeId(),\n        nodeShape: RGNodeShape.circle,\n        width: userSelectionView.width,\n        height: userSelectionView.height,\n        x: xyOnCanvas.x,\n        y: xyOnCanvas.y\n    });\n}\n```\n\nThe non-creation branch uses the same selection rectangle as a picking query and then resets the canvas back to normal dragging.\n\n```tsx\ngraphInstance.clearChecked();\ngraphInstance.clearSelected();\nconst nodesInSelection = graphInstance.getNodesInSelectionView(userSelectionView);\nSimpleGlobalMessage.success(`Select [${nodesInSelection.length}] Nodes`);\nnodesInSelection.forEach(node => {\n    graphInstance.updateNode(node, {selected: true})\n});\n\ngraphInstance.updateOptions({\n    dragEventAction: 'move'\n});\nsetSelectionForCreateNode('');\n```\n\nA small helper keeps creation mode transient by switching the canvas into selection mode only when the user explicitly arms a shape.\n\n```tsx\nconst onKeyboardUp = (e: KeyboardEvent) => {\n    if (e.code === 'KeyQ') {\n        setSelectionForCreateNodeMode('circle');\n    } else if (e.code === 'KeyW') {\n        setSelectionForCreateNodeMode('rect');\n    }\n};\n\nconst setSelectionForCreateNodeMode = (nodeShape: 'circle' | 'rect') => {\n    graphInstance.updateOptions({ dragEventAction: 'selection' });\n    setSelectionForCreateNode(nodeShape);\n};\n```\n\nThe preview overlay normalizes negative drag directions for rendering and stays transparent to pointer events.\n\n```tsx\nconst rectX = width > 0 ? x : x + width;\nconst rectY = height > 0 ? y : y + height;\nconst absWidth = Math.abs(width);\nconst absHeight = Math.abs(height);\n\n\u003Csvg\n    style={{\n        position: 'absolute',\n        width: '100%',\n        height: '100%',\n        pointerEvents: 'none',\n    }}\n>\n```\n\nThe shared floating settings panel reuses relation-graph APIs to expose runtime canvas controls and image export.\n\n```tsx\nconst canvasDom = await graphInstance.prepareForImageGeneration();\nlet graphBackgroundColor = graphInstance.getOptions().backgroundColor;\nif (!graphBackgroundColor || graphBackgroundColor === 'transparent') {\n    graphBackgroundColor = '#ffffff';\n}\nconst imageBlob = await domToImageByModernScreenshot(canvasDom, {\n    backgroundColor: graphBackgroundColor\n});\nawait graphInstance.restoreAfterImageGeneration();\n```\n\n## What Makes This Example Distinct\nCompared with [`canvas-selection`](./canvas-selection), this example emphasizes transient authoring rather than persistent mode switching. The comparison data shows that `canvas-selection-pro` adds `onKeyboardUp` shortcuts and a dedicated top-center palette, then clears the active shape and restores `dragEventAction` to `move` after each completed gesture. That makes creation feel like a one-shot command instead of a sticky canvas state.\n\nCompared with [`selections`](./selections), the drag box is not only a picking tool. The example converts selection geometry back into canvas coordinates and uses it to size and place new nodes, so the same gesture can either select existing content or author new content depending on the armed mode.\n\nCompared with [`custom-node-quick-actions`](./custom-node-quick-actions) and [`create-line-from-node`](./create-line-from-node), the selection rectangle itself is the editing instrument. Those examples use selection to decide which existing nodes expose contextual controls, while this one uses the dragged region directly as geometry for creation.\n\nThe rarity data also supports a specific combination that is not common across the example set: `RGHooks.useSelection()`, a dashed shape preview overlay, keyboard and palette mode arming, selection-end node creation, selection-end node picking, and a shared settings or export panel in the same lightweight workspace.\n\n## Where Else This Pattern Applies\nThis pattern transfers well to lightweight diagram editors where users need to switch quickly between selection and bounded-shape creation without staying in a permanent tool mode. It fits whiteboards, workflow sketchers, topology drafts, and floor-plan tools where the dragged region should define both placement and size.\n\nIt is also useful in annotation-heavy products. A review tool, map markup tool, or design feedback surface could reuse the same flow to create callout regions, placeholders, grouped containers, or domain-specific bounded objects from one drag gesture.\n",false,500,1782615424584]