Beispiele
Zusammenhängende Beispiele, alle am 14.09.2026 gegen den Live-Dienst ausgeführt.
Route zeichnen
Abschnitt betitelt „Route zeichnen“Route holen, Polylinie dekodieren, auf die Karte legen. Die Dekodierung ist der Punkt, an dem es am häufigsten schiefgeht — Präzision 6:
async function route(von, nach) { const antwort = await fetch('/ihr-server/valhalla/route', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ locations: [von, nach], costing: 'auto', directions_options: { units: 'kilometers', language: 'de-DE' }, }), }); const { trip } = await antwort.json(); return { laengeKm: trip.summary.length, dauerMin: Math.round(trip.summary.time / 60), punkte: dekodiere(trip.legs[0].shape), anweisungen: trip.legs[0].maneuvers.map((m) => m.instruction), };}
/** Kodierte Polylinie → [[lat, lon], …]. Valhalla nutzt Präzision 6. */function dekodiere(text, praezision = 6) { const faktor = 10 ** praezision; const punkte = []; let i = 0, lat = 0, lon = 0; while (i < text.length) { for (const achse of [0, 1]) { let schub = 0, ergebnis = 0, b; do { b = text.charCodeAt(i++) - 63; ergebnis |= (b & 0x1f) << schub; schub += 5; } while (b >= 0x20); const delta = ergebnis & 1 ? ~(ergebnis >> 1) : ergebnis >> 1; if (achse === 0) lat += delta; else lon += delta; } punkte.push([lat / faktor, lon / faktor]); } return punkte;}Gemessen für Klagenfurt → Villach: 39,0 km, 35 min, 746 Punkte.
Höhenprofil einer Route
Abschnitt betitelt „Höhenprofil einer Route“Erst die Route, dann deren Punkte an /height — nicht Start und Ziel, sonst
messen Sie die Luftlinie:
const { punkte } = await route( { lat: 46.6247, lon: 14.3053 }, { lat: 46.6103, lon: 13.8558 },);
// Ausdünnen: jeder 10. Punkt reicht für ein Profil und spart Nutzlastconst stuetzpunkte = punkte.filter((_, i) => i % 10 === 0);
const antwort = await fetch('/ihr-server/valhalla/height', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ range: true, shape: stuetzpunkte.map(([lat, lon]) => ({ lat, lon })), }),});const { range_height } = await antwort.json();// [[meter_entlang_der_linie, hoehe_in_meter], …] — direkt als Diagramm zeichenbarErreichbarkeit auf der Karte
Abschnitt betitelt „Erreichbarkeit auf der Karte“Die Isochronen-Antwort ist bereits GeoJSON und kann ohne Umbau als Quelle dienen:
const antwort = await fetch('/ihr-server/valhalla/isochrone', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ locations: [{ lat: 46.6247, lon: 14.3053 }], costing: 'auto', contours: [{ time: 10 }, { time: 20 }], polygons: true, }),});
karte.addSource('erreichbarkeit', { type: 'geojson', data: await antwort.json() });karte.addLayer({ id: 'erreichbarkeit', type: 'fill', source: 'erreichbarkeit', paint: { // Der Dienst liefert die Farben gleich mit 'fill-color': ['get', 'fill'], 'fill-opacity': ['get', 'fill-opacity'], },});Die Features kommen absteigend sortiert (20 min vor 10 min) — in dieser Reihenfolge gezeichnet, liegt die kleinere Fläche oben.
Nächstgelegenes Ziel finden
Abschnitt betitelt „Nächstgelegenes Ziel finden“const antwort = await fetch('/ihr-server/valhalla/sources_to_targets', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sources: [{ lat: 46.6247, lon: 14.3053 }], targets: filialen, // [{lat, lon}, …] costing: 'auto', }),});const { sources_to_targets } = await antwort.json();
const naechste = sources_to_targets[0] .filter((e) => e.time != null) // kein Weg → null, nicht 0 .sort((a, b) => a.time - b.time)[0];Der null-Filter ist kein Zierrat: ohne ihn sortiert ein unerreichbares Ziel
in manchen Sprachen nach vorn.