[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"example-markdown-content:en:connect-list-items-to-location-nodes":3},{"markdown":4,"isPaidExample":5,"isTruncated":5,"charLimit":6},"# Connect List Cards to Fixed Location Nodes on a Map\n\n## What This Example Builds\n\nThis example builds a location-assignment view on top of a school map. The left side of the canvas shows fixed-position map pins, and the right side shows six interest-group cards. One animated connector is always used to highlight the currently selected relationship between a list item and its matching map location.\n\nUsers can switch the active relationship by clicking either the card or the pin. The scene also includes a floating helper window that can be dragged, minimized, opened into a settings panel, and used to export the current canvas as an image.\n\nThe main point of the example is not generic node editing. It is a focused DOM-to-node linking pattern: the list side is ordinary DOM wrapped with `RGConnectTarget`, while the destination side stays inside the relation-graph model as real nodes.\n\n## How the Data Is Organized\n\nThe data starts as a small inline array in `MyGraph.tsx`. Each record has a `groupId`, a display name, and a `location` object with explicit `x` and `y` coordinates.\n\nBefore anything is rendered, that array is used in two ways:\n\n- It is copied into React state as `interestGroups`, which drives the right-side card list.\n- It is projected into graph nodes with ids such as `location-a`, plus `data.myGroupId`, and then inserted with `addNodes(...)`.\n\nThere is no `setJsonData(...)` call in this example. The graph content is assembled imperatively after mount, and the same source records feed both the DOM endpoints and the map-side nodes. In a real system, the same shape could represent departments on a campus map, booths in an event hall, equipment on a floor plan, or service points in a facility.\n\n## How relation-graph Is Used\n\nThe graph runs in fixed layout mode, so every projected node stays at the exact coordinates from the source records. The initial options also set `defaultJunctionPoint` to `border`, the mouse wheel to zoom mode, and canvas dragging to move mode.\n\n`RGProvider` supplies graph context, and `RGHooks.useGraphInstance()` is the main control surface. The component uses that instance to add nodes, center the viewport, fit the zoom, clear the previous fake line, and add the new active fake line. The shared helper window also uses the graph instance to change runtime options and to run the image-export workflow.\n\nTwo slots define the visible scene:\n\n- `RGSlotOnNode` replaces normal node rendering with a clickable `MapPin` marker.\n- `RGSlotOnCanvas` renders the school map and the list of `RGConnectTarget` cards inside the same canvas layer.\n\n`RGConnectTarget` is the key integration point on the list side. Each card gets a stable endpoint id like `group-a`, and the selected group is linked to its matching graph node by a fake line whose target type is explicitly set to `RGInnerConnectTargetType.Node`.\n\nThe floating helper window is not example-specific graph logic, but it matters to the complete behavior. It reads current graph options through `RGHooks.useGraphStore()`, updates `wheelEventAction` and `dragEventAction` with `setOptions(...)`, and exports the graph after `prepareForImageGeneration()` and `restoreAfterImageGeneration()`.\n\n## Key Interactions\n\n- The example auto-selects group `a` shortly after mount, so the first connector appears without manual input.\n- Clicking a list card or a map pin routes into the same `onGroupClick(...)` handler, updates the active group id, and redraws exactly one fake line.\n- The helper text and node setup indicate that the map-side pins are intended to be draggable in the live graph. The code does not write changed coordinates back into React state, so any repositioning is transient within the running canvas.\n- The floating helper window supports dragging, minimizing, opening the settings overlay, switching wheel and drag behaviors, and downloading a screenshot.\n\n## Key Code Fragments\n\nThis fragment shows how one inline record set becomes both UI state and fixed-position graph nodes.\n\n```tsx\nconst myGroups = [\n    { groupId: 'a', groupName: 'Sports Group', location: { x: 260, y: 300 } },\n    { groupId: 'b', groupName: 'Music Group', location: { x: 350, y: 100 } },\n    // ...\n];\nsetInterestGroups(myGroups);\ngraphInstance.addNodes(myGroups.map(n => ({\n    id: 'location-' + n.groupId,\n    x: n.location.x,\n    y: n.location.y,\n    data: { myGroupId: n.groupId }\n})));\n```\n\nThis fragment proves that selection does not rebuild the whole scene. It only replaces one active fake line.\n\n```tsx\nconst myFakeLines: JsonLine[] = [{\n    id: `fl-${groupId}`,\n    from: 'group-' + groupId,\n    to: 'location-' + groupId,\n    toType: RGInnerConnectTargetType.Node,\n    color: 'rgba(159,23,227,0.65)',\n    lineShape: RGLineShape.StandardCurve,\n    fromJunctionPoint: RGJunctionPoint.lr,\n    toJunctionPoint: RGJunctionPoint.border,\n    animation: 2\n}];\ngraphInstance.clearFakeLines();\ngraphInstance.addFakeLines(myFakeLines);\n```\n\nThis fragment shows that the destination side remains a real graph node, even though it is rendered as a pin-style marker.\n\n```tsx\n\u003CRGSlotOnNode>\n    {({ node, checked }: RGNodeSlotProps) => {\n        return (\n            \u003Cdiv\n                className={`pointer-events-auto cursor-point c-i-location ${checked ? 'c-i-location-active' : ''}`}\n                onClick={() => onGroupClick(node.data.myGroupId)}\n            >\n                \u003CMapPin className='transform translate-y-[-25px] translate-x-[-5px]' size={24} />\n            \u003C/div>\n        );\n    }}\n\u003C/RGSlotOnNode>\n```\n\nThis fragment shows how the list side is turned into connectable DOM endpoints.\n\n```tsx\n\u003CRGConnectTarget\n    key={group.groupId}\n    targetId={`group-${group.groupId}`}\n    junctionPoint={RGJunctionPoint.lr}\n    disableDrag={true}\n    disableDrop={true}\n>\n    \u003Cdiv\n        className={`w-full pointer-events-auto c-i-group cursor-point ${activeGroupId === group.groupId ? 'c-i-group-checked' : ''}`}\n        onClick={() => onGroupClick(group.groupId)}\n    >\n```\n\nThis fragment shows how the shared helper panel changes runtime behavior and captures the graph canvas as an image.\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});\nif (imageBlob) {\n    downloadBlob(imageBlob, 'my-image-name');\n}\nawait graphInstance.restoreAfterImageGeneration();\n```\n\n## What Makes This Example Distinct\n\nThe comparison data places this example between pure element-line demos and map-based node demos. Its clearest distinguishing point is that the list side stays ordinary DOM, while the destination side stays inside relation-graph as real fixed-position nodes. That makes it a focused reference for DOM-to-node connections rather than DOM-to-DOM wiring or a general-purpose graph editor.\n\nCompared with `element-lines`, this example is more useful when the destination must keep graph identity, metadata, and built-in node behavior. Compared with `element-connect-to-node`, it is narrower and easier to reuse because it does not compare multiple strategies side by side. It keeps one map, one list, and one active connector, so the example concentrates on the selection-and-highlight workflow itself.\n\nThe comparison output also highlights the feature combination as unusually strong: fixed-layout map nodes, custom node rendering, canvas-composed list UI, draggable graph-backed pins, and per-selection `clearFakeLines()` plus `addFakeLines()` replacement of a single animated connector. That combination makes it a practical starting point for compact assignment boards where one current relationship should remain visually dominant.\n\n## Where Else This Pattern Applies\n\nThis pattern can be transferred to any interface where one side of the relationship belongs to the graph model and the other side belongs to ordinary page UI.\n\n- Assigning teams, devices, or tasks to fixed places on a floor plan or campus map.\n- Linking warehouse items or stations in a sidebar to spatial anchors on a storage layout.\n- Connecting event booths, service desks, or emergency points to positions on a venue map.\n- Building review tools where operators pick one record from a list and immediately see its mapped destination.\n\nThe reusable idea is the split responsibility: keep meaningful spatial anchors as graph nodes, keep surrounding workflow UI as DOM, and redraw only the currently relevant connector.\n",false,500,1782615413279]