【问题标题】:Mapbox javascript : to animate marker on a polyline (points)Mapbox javascript:为折线(点)上的标记设置动画
【发布时间】:2021-01-07 16:03:59
【问题描述】:

我需要添加一个在点(折线)上移动的标记,我尝试使用https://docs.mapbox.com/mapbox-gl-js/example/animate-point-along-route,但它是一条线,我有很多点..我不知道该怎么做..我试过这个@ 987654322@ 但它不起作用.. 感谢您的帮助!

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]
        }
    });
}

【问题讨论】:

    标签: javascript jquery-animate mapbox marker points


    【解决方案1】:

    我在下面结合了 Emma 和 Moritz 的代码;

    <!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

    【讨论】:

      【解决方案2】:

      嗨,Emma,您仍然可以使用该方法。它也适用于给定的多个坐标。请参阅下面的示例,它适用于 3 个坐标。 (额外 1 个坐标对)您可以根据需要添加任意数量的额外“航点”:

      (要使其正常工作,请替换“您的访问令牌”)

      <!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>

      当然你也可以创建一个坐标列表,并将这个列表传递给geoJson路由对象。

      【讨论】:

      猜你喜欢
      • 2014-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-30
      • 1970-01-01
      • 1970-01-01
      • 2014-01-02
      相关资源
      最近更新 更多