Zum Inhalt

Isochrone

Dieses Beispiel berechnet eine Isochrone über das npm-Paket @smartmaps/routing, statt den REST-Endpunkt direkt aufzurufen. Klicken Sie auf die Karte, um den Ausgangspunkt zu setzen; wechseln Sie zwischen Reisezeit und Entfernung sowie zwischen den Geschwindigkeitsprofilen, um zu sehen, wie sich das erreichbare Gebiet ändert.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <script src="https://cdn.smartmaps.cloud/packages/smartmaps/routing/umd/routing.min.js"></script>
        <script src="https://cdn.smartmaps.cloud/packages/smartmaps/smartmaps-gl/v2/umd/smartmaps-gl.min.js"></script>
        <style>
            body {
                margin: 0;
                padding: 0;
            }

            #map {
                height: 100vh;
            }

            #controls {
                position: absolute;
                top: 10px;
                left: 10px;
                z-index: 1;
                background: rgba(255, 255, 255, 0.9);
                padding: 10px;
                border-radius: 4px;
                font: 13px sans-serif;
            }

            #controls label {
                display: block;
                margin-top: 6px;
            }

            #status {
                margin-top: 8px;
                max-width: 220px;
            }
        </style>
    </head>

    <body>
        <div id="controls">
            <strong>Click the map to place the origin</strong>
            <label>
                Mode:
                <select id="mode">
                    <option value="time">Travel time</option>
                    <option value="distance">Distance</option>
                </select>
            </label>
            <label id="value-label">
                Minutes (max 60):
                <input id="value" type="number" value="15" min="1" max="60" />
            </label>
            <label>
                Speed profile:
                <select id="profile">
                    <option value="FAST">Car</option>
                    <option value="BICYCLE">Bicycle</option>
                    <option value="PEDESTRIAN">Pedestrian</option>
                </select>
            </label>
            <div id="status"></div>
        </div>

        <div id="map"></div>

        <script>
            const apiKey = '[INSERT API-KEY]';
            const map = new smartmapsgl.Map({
                apiKey,
                container: 'map',
                center: { lat: 49.02164948779226, lng: 8.439330018049352 },
                zoom: 12,
                style: smartmapsgl.MapStyle.LIGHT
            });

            const isochroneService = new smartmaps.routingService.RoutingIsochrone(apiKey);

            const modeSelect = document.getElementById('mode');
            const valueLabel = document.getElementById('value-label');
            const valueInput = document.getElementById('value');
            const profileSelect = document.getElementById('profile');
            const statusEl = document.getElementById('status');

            let marker = null;

            modeSelect.addEventListener('change', () => {
                const isTime = modeSelect.value === 'time';
                valueLabel.firstChild.textContent = isTime ? 'Minutes (max 60): ' : 'Meters: ';
                valueInput.value = isTime ? 15 : 5000;
            });

            function removeIsochroneLayer() {
                if (map.getLayer('isochrone-fill')) map.removeLayer('isochrone-fill');
                if (map.getLayer('isochrone-outline')) map.removeLayer('isochrone-outline');
                if (map.getSource('isochrone')) map.removeSource('isochrone');
            }

            map.on('click', async (event) => {
                statusEl.textContent = 'Calculating…';

                if (marker) marker.remove();
                marker = new smartmapsgl.Marker({ color: '#0A5FA0' }).setLngLat(event.lngLat).addTo(map);

                const isTime = modeSelect.value === 'time';

                try {
                    const result = await isochroneService.calcRoute(
                        [{ longitude: event.lngLat.lng, latitude: event.lngLat.lat }],
                        {
                            speedProfile: profileSelect.value,
                            isochroneGrid: 80,
                            timeInMinutes: isTime ? Number(valueInput.value) : undefined,
                            distanceInMeters: isTime ? undefined : Number(valueInput.value)
                        }
                    );

                    const polygon = result.features.find(
                        (feature) => feature.properties?.featureType === 'ISOCHRONE_OUTLINE_POLYGON'
                    );
                    if (!polygon) throw new Error('No isochrone in response');

                    removeIsochroneLayer();
                    map.addSource('isochrone', { type: 'geojson', data: polygon });
                    map.addLayer({
                        id: 'isochrone-fill',
                        type: 'fill',
                        source: 'isochrone',
                        paint: { 'fill-color': '#0A5FA0', 'fill-opacity': 0.25 }
                    });
                    map.addLayer({
                        id: 'isochrone-outline',
                        type: 'line',
                        source: 'isochrone',
                        paint: { 'line-color': '#0A5FA0', 'line-width': 2 }
                    });

                    const label = isTime ? `${valueInput.value} min` : `${valueInput.value} m`;
                    statusEl.textContent = `Area reachable within ${label} (${profileSelect.value.toLowerCase()}).`;
                } catch (error) {
                    console.error('Error fetching isochrone:', error);
                    statusEl.textContent = 'Failed to calculate the isochrone. Please try again.';
                }
            });
        </script>
    </body>
</html>

Hinweise

  • calcRoute() erwartet ein Array von Punkten sowie ein Options-Objekt; hier enthält das Array nur den Ausgangspunkt. Punkte können als { longitude, latitude }, { lat, lng }, [lng, lat], ein GeoJSON-Point oder ein GeolocationCoordinates-Objekt des Browsers übergeben werden.
  • Der SpeedProfile-Typ der Bibliothek ist "FAST" | "BICYCLE" | "PEDESTRIAN" – enger als das speedProfile des REST-Endpunkts, das zusätzlich "SLOW" akzeptiert.
  • timeInMinutes und distanceInMeters schließen sich gegenseitig aus – lassen Sie den nicht verwendeten Wert auf undefined statt auf 0, sonst überschreibt er den Standardwert.
  • Die Antwort hat dieselbe Form wie beim REST-Endpunkt: zwei Features, das Umriss-Polygon (properties.featureType === "ISOCHRONE_OUTLINE_POLYGON") und der Ursprungspunkt.

Die vollständige Klassenreferenz finden Sie unter RoutingIsochrone, oder nutzen Sie die REST-Version, wenn Sie den Endpunkt direkt aufrufen möchten.