Skip to content
Documentation menu
docs / examples / live-updates
Example

Live updates with updateData

Move a fleet of vans every two seconds by sending only what changed. updateData patches features by id, so a position feed of hundreds of vehicles never re-sends the whole collection the way setData does.

ts
import { createMap } from "@mapmap/maps";
import type { GeoJSONSource } from "maplibre-gl";

const map = createMap({
  container: "map",
  apiKey: "snk_...",
  attributionPosition: "bottom-left",
  center: [-0.12, 51.51],
  zoom: 11.5,
});
await map.whenReady();

// updateData finds features by id: promoteId names the property holding it.
const vans = Array.from({ length: 40 }, (_, i) => ({
  id: "van-" + i,
  lng: -0.12 + Math.cos(i) * 0.06,
  lat: 51.51 + Math.sin(i * 1.7) * 0.03,
}));

map.map.addSource("vans", {
  type: "geojson",
  data: {
    type: "FeatureCollection",
    features: vans.map((v) => ({
      type: "Feature",
      properties: { id: v.id },
      geometry: { type: "Point", coordinates: [v.lng, v.lat] },
    })),
  },
  promoteId: "id",
});

// Slots arrive in the SDK 0.17: map.slot("middle") replaces "road-labels".
map.map.addLayer({
  id: "vans",
  type: "circle",
  source: "vans",
  paint: {
    "circle-radius": 6,
    "circle-color": "#1a6bff",
    "circle-stroke-color": "#ffffff",
    "circle-stroke-width": 2,
  },
}, "road-labels");

// Stand-in for your feed: nudge every van, then patch only the geometry.
setInterval(async () => {
  for (const v of vans) {
    v.lng += (Math.random() - 0.5) * 0.002;
    v.lat += (Math.random() - 0.5) * 0.0012;
  }
  await map.map.getSource<GeoJSONSource>("vans")?.updateData({
    update: vans.map((v) => ({
      id: v.id,
      newGeometry: { type: "Point", coordinates: [v.lng, v.lat] },
    })),
  });
}, 2000);

Worth knowing

  • updateData takes remove, add and update in one diff and applies them in that order. Updating an id that is not in the source is ignored rather than an error.
  • It is an error to call updateData on a source whose features did not all have unique ids from the start: set feature.id or promoteId before the first frame, not later.
  • A diff also changes properties: addOrUpdateProperties: [{ key: "status", value: "late" }] on an update entry restyles one van without touching its position.