<div id="sigma-container"></div>
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.5.0/dist/maplibre-gl.css" />
import bindMaplibreLayer, { graphToLatlng } from "@sigma/layer-maplibre";
import Graph from "graphology";
import { Marker } from "maplibre-gl";
import Sigma from "sigma";
import { DEFAULT_STYLES } from "sigma/types";
import type { FeatureCollection } from "geojson";
const container = document.getElementById("sigma-container") as HTMLElement;
const graph = new Graph();
graph.addNode("paris", { x: 0, y: 0, lat: 48.8566, lng: 2.3522, label: "Paris" });
graph.addNode("london", { x: 0, y: 0, lat: 51.5074, lng: -0.1278, label: "London" });
graph.addEdge("paris", "london");
// Approximate Channel Tunnel route as inline GeoJSON
const channelTunnelGeoJSON: FeatureCollection = {
type: "FeatureCollection",
properties: { name: "Channel Tunnel (approximate)" },
const renderer = new Sigma(graph, container, {
labelRenderedSizeThreshold: 0,
nodes: [DEFAULT_STYLES.nodes, { color: "black", size: 0.004 }],
edges: [DEFAULT_STYLES.edges, { color: "black", size: 0.001 }],
const { map } = bindMaplibreLayer(renderer, {
getNodeLatLng: (attrs) => ({ lat: attrs.lat, lng: attrs.lng }),
// Add GeoJSON layer and click-to-marker after map loads
map.addSource("channel-tunnel", { type: "geojson", data: channelTunnelGeoJSON }).addLayer({
id: "channel-tunnel-line",
source: "channel-tunnel",
"line-dasharray": [2, 2],
// Click on the stage to place a marker
let markerOnClick: null | Marker = null;
renderer.on("clickStage", (e) => {
const graphCoords = renderer.viewportToGraph({ x: e.event.x, y: e.event.y });
const geoCoords = graphToLatlng(graphCoords);
markerOnClick = new Marker();
markerOnClick.setLngLat(geoCoords);
markerOnClick.addTo(map);
markerOnClick.setLngLat(geoCoords);