World Map Graph Overlay with Snapshots
A fixed-layout relation-graph example that overlays authored node coordinates and animated links on a bundled world SVG. It also adds a draggable utility window for snapshot save and replay, shared canvas settings, and image export.
World Map Graph Overlay with Snapshot Replay
What This Example Builds
This example builds a fixed-position relation graph on top of a bundled world SVG. The screen combines a pale 2000 by 857 world map, five small orange circular nodes, four orange links, the built-in graph toolbar, and a floating white utility window. Users can pan or zoom the canvas, save the current graph into timestamped snapshots, reopen a saved snapshot by clicking its row, switch the floating window into canvas settings mode, and export an image. The main point is not geographic analysis. It is a composition pattern for placing relation-graph content at authored coordinates on a map-shaped backdrop.
How the Data Is Organized
The main dataset is inline RGJsonData inside MyGraph.tsx. It contains a rootId, five nodes with explicit x and y coordinates, and four lines with ids, animation values, and optional line-shape overrides. There is no layout preprocessing before setJsonData(). The world map is also not generated from graph data. It comes from a separate MapSvg4World component that renders a large static SVG and is inserted behind the graph content.
At runtime, the example performs one extra data transformation: the Save action serializes the live graph back into a snapshot object by reading getNodes(), getLinks(), and getOptions(). That snapshot format can be reused for logistics hubs, regional offices, cable landing points, route maps, or any other dataset where a static geographic backdrop is useful but node positions are authored directly.
How relation-graph Is Used
RGProvider wraps the demo so hooks can resolve against the active graph instance. The graph itself uses layoutName: 'fixed', which means relation-graph respects the coordinates seeded in the data instead of computing a new layout. Graph options enable the built-in toolbar, use border junction points, and define the orange node and line defaults that make the overlay visually consistent.
RGHooks.useGraphInstance() drives nearly all graph operations: initial setJsonData(), moveToCenter(), zoomToFit(), snapshot serialization, snapshot replay, and the shared settings and export flow inside the floating window. The demo does not define custom node or line slots. Instead, it passes MapSvg4World as child content of RelationGraph, so the SVG becomes part of the graph scene. Styling stays light. The SCSS leaves most graph internals alone and focuses on the snapshot list appearance.
Key Interactions
The primary interaction is snapshot capture and replay. Pressing the Save button reads the live graph state, stores a timestamped snapshot, and blocks duplicate saves when the newest snapshot already matches the current graph. Clicking a saved row clears the graph and redraws the saved nodes and lines.
The floating helper window is also part of the interaction model. Users can drag it, minimize it, and switch it into a settings overlay. That overlay changes wheel behavior, changes canvas drag behavior, and downloads an image by running the prepare and restore image-generation lifecycle on the graph instance. Node and line click handlers exist, but they only log inspection data and do not drive the feature flow.
Key Code Fragments
This option block proves the graph is configured as a fixed-position orange overlay with the built-in toolbar enabled.
const graphOptions: RGOptions = {
debug: false,
showToolBar: true,
defaultJunctionPoint: RGJunctionPoint.border,
defaultNodeColor: '#f39930',
defaultNodeBorderWidth: 1,
defaultNodeBorderColor: '#f39930',
defaultNodeWidth: 20,
defaultNodeHeight: 20,
defaultLineColor: '#f39930',
defaultLineWidth: 2,
layout: {
layoutName: 'fixed'
}
};
This initialization block shows that node positions are authored directly in the data instead of being computed by an external layout engine.
const myJsonData: RGJsonData = {
rootId: 'R',
nodes: [
{ id: "R", text: "R", opacity: 1, x: 1070, y: 250, nodeShape: RGNodeShape.circle },
{ id: "A", text: "A", opacity: 1, x: 460, y: 160, nodeShape: RGNodeShape.circle },
// ...
{ id: "C", text: "C", opacity: 1, x: 1680, y: 550, nodeShape: RGNodeShape.circle },
{ id: "D", text: "D", opacity: 1, x: 1230, y: 450, nodeShape: RGNodeShape.circle }
],
lines: [
{ id: 'l1', from: 'R', to: 'A', animation: 1, lineShape: RGLineShape.Curve3 },
// ...
{ id: 'l4', from: 'R', to: 'D', animation: 4, lineShape: RGLineShape.StandardStraight },
]
};
This save routine shows how the demo serializes the live graph instance into replayable snapshots.
const allNodesWithPosition = graphInstance.getNodes().map(node => ({
id: node.id,
text: node.text,
x: node.x,
y: node.y,
opacity: node.opacity,
nodeShape: node.nodeShape
}));
const allLines = graphInstance.getLinks().map(link => ({
id: link.line.id,
from: link.fromNode.id,
to: link.toNode.id,
lineShape: link.line.lineShape,
animation: link.line.animation
}));
This duplicate guard and replay path show that snapshots are lightweight graph-state checkpoints rather than full viewport restores.
if (graphSnapshots.length > 0 && JSON.stringify(graphSnapshotData) === JSON.stringify(graphSnapshots[0].data)) {
alert('The data has not changed');
return;
}
const redrawSnapshot = (theSnapshot: {data: RGJsonData}) => {
graphInstance.clearGraph();
graphInstance.addNodes(theSnapshot.data.nodes);
graphInstance.addLines(theSnapshot.data.lines);
};
This settings fragment proves the floating window can switch from snapshot history into runtime canvas controls and 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
});
await graphInstance.restoreAfterImageGeneration();
What Makes This Example Distinct
Comparison data shows that map-world is not the only map-backed example. map-us uses the same broad snapshot-and-backdrop recipe. What makes this one distinct is the combination of a full-world bundled SVG, explicit x and y placement, an always-visible built-in toolbar, animated orange links, and snapshot save or replay controls in one draggable window.
The comparison with map-us is mainly about scope and motion. map-world stretches the pattern across a much larger global backdrop and gives every seeded line an animation value while mixing curved and straight shapes. Against use-sigma-layout and use-dagre-layout, the teaching value is different: coordinates are authored up front for backdrop composition rather than computed by an external layout engine and written back after measurement. That makes this example a stronger starting point for fixed-coordinate overlays than for automatic graph layout workflows.
Where Else This Pattern Applies
This pattern transfers well to global supply-chain maps, route boards, international infrastructure views, office or campus overlays, and static diagram backdrops such as floor plans or equipment maps. It is also useful when a product needs lightweight save and restore behavior, image export, or a helper window without becoming a full graph editor. In those cases, the world SVG can be replaced with any authored drawing while relation-graph keeps handling the graph layer, viewport, and serialization hooks.