Map-Linked Warehouse and Product Overview
This example composes a US map backdrop, warehouse cards, and product cards inside RGSlotOnCanvas, then uses RGConnectTarget anchors and fake lines to highlight the current selection. It is primarily a reference for map-backed DOM-endpoint wiring and master-detail synchronization rather than a stable inventory data model.
Map-Backed Warehouse and Product Highlighting with Canvas-Slot Connect Targets
What This Example Builds
This example builds a composed dashboard scene rather than a conventional node-link diagram. The canvas shows a semi-transparent US SVG map, pulsing location pins placed at fixed coordinates, a warehouse list on the left, and a goods list on the right. Blue curved highlight lines connect the currently selected warehouse to both its map pin and its generated product cards.
Users can click either a map pin or a warehouse card to change the active selection. They can also open the floating helper window to adjust wheel and canvas-drag behavior or export the current canvas as an image. The main implementation lesson is that relation-graph is used here as a connective overlay for ordinary HTML panels and markers, not as the primary renderer of visible business nodes.
How the Data Is Organized
The main scene state is split into two lightweight data shapes. MyWarehouseGroup stores groupId, groupName, percent, and an absolute location with x and y coordinates, and MyProduct stores id, name, unit, and count. The warehouse records are seeded directly inside MyGraph, while the product list is produced by fetchWarehouseProducts(...) from my-data-api.tsx.
Before relation-graph draws anything, the example does two small preprocessing steps. It seeds six fixed-position records for the left list and map-pin layer, then initializeGraph() selects group b and calls moveToCenter() plus zoomToFit() so the composed scene is visible immediately. After that, every activeGroupId change triggers a fresh product list and a fake-line rebuild.
One important limitation is that the current product fetcher ignores the incoming warehouse id and returns a random set of 8 to 30 mock products each time. In a real warehouse dashboard, this structure would map cleanly to warehouse metadata plus per-warehouse inventory rows with stable geo coordinates, but this demo is intentionally focused on wiring and highlighting behavior rather than stable domain data.
How relation-graph Is Used
The entry component wraps the demo in RGProvider, which enables hook-based graph access throughout the example. Inside MyGraph, RGHooks.useGraphInstance() provides the graph instance, and the graph is configured with layout.layoutName = 'fixed' and defaultJunctionPoint = RGJunctionPoint.lr. That fixed layout matters because the visible scene is manually positioned with absolute DOM coordinates instead of draggable graph nodes.
RelationGraph hosts a single RGSlotOnCanvas scene. The slot contains the static US map backdrop, the absolute-positioned location markers, the warehouse cards, and the product cards. Each visible endpoint is wrapped in RGConnectTarget with a stable targetId, so relation-graph can attach fake lines to ordinary HTML elements. The three target families are:
location-*for map pinsgroup-*for warehouse cardsproduct-*for product cards
When selection changes, the example does not update normal graph nodes or links. Instead, it waits briefly for the slot content to mount, clears the graph, inserts one invisible placeholder node, and redraws the current connector set with addFakeLines(). That makes relation-graph behave like a relationship-highlighting layer on top of a prebuilt dashboard composition.
The shared DraggableWindow component adds the secondary runtime tooling. Through RGHooks.useGraphStore() and useGraphInstance(), it exposes wheel-mode switching, canvas-drag-mode switching, and image export using prepareForImageGeneration() and restoreAfterImageGeneration(). There is no structural editing workflow in this example; it remains a viewer with runtime controls.
Styling is mostly applied to the surrounding DOM rather than to relation-graph internals. The custom SCSS defines the pulsing .c-i-location marker treatment and the .wuxia-map-svg4us fill and hover styling for the static map asset. The relation-graph style override blocks are present but effectively unused.
Key Interactions
Clicking a warehouse card changes activeGroupId, highlights that card, regenerates the right-side goods list, and redraws all fake lines for the new selection. Clicking a map pin runs the same selection flow, so the left panel and map remain synchronized from a single active state.
The connector logic fans one selection into multiple relationships. Every current product card gets a curved line back to the selected warehouse card, and the selected warehouse also gets a thicker curved line to its fixed map location. This creates a compact master-detail behavior across three different DOM surfaces.
The floating helper window adds secondary interactions. Users can toggle the mouse wheel between scroll, zoom, and none; switch canvas dragging between selection, move, and none; and export the current graph canvas as an image. Product cards themselves are only presentational endpoints in the current implementation, so there is no reverse product-to-warehouse exploration.
Key Code Fragments
This fragment shows that the graph uses fixed layout and left-right junctions so absolute DOM anchors can stay aligned with the map scene.
const graphOptions: RGOptions = {
debug: false,
defaultJunctionPoint: RGJunctionPoint.lr,
layout: {
layoutName: 'fixed'
}
};
This fragment shows the central pattern: one active selection is converted into fake lines from products back to the selected warehouse.
if (activeGroupId) {
warehouseProducts.forEach((product) => {
myFakeLines.push({
id: `line-${product.id}`,
from: 'product-' + product.id,
to: 'group-' + activeGroupId,
color: 'rgb(59 130 246)',
lineShape: RGLineShape.StandardCurve
});
});
}
This fragment shows that the visible scene lives inside RGSlotOnCanvas, while map pins are registered as connect targets instead of graph nodes.
<RGSlotOnCanvas>
<div style={{ zIndex: 1, position: 'absolute', left: -900, top: 100, height: 800, width: 900, opacity: 0.6 }}>
<MapSvg4US />
</div>
{/* ... */}
<RGConnectTarget
targetId={`location-${group.groupId}`}
junctionPoint={RGJunctionPoint.lr}
disableDrag={true}
disableDrop={true}
>
This fragment shows that the floating helper window is not decorative: it changes runtime graph behavior and supports image export.
const canvasDom = await graphInstance.prepareForImageGeneration();
let graphBackgroundColor = graphInstance.getOptions().backgroundColor;
if (!graphBackgroundColor || graphBackgroundColor === 'transparent') {
graphBackgroundColor = '#ffffff';
}
const imageBlob = await domToImageByModernScreenshot(canvasDom, {
backgroundColor: graphBackgroundColor
});
This fragment shows that the current product panel is intentionally mock-driven and is regenerated rather than loaded as stable per-warehouse inventory.
export const fetchWarehouseProducts = async(myWarehouseId: string) => {
return generateProducts();
};
const generateProducts = (min: number = 8, max: number = 30): MyProduct[] => {
const productCount = Math.floor(Math.random() * (max - min + 1)) + min;
const products: MyProduct[] = [];
What Makes This Example Distinct
Compared with nearby canvas-slot examples, this one stands out for combining three endpoint families in a single composed board: fixed-position map pins, warehouse cards with utilization bars, and product cards with count and unit badges. That combination gives the example a stronger dashboard character than simpler DOM-endpoint demos that only connect one list to one map surface.
The prepared comparison also shows a specific behavioral difference from interest-group. Both examples share the same broad wiring pattern, but this version is more one-directional: selecting a warehouse or pin repopulates the product list and redraws the connectors, while product cards do not provide reverse exploration. That makes this example a better starting point for master-detail highlighting than for symmetric relationship browsing.
Relative to scene-network-use-canvas-slot, the example also pushes interaction further. Instead of mounting one fixed connector set after startup, it continuously rebuilds the line set from current selection state. The result is a more stateful pattern for dashboards that need coordinated focus across map, summary list, and detail list.
The article title and source path are somewhat generic for what the code actually does. The implementation is best understood as a map-linked DOM-endpoint composition pattern, especially because some labels and helper text still preserve older interest-group wording. That mismatch is another reason this example is more useful as a technical wiring reference than as a domain-accurate inventory model.
Where Else This Pattern Applies
This pattern transfers well to logistics dashboards where a selected warehouse, depot, or route hub should highlight related inventory rows and its geographic location without turning the entire page into graph nodes.
It also fits retail territory planning, field-service coordination, regional sales coverage, and emergency response boards where a spatial anchor on a map needs to stay synchronized with summary cards and detail rows in side panels.
More generally, it is a useful starting point whenever a product team already has a custom HTML dashboard and wants relation-graph to add relationship emphasis, focus synchronization, and exportable visual traces on top of that existing layout.