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

Live bus positions

England's local buses moving on your map from the Bus Open Data Service, polled for the area on screen and drawn one poll behind so they glide between fixes. Display only: positions as the feed reports them, never an arrival prediction.

ts
import { createMap, TransitVehiclesLayer } from "@mapmap/maps";

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

// The freshness pill: "Live, 42 s ago", "Paused: last data 6 min ago" or
// "Feed status unknown". Show it whenever the buses are on screen.
const pill = document.querySelector("#feed")!;

const buses = new TransitVehiclesLayer(map, {
  // bbox defaults to "viewport": the area on screen, refetched when the
  // map stops moving. pollMs defaults to 30,000 (at least 15,000).
  onFeedStatus: ({ label }) => { pill.textContent = label; },
  popup: (v) => {
    const el = document.createElement("div");
    el.textContent = "Line " + (v.line ?? "?") + " to " + (v.destination ?? "?");
    return el;
  },
});
buses.start();

// Stop polling when the map is off screen: every poll is a metered call.
// buses.stop(); buses.start(); buses.remove();

Worth knowing

  • Each poll is one Standard request. A page polling every 30 seconds makes 2,880 calls a day while it stays open, so the layer polls only the visible area and pauses while the page is hidden.
  • A stale feed is a field, not an error: past 180 seconds feed.status reads stale, the buses still return and the layer dims them. Coverage is England's local bus services; Scotland, Wales and rail are not in this feed.
  • The layer adds the BODS short credit to the map's one credit line. The full Open Government Licence wording is in every answer's attribution field.