Skip to content
Documentation menu
docs / examples / image-overlay
Example

Image overlay

Pin a picture to four corners on the map: a site plan, a scanned survey or a rendered surface. This one is MapMap's own hillshade of Kynance Cove, made from Environment Agency LiDAR, with the sea left transparent so the basemap shows through.

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

const map = createMap({
  container: "map",
  apiKey: "snk_...",
  attributionPosition: "bottom-left",
  center: [-5.2275, 49.9752],
  zoom: 14.2,
  mapOptions: {
    // Credit the image's own source alongside the map credit.
    attributionControl: {
      customAttribution:
        "Contains Environment Agency information, OGL v3.0",
    },
  },
});
await map.whenReady();

map.map.addSource("relief", {
  type: "image",
  url: "https://mapmap.ai/data/examples/kynance-cove-relief.png",
  // Corners as [lng, lat], clockwise from top left. Four free corners, so
  // an image on a rotated national grid still lands exactly.
  coordinates: [
    [-5.243262, 49.983953],   // top left
    [-5.213107, 49.984793],   // top right
    [-5.211856, 49.966020],   // bottom right
    [-5.242000, 49.965180],   // bottom left
  ],
});

// Slots arrive in the SDK 0.17: map.slot("middle") replaces "road-labels".
map.map.addLayer({
  id: "relief",
  type: "raster",
  source: "relief",
  paint: { "raster-opacity": 0.85, "raster-fade-duration": 0 },
}, "road-labels");

Worth knowing

  • The image must be served with CORS (Access-Control-Allow-Origin) because MapLibre uploads it to WebGL. A same-origin file or a bucket with CORS on both work; a bare third-party URL usually does not.
  • The corners do not have to form a rectangle in longitude and latitude. This image is a square on the British National Grid, which sits about two and a half degrees off true north in Cornwall, so its corners were converted point by point.
  • Swap the picture later without re-adding the layer: getSource("relief").updateImage({ url, coordinates }).