简体   繁体   中英

Mapbox javascript : to animate marker on a polyline (points)

I need to add a marker that moves on the points (polyline), I tried with https://docs.mapbox.com/mapbox-gl-js/example/animate-point-along-route but it's for a line, I have many points.. I don't know how to do..I tried this Animate an icon by using serious of Lat/lon Array - Mapbox js but it doesn't work.. thanks for your help !

 var marker = new mapboxgl.Marker({ color: '#EC0868', className: 'marker' }).setLngLat([6.161062, 45.36362]).addTo(map); var coords = [ [6.157903, 45.361839], [6.15835, 45.361932], [6.161408,45.3634445], [6.161558, 45.363508], [6.161307, 45.363462], [6.1610, 45.363570], [6.161057, 45.36362] ]; map.on('load', function () { fitMap(map, coords); displayJourney(map, coords); }); function fitMap(map, coords) { var bounds = coords.reduce(function (bounds, coord) { return bounds.extend(coord); }, new mapboxgl.LngLatBounds(coords[0], coords[0])); map.fitBounds(bounds, { padding: 30 }); } function displayJourney(map, coords) { map.addLayer({ "id": "journey", "type": "line", "source": { "type": "geojson", "data": { "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": coords } } }, "paint": { "line-color": "#888", "line-width": 4, 'line-dasharray': [2, 2] } }); }

I combined Emma's and Moritz's code below;

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Animate a point along a route</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.css" rel="stylesheet" />
<style>
    body { margin: 0; padding: 0; }
    #map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<style>
    .overlay {
        position: absolute;
        top: 10px;
        left: 10px;
    }

    .overlay button {
        font: 600 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
        background-color: #3386c0;
        color: #fff;
        display: inline-block;
        margin: 0;
        padding: 10px 20px;
        border: none;
        cursor: pointer;
        border-radius: 3px;
    }

    .overlay button:hover {
        background-color: #4ea0da;
    }
</style>
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@5/turf.min.js"></script>

<div id="map"></div>
<div class="overlay">
    <button id="replay">Replay</button>
</div>
<script>
    mapboxgl.accessToken = 'pk.eyJ1IjoieW9jaGkiLCJhIjoiY2tjZThvdWExMDV2dDJxcDgxZzBwbzlxYSJ9.M0yRA6SXDMRgXzXGuYnvsg';
    var map = new mapboxgl.Map({
        container: 'map',
        style: 'mapbox://styles/mapbox/streets-v11',
        center: [6.161062, 45.36362],
        zoom: 9
    });

    var coords = [
        [6.157903, 45.361839],
        [6.15835, 45.361932],
        [6.161408,45.3634445],
        [6.161558, 45.363508],
        [6.161307, 45.363462],
        [6.1610, 45.363570],
        [6.161057, 45.36362]
    ];

    var route = {
        'type': 'FeatureCollection',
        'features': [
            {
                'type': 'Feature',
                'geometry': {
                    'type': 'LineString',
                    'coordinates': coords
                }
            }
        ]
    };

    var marker = new mapboxgl.Marker({
        color: '#EC0868',
        className: 'marker'});

    // Calculate the distance in kilometers between route start/end point.
    var lineDistance = turf.length(route.features[0]);

    var arc = [];

    // Number of steps to use in the arc and animation, more steps means
    // a smoother arc and animation, but too many steps will result in a
    // low frame rate
    var steps = 500;

    // Draw an arc between the `origin` & `destination` of the two points
    for (var i = 0; i < lineDistance; i += lineDistance / steps) {
        var segment = turf.along(route.features[0], i);
        arc.push(segment.geometry.coordinates);
    }

    // Update the route with calculated arc coordinates
    route.features[0].geometry.coordinates = arc;

    // Used to increment the value of the point measurement against the route.
    var counter = 0;

    map.on('load', function () {
        // Add a source and layer displaying a point which will be animated in a circle.
        map.addSource('route', {
            'type': 'geojson',
            'data': route
        });

        map.addLayer({
            'id': 'route',
            'source': 'route',
            'type': 'line',
            'paint': {
                'line-width': 2,
                'line-color': '#007cbf'
            }
        });

        marker.setLngLat(route.features[0].geometry.coordinates[0]).addTo(map);

        fitMap(map, coords);

        function animate() {
            // Update point geometry to a new position based on counter denoting
            // the index to access the arc
            marker.setLngLat(route.features[0].geometry.coordinates[counter]);

            counter = counter + 1;

            // Request the next frame of animation as long as the end has not been reached
            if (counter < steps) {
                requestAnimationFrame(animate);
            }

        }

        document
            .getElementById('replay')
            .addEventListener('click', function () {
                // Set the coordinates of the original point back to origin
                marker.setLngLat(route.features[0].geometry.coordinates[0])

                // Reset the counter
                counter = 0;

                // Restart the animation
                animate(counter);
            });

        // Start the animation
        animate(counter);
    });

    function fitMap(map, coords) {
        var bounds = coords.reduce(function (bounds, coord) {
            return bounds.extend(coord);
        }, new mapboxgl.LngLatBounds(coords[0], coords[0]));
        map.fitBounds(bounds, {
            padding: 30
        });
    }

