Zum Inhalt

Animierte Route

Zeichnen Sie eine Route schrittweise auf der Karte mithilfe von requestAnimationFrame und dynamischen GeoJSON-Updates.

<!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/smartmaps-gl/v2/umd/smartmaps-gl.min.js"></script>
        <style>
            body { margin: 0; padding: 0; }
            html, body, #map { height: 100%; }
            #controls {
                position: absolute;
                top: 20px;
                left: 50%;
                transform: translateX(-50%);
                z-index: 1;
                display: flex;
                gap: 8px;
            }
            button {
                background: #18345c;
                color: white;
                border: none;
                padding: 10px 18px;
                border-radius: 6px;
                font-size: 13px;
                cursor: pointer;
                font-weight: 500;
            }
            button:hover { background: #2c5282; }
            button:disabled { background: #9ca3af; cursor: not-allowed; }
        </style>
    </head>
    <body>
        <div id="map"></div>
        <div id="controls">
            <button id="start-btn" onclick="startAnimation()">Start animation</button>
            <button id="reset-btn" onclick="resetAnimation()" disabled>Reset</button>
        </div>
        <script>
            const map = new smartmapsgl.Map({
                apiKey: "[INSERT API-KEY]",
                container: "map",
                center: { lat: 50.5, lng: 10.0 },
                zoom: 6,
                style: smartmapsgl.MapStyle.ESSENTIAL
            });

            // Route coordinates (Rhine river cities)
            const routeCoords = [
                [6.9603, 50.9375],  // Cologne
                [7.0986, 50.7374],  // Bonn
                [7.5886, 50.3569],  // Koblenz
                [8.2473, 50.0012],  // Mainz
                [8.4037, 49.4875],  // Mannheim
                [8.6821, 49.0069],  // Karlsruhe
                [7.5886, 47.5596]   // Basel
            ];

            let animationId = null;
            let currentIndex = 0;

            map.on("load", () => {
                // Full route (dashed preview)
                map.addSource("full-route", {
                    type: "geojson",
                    data: { type: "Feature", geometry: { type: "LineString", coordinates: routeCoords } }
                });
                map.addLayer({
                    id: "full-route-line",
                    type: "line",
                    source: "full-route",
                    layout: { "line-join": "round", "line-cap": "round" },
                    paint: { "line-color": "#18345c", "line-width": 4, "line-opacity": 0.2, "line-dasharray": [2, 2] }
                });

                // Animated route (grows over time)
                map.addSource("animated-route", {
                    type: "geojson",
                    data: { type: "Feature", geometry: { type: "LineString", coordinates: [routeCoords[0]] } }
                });
                map.addLayer({
                    id: "animated-route-line",
                    type: "line",
                    source: "animated-route",
                    layout: { "line-join": "round", "line-cap": "round" },
                    paint: { "line-color": "#f6b80c", "line-width": 5 }
                });

                // Fit to route
                const bounds = new smartmapsgl.LngLatBounds();
                routeCoords.forEach(c => bounds.extend(c));
                map.fitBounds(bounds, { padding: 50 });
            });

            function interpolate(start, end, t) {
                return [
                    start[0] + (end[0] - start[0]) * t,
                    start[1] + (end[1] - start[1]) * t
                ];
            }

            function startAnimation() {
                document.getElementById("start-btn").disabled = true;
                document.getElementById("reset-btn").disabled = false;
                currentIndex = 0;

                const totalSteps = 200;
                let step = 0;
                const points = [routeCoords[0]];

                function animate() {
                    step++;
                    const progress = step / totalSteps;
                    const segmentFloat = progress * (routeCoords.length - 1);
                    const segIndex = Math.floor(segmentFloat);
                    const segProgress = segmentFloat - segIndex;

                    if (segIndex < routeCoords.length - 1) {
                        const point = interpolate(routeCoords[segIndex], routeCoords[segIndex + 1], segProgress);
                        points.push(point);

                        map.getSource("animated-route").setData({
                            type: "Feature",
                            geometry: { type: "LineString", coordinates: [...points] }
                        });
                    }

                    if (step < totalSteps) {
                        animationId = requestAnimationFrame(animate);
                    } else {
                        document.getElementById("start-btn").disabled = false;
                    }
                }

                animationId = requestAnimationFrame(animate);
            }

            function resetAnimation() {
                if (animationId) cancelAnimationFrame(animationId);
                map.getSource("animated-route").setData({
                    type: "Feature",
                    geometry: { type: "LineString", coordinates: [routeCoords[0]] }
                });
                document.getElementById("start-btn").disabled = false;
                document.getElementById("reset-btn").disabled = true;
            }
        </script>
    </body>
</html>