使用Mapbox-GL.JS对路线上的多个点进行动画处理 [英] Animate multiple point along routes using Mapbox-GL.JS

查看:92
本文介绍了使用Mapbox-GL.JS对路线上的多个点进行动画处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在以下示例中遇到问题:
沿路线设置动画点我要实现的目标是在同一个地图容器中提出另一个要点和路线.
到目前为止,我尝试过的是

I am having problems with following example :
Animate a point along a route What I am trying to achieve is to make another point and routes in the same map container.
What I tried so far is this

mapboxgl.accessToken = 'pk.eyJ1IjoicGFwYWJ1Y2t0IiwiYSI6ImNqa2k3azQ1dzA1Zmgza3B1czIxOGhhaW4ifQ.h5OT3NaQf0vcxx3g1q1cXw';
var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v9',
    center: [118.0148634, -2.548926],
    zoom: 4.1
});
var route = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "LineString",
                "coordinates": [
                   [117.66769409179686,3.2913401805277034],[117.75009155273438,3.2419820359767444],
                   [117.81188964843751,3.2008484073844365],[117.93273925781249,3.1514858749293237],
                   [118.048095703125,3.0637245031869744],[118.20190429687501,2.9649843693339677],
                   [118.35571289062499,2.855262784366583],[118.443603515625,2.789424777005989],
                   [118.597412109375,2.67419944615503],[118.817138671875,2.4656692707025543],
                   [118.93798828125,2.191238104506552],[118.97644042968749,1.9442068658308456],
                   [119.0643310546875,1.6477220517969353],[119.13574218749999,1.334718132769963],
                   [119.15222167968751,1.0051974541602744],[119.05334472656249,0.5987439850125229],
                   [118.9215087890625,0.29113644247137116],[118.8006591796875,-0.027465819260582135],
                   [118.597412109375,-0.5163504323777461],[118.27880859375001,-0.8953492997435784],
                   [118.16894531249999,-1.219390359762202],[117.83935546874999,-1.6641946615712557],
                   [117.7349853515625,-1.8618548574369598],[117.65258789062499,-2.0485136203038063],
                   [117.40539550781249,-2.67968661580376],[117.07580566406249,-3.2721456350750127],
                   [116.7572021484375,-3.8806964824972487],[116.44958496093749,-4.209464815163466],
                   [115.7574462890625,-4.335456463573485],[115.213623046875,-4.510714125698484],
                   [114.6533203125,-4.647604837557583],[114.1864013671875,-4.70235372255946],
                   [113.79089355468749,-4.7242520745232515],[113.4228515625,-4.8118385341739005],
                   [112.9669189453125,-4.8282597468669755],[112.28576660156249,-4.844680562025358],
                   [111.104736328125,-4.855627550617055],[110.7366943359375,-4.855627550617055],
                   [110.19287109375,-4.855627550617055],[109.60510253906249,-4.926778627933801],
                   [109.00634765625,-5.00339434502215],[108.4075927734375,-5.036226914872183],
                   [108.116455078125,-5.189423479732417],[107.5177001953125,-5.369928743247035],
                   [107.061767578125,-5.473831889192786],[106.76513671875,-5.544913134097361],
                   [106.44653320312499,-5.626919311742117],[106.248779296875,-5.747174076651375],
                   [106.1444091796875,-5.807291968003861],[106.02948188781738,-5.882003409958776]
                ]
            }
        },
        {
          "type": "Feature",
          "properties": {},
          "geometry": {
                "type": "LineString",
                "coordinates": [
                      [-252.99316406250003,-5.932972207945653],[-252.92724609374997,-5.774501181937723],
                      [-252.872314453125,-5.697981985463135],[-252.8118896484375,-5.572249801113899],
                      [-252.7789306640625,-5.484768018141262],[-252.7294921875,-5.353521355337321],
                      [-252.66357421875,-5.244127581489528],[-252.57568359374997,-5.112829778499449],
                      [-252.509765625,-5.00339434502215],[-252.42187499999997,-4.872047700241915],
                      [-252.2900390625,-4.740675384778361],[-252.11425781249997,-4.653079918274038],
                      [-252.00439453125,-4.54357027937176],[-251.78466796875,-4.434044005032582],
                      [-251.65283203125003,-4.34641127533318],[-251.45507812499997,-4.171115454867424],
                      [-251.16943359375,-4.083452772038619],[-251.03759765625,-3.9738609758391017],
                      [-250.90576171875,-3.8204080831949407],[-250.70800781249997,-3.688855143147035],
                      [-250.42236328125,-3.579212785860631],[-250.31250000000003,-3.513421045640032],
                      [-250.13671875,-3.3818237353282767],[-249.87304687499997,-3.2940822283128046],
                      [-249.697265625,-3.118576216781991],[-249.697265625,-2.943040910055132]
                ]
            }
        }
    ]
};

// 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": [117.66769409179686,3.2913401805277034]
            }
        },
        {
            "type": "Feature",
            "properties": {},
            "geometry": {
                "type": "Point",
                "coordinates": [-252.99316406250003,-5.932972207945653]
            }
        }

    ]
};