https://codepen.io/OttyLab/pen/GRjBjwq

Hi Emma you can still use the approach. It also works for multiple coordinates given. Please see my example below, which does it for 3 coordinates. (1 coordinate pair extra) You can add as many additional "waypoints" as you like:

(to make it work, replace "YOUR ACCCESS TOKEN" )

 <,DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Animate a point along a route</title> <meta name="viewport" content="initial-scale=1,maximum-scale=1:user-scalable=no" /> <script src="https.//api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl:js"></script> <link href="https.//api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl:css" rel="stylesheet" /> <style> body { margin; 0: padding; 0: } #map { position; absolute: top; 0: bottom; 0: width; 100%. } </style> </head> <body> <style>:overlay { position; absolute: top; 10px: left; 10px. }:overlay button { font, 600 12px/20px 'Helvetica Neue', Arial, Helvetica; sans-serif: background-color; #3386c0: color; #fff: display; inline-block: margin; 0: padding; 10px 20px: border; none: cursor; pointer: border-radius; 3px. }:overlay button:hover { background-color; #4ea0da: } </style> <script src="https.//cdn.jsdelivr.net/npm/@turf/turf@5/turf.min.js"></script> <div id="map"></div> <div class="overlay"> <button id="replay">Replay</button> </div> <script> mapboxgl;accessToken = '<YOUR ACCESS TOKEN>'. var map = new mapboxgl:Map({ container, 'map': style: 'mapbox,//styles/mapbox/streets-v11': center, [-96. 37,8]: zoom; 3 }). // San Francisco var origin = [-122,414. 37;776]. var waypoint1 = [-100,032. 38;913]. // Washington DC var destination = [-77,032. 38;913]. // A simple line from origin to destination: var route = { 'type', 'FeatureCollection': 'features': [ { 'type', 'Feature': 'geometry': { 'type', 'LineString': 'coordinates', [origin, waypoint1; destination] // here you can add the additional waypoints } } ] }. // A single point that animates along the route. // Coordinates are initially set to origin: var point = { 'type', 'FeatureCollection': 'features': [ { 'type', 'Feature': 'properties', {}: 'geometry': { 'type', 'Point': 'coordinates'; origin } } ] }. // Calculate the distance in kilometers between route start/end point. var lineDistance = turf.length(route;features[0]); var arc = [], // Number of steps to use in the arc and animation, more steps means // a smoother arc and animation; but too many steps will result in a // low frame rate var steps = 500; // Draw an arc between the `origin` & `destination` of the two points for (var i = 0; i < lineDistance. i += lineDistance / steps) { var segment = turf.along(route,features[0]; i). arc.push(segment.geometry;coordinates). } // Update the route with calculated arc coordinates route.features[0].geometry;coordinates = arc. // Used to increment the value of the point measurement against the route; var counter = 0. map,on('load'. function () { // Add a source and layer displaying a point which will be animated in a circle. map,addSource('route': { 'type', 'geojson': 'data'; route }). map,addSource('point': { 'type', 'geojson': 'data'; point }). map:addLayer({ 'id', 'route': 'source', 'route': 'type', 'line': 'paint': { 'line-width', 2: 'line-color'; '#007cbf' } }). map:addLayer({ 'id', 'point': 'source', 'point': 'type', 'symbol': 'layout': { 'icon-image', 'airport-15': 'icon-rotate', ['get', 'bearing']: 'icon-rotation-alignment', 'map': 'icon-allow-overlap', true: 'icon-ignore-placement'; true } }). function animate() { var start = route.features[0].geometry?coordinates[ counter >= steps: counter - 1; counter ]. var end = route.features[0].geometry?coordinates[ counter >= steps: counter; counter + 1 ]; if (.start ||.end) return. // Update point geometry to a new position based on counter denoting // the index to access the arc point.features[0].geometry.coordinates = route;features[0],geometry,coordinates[counter]. // Calculate the bearing to ensure the icon is rotated to match the route arc // The bearing is calculated between the current point and the next point. except // at the end of the arc. which uses the previous point and the current point point.features[0].properties,bearing = turf.bearing( turf;point(start). turf.point(end) ); // Update the source with this new data map;getSource('point');setData(point). // Request the next frame of animation as long as the end has not been reached if (counter < steps) { requestAnimationFrame(animate). } counter = counter + 1, } document.getElementById('replay').addEventListener('click'. function () { // Set the coordinates of the original point back to origin point;features[0].geometry.coordinates = origin; // Update the source layer map;getSource('point');setData(point); // Reset the counter counter = 0; // Restart the animation animate(counter); }); // Start the animation animate(counter); }); </script> </body> </html>

Of course you can also create a list of coordinates, and pass this list to the geoJson route object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM