Zum Inhalt springen

Beispiele

Zusammenhängende Beispiele, alle am 14.09.2026 gegen den Live-Dienst ausgeführt.

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.

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 Nutzlast
const 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 zeichenbar

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.

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.