// Calculate the distance in kilometers between route start/end point.
for(i=0;i<2;i++) {
   var lineDistance = turf.lineDistance(route.features[0], 'kilometers');
}
   console.log(lineDistance) 


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 = 1000;

// 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, 'kilometers');
    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": 1,
            "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() {
        // Update point geometry to a new position based on counter denoting
        // the index to access the arc.

        for(i=0;i < 2;i++) {
            point.features[i].properties.bearing = turf.bearing(
                turf.point(route.features[i].geometry.coordinates[counter >= steps ? counter - 1 : counter]),
                turf.point(route.features[i].geometry.coordinates[counter >= steps ? counter : counter + 1])
            );  
        }
        

        point.features[0].geometry.coordinates = route.features[0].geometry.coordinates[counter];
        // Update the source with this new data.
        map.getSource('point').setData(point);

        // Request the next frame of animation so long 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);
});

.overlay {
    position: absolute;
    top: 10px;
    left: 30px;
}

.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;
}
body { margin:0; padding:0; }
#map { top:0; bottom:0; width:100%;height: 600px }

<!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' />
    
    <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.css' rel='stylesheet' />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.js'></script>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

   
</head>
<body>
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/turf/v2.0.0/turf.min.js' charset='utf-8'></script>
<div class="col-md-12">
    <div class="card text-white">
      <h5 class="card-header bg-info">Featured</h5>
      <div class="card-body">
        <div class="col-md-12">
            <div id='map'></div>
            <div class='overlay'>
                <button id='replay'>Replay</button>
            </div>
        </div>    
      </div>
    </div>
</div>

</body>
</html>

经过几次尝试,第一次尝试的结果是Point 1和Line 1到达终点.但是Point 2 and Line 2在Point 1和Line 1到达终点之后停止了.这是我的第十次尝试.另一个尝试是循环出错.
我该怎么办?

After few things that I tried,the result of first attempt was Point 1 and Line 1 are reaching to the end.but Point 2 and Line 2 stopped after Point 1 and Line 1 are reaching to the end.
This is my 10th attempt. The other attempt was error on the loop.
What should I do with this ?

推荐答案

基本问题是两条路线的长度不同,因此您仍在穿越较短路线时会越过较短路线的坐标范围更长的一个.我在下面插入的代码片段说明了这一点.尝试一下,我的编辑就完成了,没有错误.

The basic problem is that the two routes are different lengths, so you go out of bounds on the coordinates for the shorter one while you're still going through the longer one. The snippet I inserted below accounts for that. Trying it just now, my edit completes without errors.

您可能需要进一步调整,现在较短的路线比较长的路线要快得多,并且移动速度要比较长的路线快得多.如果您希望它们表现出相同的速度,则对于较短的步骤,您将需要使用较少的步骤.如果希望它们在相同的时间内完成,则需要在较短的点上添加更多的点,或减少较短的点刷新的频率.

You'll probably want to tweak it a bit further, right now the shorter route completes much more quickly than the longer one, and moves much faster than the longer one. If you want them to appear to go the same speed, you'll need to use fewer steps for for the shorter one. If you want them to complete in the same amount of time, you'll need to add more points to the shorter one, or reduce the frequency with which the shorter one refreshes.

