[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:connect-targets-across-canvas-node-and-grid":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Mixed Connect Targets Across Canvas Widgets, Nodes, and Grid Cards\n\n## What This Example Builds\n\nThis example builds a fixed-layout connect-target playground instead of a domain-specific graph. The scene mixes two standalone canvas widgets, two positioned graph nodes, internal node ports, and a grid of connectable cards inside the same `RelationGraph` instance.\n\nWhat the user sees is a light full-screen sandbox with color-coded curved demo links, a green node that exposes multiple input and output ports, a blue fallback node with one internal target, two differently styled canvas elements, and a white control panel that changes the grid layout. The important behavior is that one page demonstrates several endpoint scopes at once and also intercepts newly created lines without automatically saving them.\n\n## How the Data Is Organized\n\nThe data is assembled inline rather than loaded through one large `setJsonData(...)` payload. `initializeGraph()` creates a small `nodes` array with explicit `x` and `y` coordinates, then creates a `fakeLines` array whose endpoints refer to ids such as `canvas-el-a`, `n2`, `n1-input-1`, and `grid-item-6`. Separately, component state stores `gridCols`, `gridGap`, and a six-item `gridItems` array for the connectable grid.\n\nThere is no separate preprocessing pass before `setJsonData(...)` or `doLayout(...)`, but there is a strict id contract. Every line endpoint id must match either a graph node id, a node-internal `RGConnectTarget`, or a canvas-slot `RGConnectTarget`. Whole-node endpoints are marked with `RGInnerConnectTargetType.Node`, while internal ports and grid cards keep the default connect-target behavior. In a real application, the same structure could represent workflow widgets, device panels, field-mapping targets, scheduling slots, or dashboard cards that need to connect across mixed UI surfaces.\n\n## How relation-graph Is Used\n\n`RGProvider` wraps the demo so `RGHooks.useGraphInstance()` can access the active graph instance. The graph runs in `fixed` layout mode, which means relation-graph does not compute placement from relationships; the example supplies node coordinates directly. The options also remove the default node border and fill, set the default line shape to `RGLineShape.StandardCurve`, and enable the built-in toolbar.\n\nThe example uses both major slot types. `RGSlotOnNode` replaces the default node body with custom JSX: node `n1` becomes a green card with five internal targets, while the fallback node renderer exposes one extra internal target on the blue node. `RGSlotOnCanvas` renders two free-positioned canvas widgets and a dynamic CSS-grid block whose cells are also wrapped in `RGConnectTarget`. This is the core relation-graph technique here: connector routing is handled by the graph engine, but the actual endpoints live inside ordinary DOM rendered through node and canvas slots.\n\nThe graph instance API drives initialization. On mount, the demo calls `addNodes(...)`, waits briefly for the DOM to exist, recenters the viewport, fits the scene, and finally seeds the demo links with `addFakeLines(...)`. The `onLineBeCreated` callback is the manual persistence handoff. When a user creates a new line, the demo shows a toast message with the source and target ids, but it does not call `addLines(...)` to store that line in graph data. Styling is minimal and targeted: the SCSS file mainly makes line labels inherit the current line color so each seeded connection case stays readable.\n\n## Key Interactions\n\n- The built-in toolbar and normal graph viewport controls are enabled because `showToolBar` is set to `true`.\n- The scene starts with seeded fake lines that demonstrate canvas-to-canvas, canvas-to-node, canvas-to-internal-port, node-to-internal-port, internal-to-internal, and grid-to-grid connections.\n- Two number inputs inside the canvas slot update `gridCols` and `gridGap`, so the grid of endpoint cards reflows at runtime while remaining connectable.\n- When the user creates a new line, `onLineBeCreated` shows a success toast naming the source and target ids, but the new line is not persisted automatically.\n\n## Key Code Fragments\n\nThis fragment shows the graph configured as a fixed scene with transparent node chrome, curved default lines, and the built-in toolbar enabled.\n\n```tsx\nconst graphOptions: RGOptions = {\n    debug: false,\n    layout: {\n        layoutName: 'fixed' // Use fixed layout for easier manual positioning\n    },\n    defaultNodeBorderWidth: 0,\n    defaultNodeColor: 'transparent',\n    defaultLineShape: RGLineShape.StandardCurve,\n    showToolBar: true\n};\n```\n\nThis fragment shows the mixed endpoint typing pattern: one fake line targets a whole node through `RGInnerConnectTargetType.Node`, while another lands on a named internal port.\n\n```tsx\n{\n    id: 'f-2', from: 'canvas-el-a',\n    to: 'n2',\n    toType: RGInnerConnectTargetType.Node,\n    text: 'Element to Node', color: '#9c27b0'\n},\n{ id: 'f-3', from: 'canvas-el-b', fromJunctionPoint: RGJunctionPoint.ltrb, to: 'n1-input-1', text: 'To Internal Target', color: '#009688' },\n{ id: 'f-801', from: 'canvas-el-b', fromJunctionPoint: RGJunctionPoint.ltrb, to: 'n2', toType: RGInnerConnectTargetType.Node, text: 'Element to Node', color: '#9c27b0' },\n```\n\nThis fragment shows the mount-time initialization flow through the graph instance API.\n\n```tsx\ngraphInstance.addNodes(nodes);\nawait graphInstance.sleep(200); // Wait for nodes to finish rendering\ngraphInstance.moveToCenter(); // Center based on elements in the canvas slot\ngraphInstance.zoomToFit(); // Zoom to a suitable scale based on elements in the canvas slot\ngraphInstance.addFakeLines(fakeLines);\n```\n\nThis fragment shows that newly created lines are intercepted and surfaced immediately, but not persisted.\n\n```tsx\nconst onLineBeCreated = (lineInfo: {\n        lineJson: JsonLine,\n        fromNode: RGLineTarget | RGNode,\n        toNode: RGLineTarget | RGNode\n    }) => {\n    SimpleGlobalMessage.success(`New line created! From ${lineInfo.fromNode.id} to ${lineInfo.toNode.id}`);\n    // English：Here you need to add the new line to the graph yourself through the graphInstance.addLines method.\n}\n```\n\nThis fragment shows a real internal port living inside custom node content.\n\n```tsx\n\u003CRGConnectTarget\n    targetId=\"n1-input-1\"\n    junctionPoint={RGJunctionPoint.left}\n>\n    \u003Cdiv className=\"bg-orange-500 text-white text-[10px] px-2 py-1 rounded cursor-pointer hover:bg-orange-600 transition-colors\">\n        Input 1\n    \u003C/div>\n\u003C/RGConnectTarget>\n```\n\nThis fragment shows the canvas-slot grid pattern: ordinary HTML cards are mapped into `RGConnectTarget`s, so they behave like endpoints even while the grid layout changes.\n\n```tsx\n\u003Cdiv\n    className=\"p-4 bg-gray-200\"\n    style={{\n        display: 'grid',\n        gridTemplateColumns: `repeat(${gridCols}, 1fr)`,\n        gap: `${gridGap}px`\n    }}\n>\n    {gridItems.map(item => (\n        \u003CRGConnectTarget key={item.id} targetId={item.id}>\n```\n\nThis fragment shows the SCSS override that makes line labels inherit each line's current color.\n\n```scss\n.rg-line-label {\n    background-color: var(--rg-line-color);\n    color: #fff;\n    font-size: 10px;\n}\n```\n\n## What Makes This Example Distinct\n\nThe comparison data identifies this example as a mixed-endpoint reference rather than a scene-specific viewer. Its strongest distinction is breadth: it demonstrates `RGConnectTarget` across standalone canvas widgets, whole graph nodes, internal node ports, and grid items rendered inside ordinary canvas-slot HTML. That is a rarer combination than examples that stay only in `RGSlotOnCanvas` or only inside node content.\n\nCompared with `scene-network-use-canvas-slot`, this demo is not limited to a canvas-only DOM board. It adds `RGSlotOnNode` ports, explicit whole-node typing through `RGInnerConnectTargetType.Node`, and `onLineBeCreated` as the handoff point for user-made connections. Compared with `node-content-lines`, the lesson is not precise node-internal anchoring alone; it is interoperability between node-slot targets, whole nodes, and canvas-slot endpoints. Compared with `mix-layout-2` and `interest-group`, the focus is not relayout orchestration or selection-driven browsing. It works more like a compact laboratory for comparing connection behaviors across several host types in one scene.\n\nThe live grid controls also make it unusual inside the connect-target examples. The grid can change column count and gap at runtime, but its cards remain valid endpoints. Combined with the non-persisted line-creation callback, that makes this example a strong starting point when a team needs to test how mixed DOM targets behave before deciding how to store user edits.\n\n## Where Else This Pattern Applies\n\nThis pattern transfers well to applications that mix graph nodes with freeform interface widgets. Examples include workflow builders with node ports plus floating control panels, device dashboards that connect racks and canvas-level alert widgets, and mapping tools where users need to connect form fields, cards, or grid cells rather than only whole nodes.\n\nIt is also useful as a migration pattern when a team already has HTML fragments that should stay as ordinary DOM. By wrapping those fragments in `RGConnectTarget` and using node or canvas slots as needed, the team can add visible relationship routing without redesigning every object as a standard graph node body.\n",false,500,1782615412273]