Skip to content
Documentation menu
docs / examples / geojson-lines-polygons
Example

GeoJSON lines and polygons

Your own zones and paths from one GeoJSON source: a fill and an outline for the polygons, a line for the paths, split by geometry type. The layers sit beneath the labels, so street names stay readable over your shapes.

ts
import { createMap } from "@mapmap/maps";
import "maplibre-gl/dist/maplibre-gl.css";

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

// One source, any mix of geometries. data also takes a URL to a .geojson.
map.addPersistentSource("my-shapes", {
  type: "geojson",
  data: {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        properties: { name: "Delivery zone A" },
        geometry: {
          type: "Polygon",
          coordinates: [[
            [-0.112, 51.498], [-0.084, 51.498], [-0.084, 51.511],
            [-0.112, 51.511], [-0.112, 51.498],
          ]],
        },
      },
      {
        type: "Feature",
        properties: { name: "Riverside path" },
        geometry: {
          type: "LineString",
          coordinates: [
            [-0.1195, 51.5033], [-0.1080, 51.5075], [-0.0990, 51.5080],
            [-0.0870, 51.5070], [-0.0760, 51.5055],
          ],
        },
      },
    ],
  },
});

// slot "middle": above the roads, below every label. Persistent layers come
// back after every map.setStyle(...), at the same slot.
map.addPersistentLayer({
  id: "my-zones-fill",
  type: "fill",
  source: "my-shapes",
  filter: ["==", ["geometry-type"], "Polygon"],
  paint: { "fill-color": "#1a6bff", "fill-opacity": 0.16 },
}, { slot: "middle" });

map.addPersistentLayer({
  id: "my-zones-outline",
  type: "line",
  source: "my-shapes",
  filter: ["==", ["geometry-type"], "Polygon"],
  paint: { "line-color": "#1a6bff", "line-width": 1.5 },
}, { slot: "middle" });

map.addPersistentLayer({
  id: "my-paths",
  type: "line",
  source: "my-shapes",
  filter: ["==", ["geometry-type"], "LineString"],
  layout: { "line-cap": "round", "line-join": "round" },
  paint: { "line-color": "#e07b39", "line-width": 4 },
}, { slot: "middle" });

Worth knowing

  • The slot says where your layer sits: "bottom" beneath the roads and buildings, "middle" above the roads and below every label, "top" above POI labels and below place names. The full table is under insertion points on /docs/custom-data.
  • addPersistentSource and addPersistentLayer survive map.setStyle(...): a theme swap re-adds them at their slot. A layer added through map.map directly is dropped on setStyle; insert it with map.map.addLayer(layer, map.slot("middle")) and re-add it in a style.load handler.