mapboxgl.accessToken = 'pk.eyJ1IjoicGFwYWJ1Y2t0IiwiYSI6ImNqa2k3azQ1dzA1Zmgza3B1czIxOGhhaW4ifQ.h5OT3NaQf0vcxx3g1q1cXw';
var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v9',
    center: [118.0148634, -2.548926],
    zoom: 4.1
});
var route = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "LineString",
                "coordinates": [
                   [117.66769409179686,3.2913401805277034],[117.75009155273438,3.2419820359767444],
                   [117.81188964843751,3.2008484073844365],[117.93273925781249,3.1514858749293237],
                   [118.048095703125,3.0637245031869744],[118.20190429687501,2.9649843693339677],
                   [118.35571289062499,2.855262784366583],[118.443603515625,2.789424777005989],
                   [118.597412109375,2.67419944615503],[118.817138671875,2.4656692707025543],
                   [118.93798828125,2.191238104506552],[118.97644042968749,1.9442068658308456],
                   [119.0643310546875,1.6477220517969353],[119.13574218749999,1.334718132769963],
                   [119.15222167968751,1.0051974541602744],[119.05334472656249,0.5987439850125229],
                   [118.9215087890625,0.29113644247137116],[118.8006591796875,-0.027465819260582135],
                   [118.597412109375,-0.5163504323777461],[118.27880859375001,-0.8953492997435784],
                   [118.16894531249999,-1.219390359762202],[117.83935546874999,-1.6641946615712557],
                   [117.7349853515625,-1.8618548574369598],[117.65258789062499,-2.0485136203038063],
                   [117.40539550781249,-2.67968661580376],[117.07580566406249,-3.2721456350750127],
                   [116.7572021484375,-3.8806964824972487],[116.44958496093749,-4.209464815163466],
                   [115.7574462890625,-4.335456463573485],[115.213623046875,-4.510714125698484],
                   [114.6533203125,-4.647604837557583],[114.1864013671875,-4.70235372255946],
                   [113.79089355468749,-4.7242520745232515],[113.4228515625,-4.8118385341739005],
                   [112.9669189453125,-4.8282597468669755],[112.28576660156249,-4.844680562025358],
                   [111.104736328125,-4.855627550617055],[110.7366943359375,-4.855627550617055],
                   [110.19287109375,-4.855627550617055],[109.60510253906249,-4.926778627933801],
                   [109.00634765625,-5.00339434502215],[108.4075927734375,-5.036226914872183],
                   [108.116455078125,-5.189423479732417],[107.5177001953125,-5.369928743247035],
                   [107.061767578125,-5.473831889192786],[106.76513671875,-5.544913134097361],
                   [106.44653320312499,-5.626919311742117],[106.248779296875,-5.747174076651375],
                   [106.1444091796875,-5.807291968003861],[106.02948188781738,-5.882003409958776]
                ]
            }
        },
        {
          "type": "Feature",
          "properties": {},
          "geometry": {
                "type": "LineString",
                "coordinates": [
                      [-252.99316406250003,-5.932972207945653],[-252.92724609374997,-5.774501181937723],
                      [-252.872314453125,-5.697981985463135],[-252.8118896484375,-5.572249801113899],
                      [-252.7789306640625,-5.484768018141262],[-252.7294921875,-5.353521355337321],
                      [-252.66357421875,-5.244127581489528],[-252.57568359374997,-5.112829778499449],
                      [-252.509765625,-5.00339434502215],[-252.42187499999997,-4.872047700241915],
                      [-252.2900390625,-4.740675384778361],[-252.11425781249997,-4.653079918274038],
                      [-252.00439453125,-4.54357027937176],[-251.78466796875,-4.434044005032582],
                      [-251.65283203125003,-4.34641127533318],[-251.45507812499997,-4.171115454867424],
                      [-251.16943359375,-4.083452772038619],[-251.03759765625,-3.9738609758391017],
                      [-250.90576171875,-3.8204080831949407],[-250.70800781249997,-3.688855143147035],
                      [-250.42236328125,-3.579212785860631],[-250.31250000000003,-3.513421045640032],
                      [-250.13671875,-3.3818237353282767],[-249.87304687499997,-3.2940822283128046],
                      [-249.697265625,-3.118576216781991],[-249.697265625,-2.943040910055132]
                ]
            }
        }
    ]
};

// 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": [117.66769409179686,3.2913401805277034]
            }
        },
        {
            "type": "Feature",
            "properties": {},
            "geometry": {
                "type": "Point",
                "coordinates": [-252.99316406250003,-5.932972207945653]
            }
        }

    ]
};

// Calculate the distance in kilometers between route start/end point.
for(i=0;i<2;i++) {
   var lineDistance = turf.lineDistance(route.features[0], 'kilometers');
}
   console.log(lineDistance) 


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 = 1000;

// 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, 'kilometers');
    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": 1,
            "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(featureIdx, cntr) {
        // Update point geometry to a new position based on counter denoting
        // the index to access the arc.
        if (cntr >= route.features[featureIdx].geometry.coordinates.length-1){
          return;
        }
        point.features[featureIdx].geometry.coordinates = route.features[featureIdx].geometry.coordinates[cntr];


        point.features[featureIdx].properties.bearing = turf.bearing(
            turf.point(route.features[featureIdx].geometry.coordinates[cntr >= steps ? cntr - 1 : cntr]),
            turf.point(route.features[featureIdx].geometry.coordinates[cntr >= steps ? cntr : cntr + 1])
        );  
        

        // Update the source with this new data.
        map.getSource('point').setData(point);

        // Request the next frame of animation so long the end has not been reached.
        if (cntr < steps) {
            requestAnimationFrame(function(){animate(featureIdx, cntr+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
        cntr = 0;

        // Restart the animation.
        animate(0,cntr);
        animate(1,cntr)
    });

    // Start the animation.
    animate(0, 0);
    animate(1, 0);
});

.overlay {
    position: absolute;
    top: 10px;
    left: 30px;
}

.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;
}
body { margin:0; padding:0; }
#map { top:0; bottom:0; width:100%;height: 600px }

<!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' />
    
    <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.css' rel='stylesheet' />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.js'></script>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

   
</head>
<body>
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/turf/v2.0.0/turf.min.js' charset='utf-8'></script>
<div class="col-md-12">
    <div class="card text-white">
      <h5 class="card-header bg-info">Featured</h5>
      <div class="card-body">
        <div class="col-md-12">
            <div id='map'></div>
            <div class='overlay'>
                <button id='replay'>Replay</button>
            </div>
        </div>    
      </div>
    </div>
</div>

</body>
</html>

这篇关于使用Mapbox-GL.JS对路线上的多个点进行动画处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