Anleitung

Vektorkacheln in Leaflet

Leaflet zeigt Kartenbilder und kann keine Vektorkacheln mit einem Stil zeichnen. Das Plugin maplibre-gl-leaflet setzt eine MapLibre-Karte als Layer in Leaflet, Ihre Leaflet-Marker, Popups und GeoJSON bleiben also, wie sie sind. Mit Script-Tags und mit einem Bundler. Getestet mit Leaflet 1.9.4 und maplibre-gl-leaflet 0.1.4.

Mit Script-Tags, MapLibre 5 und dem Plugin:
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@5.24.0/dist/maplibre-gl.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/maplibre-gl@5.24.0/dist/maplibre-gl.js"></script>
<script src="https://unpkg.com/@maplibre/maplibre-gl-leaflet@0.1.4/leaflet-maplibre-gl.js"></script>

<style>#map { height: 480px; }</style>
<div id="map"></div>
<script>
const map = L.map("map").setView([47.37, 8.54], 13);
L.maplibreGL({
  style: "https://api.overpass.ch/v1/IHR_SCHLÜSSEL/maps/styles/light.json?lang=de"
}).addTo(map);
</script>

Mit Script-Tags

Das Plugin braucht den klassischen Build von MapLibre, der mit einem Tag <script src> lädt und maplibregl definiert. MapLibre 6 gibt es nur als ES-Module, Script-Tags verwenden also MapLibre 5; Version 5.24.0 ist die letzte. Leaflet-Layer kommen wie gewohnt über die Vektorkarte:

const map = L.map("map").setView([47.37, 8.54], 13);
const base = L.maplibreGL({
  style: "https://api.overpass.ch/v1/IHR_SCHLÜSSEL/maps/styles/light.json?lang=de"
}).addTo(map);

L.marker([47.3769, 8.5417]).addTo(map).bindPopup("Zürich HB").openPopup();
L.geoJSON(route, { style: { color: "#d0312d", weight: 4 } }).addTo(map);

Jeder unserer neun Stile funktioniert: light, dark, white, grayscale, black, outdoor, marine, relief und driving. Ergänzen Sie &hillshade=1 für die Schummerung. Leaflet kann die Karte nicht neigen, terrain=1 nützt hier also nichts.

Mit einem Bundler und MapLibre 6

npm install leaflet maplibre-gl @maplibre/maplibre-gl-leaflet

Das lief in einem Build mit Vite 8 und MapLibre 6.13.0:

import L from "leaflet";
import "leaflet/dist/leaflet.css";
import "maplibre-gl/dist/maplibre-gl.css";
import { setWorkerUrl } from "maplibre-gl";
import workerUrl from "maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url";
import { maplibreGL } from "@maplibre/maplibre-gl-leaflet";
import markerIcon from "leaflet/dist/images/marker-icon.png";
import markerIcon2x from "leaflet/dist/images/marker-icon-2x.png";
import markerShadow from "leaflet/dist/images/marker-shadow.png";

setWorkerUrl(workerUrl);

// der Bundler verschiebt die Marker-Bilder: sagen Sie Leaflet, wo sie sind
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({ iconUrl: markerIcon, iconRetinaUrl: markerIcon2x, shadowUrl: markerShadow });

const KEY = import.meta.env.VITE_OVERPASS_KEY;

const map = L.map("map").setView([47.37, 8.54], 13);
maplibreGL({
  style: `https://api.overpass.ch/v1/${KEY}/maps/styles/light.json?lang=en`
}).addTo(map);

L.marker([47.3769, 8.5417]).addTo(map).bindPopup("Zürich HB").openPopup();

Zwei Stellen beheben die Fehler, auf die wir unterwegs gestossen sind:

  • Ohne setWorkerUrl bleibt die Karte leer, und die Konsole zeigt «Worker failed to load. Check that the worker URL is correct.» MapLibre 6 braucht den Aufruf mit jedem Bundler; für webpack siehe die Anleitung zum Umstieg auf MapLibre.
  • Ohne die Marker-Bilder sind Marker unsichtbar, und der Netzwerk-Tab zeigt 404 für marker-icon.png und marker-shadow.png. Das ist ein Problem von Leaflet mit jedem Bundler.

Die MapLibre-Karte darin

getMaplibreMap() gibt die MapLibre-Karte zurück, für alles, was Leaflet nicht kann, etwa einen Layer mit Höhenlinien oder einen Klick auf ein Objekt der Grundkarte:

const gl = base.getMaplibreMap();
gl.on("load", () => {
  gl.addSource("contours", { type: "vector", url: "https://api.overpass.ch/v1/IHR_SCHLÜSSEL/maps/contours.json" });
  gl.addLayer({ id: "contours", type: "line", source: "contours", "source-layer": "contours",
    paint: { "line-color": "rgba(124, 92, 58, 0.5)" } });
});

Die Zoomstufen unterscheiden sich um eins: Leaflet-Zoomstufe 13 ist MapLibre-Zoomstufe 12, weil MapLibre mit Kacheln von 512 Pixeln rechnet. Das Plugin rechnet zwischen ihnen um.

Grenzen

  • Leaflet kann die Karte weder neigen noch drehen. Für 3D-Gelände oder eine drehbare Karte verwenden Sie MapLibre GL JS direkt: Aus L.marker wird maplibregl.Marker, und GeoJSON-Layer werden zu Quellen und Layern.
  • overpass.ch hat keine Kartenbilder als PNG. Für einen einfachen Layer mit Bildkacheln verwenden Sie einen Rasterkachel-Dienst.
  • Ihr Schlüssel ist in der Seite sichtbar. Erstellen Sie in Ihrem Dashboard einen Schlüssel vom Typ «Nur Karten», und tragen Sie Ihre Website als erlaubten Referer ein, dazu localhost:5173 für den Entwicklungsserver von Vite.
  • Kacheln zählen wie bei MapLibre: eine Kartenkachel pro Vektorkachel. Jedes Konto enthält 100'000 im Monat.