【问题标题】:Mapbox javascript : to make a break at the marker that moves (simulation red traffic light)Mapbox javascript:在移动的标记处休息(模拟红色交通灯)
【发布时间】:2021-01-11 14:45:17
【问题描述】:

如何像在红绿灯处一样在我的标记处休息,然后重新开始,(短暂停留)我在网上找不到任何 tuto ..(在坐标的随机点停止) ,这是为了模拟..我只是想知道我们是怎么做的..我试过setTimeOut,但它不起作用..谢谢你的帮助!!

var marker1 = new mapboxgl.Marker({
        className: 'marker1'
    }) // Initialize a new marker 
    .setLngLat([6.167361, 45.362544]) // Marker [lng, lat] coordinates
    .addTo(map);

var coords = [
    [6.157903, 45.361839],
    [6.157956, 45.361699],
    [6.161326, 45.363424],
    [6.165399, 45.361447],
    [6.16741, 45.36239],
    [6.167361, 45.362544]

];

var origin = [6.157903, 45.361839];
var waypoint1 = [6.157956, 45.361699];
var waypoint2 = [6.161326, 45.363424];
var waypoint3 = [6.165399, 45.361447];
var waypoint4 = [6.16741, 45.36239];

var destination = [6.167361, 45.362544];
var size = 250;

// implementation of CustomLayerInterface to draw a pulsing dot icon on the map
// see https://docs.mapbox.com/mapbox-gl-js/api/#customlayerinterface for more info
var pulsingDot = {
    width: size,
    height: size,
    data: new Uint8Array(size * size * 4),

    // get rendering context for the map canvas when layer is added to the map
    onAdd: function () {
        var canvas = document.createElement('canvas');
        canvas.width = this.width;
        canvas.height = this.height;
        this.context = canvas.getContext('2d');
    },

    // called once before every frame where the icon will be used
    render: function () {
        var duration = 1000;
        var t = (performance.now() % duration) / duration;

        var radius = (size / 2) * 0.3;
        var outerRadius = (size / 2) * 0.7 * t + radius;
        var context = this.context;

        // draw outer circle
        context.clearRect(0, 0, this.width, this.height);
        context.beginPath();
        context.arc(
            this.width / 2,
            this.height / 2,
            outerRadius,
            0,
            Math.PI * 2
        );
        context.fillStyle = 'rgba(255, 200, 200,' + (1 - t) + ')';
        context.fill();

        // draw inner circle
        context.beginPath();
        context.arc(
            this.width / 2,
            this.height / 2,
            radius,
            0,
            Math.PI * 2
        );
        context.fillStyle = 'rgba(255, 100, 100, 1)';
        context.strokeStyle = 'white';
        context.lineWidth = 2 + 4 * (1 - t);
        context.fill();
        context.stroke();

        // update this image's data with data from the canvas
        this.data = context.getImageData(
            0,
            0,
            this.width,
            this.height
        ).data;

        // continuously repaint the map, resulting in the smooth animation of the dot
        map.triggerRepaint();

        // return `true` to let the map know that the image was updated
        return true;
    }
};
// A simple line from origin to destination.
var route = {
    'type': 'FeatureCollection',
    'features': [{
        'type': 'Feature',
        'geometry': {
            'type': 'LineString',
            'coordinates': [origin, waypoint1, waypoint2, waypoint3, waypoint4, 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 = 2500;

// 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 () {
    map.addImage('pulsing-dot', pulsingDot, {
        pixelRatio: 6
    });
    // 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': '#ff8e0a',
            'line-dasharray': [2, 2]
        }
    });


    map.addLayer({
        'id': 'point',
        'source': 'point',
        'type': 'symbol',
        'layout': {
            'icon-image': 'pulsing-dot',
            'icon-allow-overlap': false,
            'icon-ignore-placement': true
        }
    });


    fitMap(map, coords);

    function animate() {

        counter = counter + 1;
        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);
});

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: 100
    });
}

【问题讨论】:

    标签: javascript animation mapbox marker


    【解决方案1】:

    您可以添加另一个与之前的航点具有相同坐标的航点。我在下面称它为breakpoint

    var origin = [6.157903, 45.361839];
    var waypoint1 = [6.157956, 45.361699];
    var breakpoint = [6.157956, 45.361699];
    var waypoint2 = [6.161326, 45.363424];
    var waypoint3 = [6.165399, 45.361447];
    var waypoint4 = [6.16741, 45.36239];

    这就是您可以向路线添加航点的方法

    var route = {
        'type': 'FeatureCollection',
        'features': [{
            'type': 'Feature',
            'geometry': {
                'type': 'LineString',
                'coordinates': [origin, waypoint1, breakpoint, waypoint2, waypoint3, waypoint4, destination] // here you can add the additional waypoints
            }
        }]
    };

    现在看动画。路线分为多个步骤。步数越多越流畅。

    对于每个步骤,都会向arc 对象添加一个坐标。在arc 中的每个位置之间,动画将以相同的时间移动标记。

    因此,要使标记停止在某个位置,您必须将坐标添加到具有停止位置的arc 对象。

    我在这里做这个:

    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);
            
            
            // logic to add additional coordinates to the arc, with coordinates of the waypoint
            if((segment.geometry.coordinates[0] < waypoint1[0] + 0.5 && segment.geometry.coordinates[0] > waypoint1[0] - 0.5) && (segment.geometry.coordinates[1] < waypoint1[1] + 0.5 && segment.geometry.coordinates[1] > waypoint1[1] - 0.5)){
                for(var i2 = 0; i2 < 10; i2 ++){
                    arc.push(waypoint1);
                }
            }
        }
        
        //update steps
        steps = arc.length;

    您可以通过增加在路点位置推入弧线的元素数量来增加停留在路点的持续时间。 这是我的完整代码。请输入您的访问令牌以运行它。

    <!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]
                    }
                }
            ]
        };
    
        // 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);
            
            if((segment.geometry.coordinates[0] < waypoint1[0] + 0.5 && segment.geometry.coordinates[0] > waypoint1[0] - 0.5) && (segment.geometry.coordinates[1] < waypoint1[1] + 0.5 && segment.geometry.coordinates[1] > waypoint1[1] - 0.5)){
                for(var i2 = 0; i2 < 10; i2 ++){
                    arc.push(waypoint1);
                }
            }
        }
        
        //update steps
        steps = arc.length;
    
        // 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>

    【讨论】:

    • 非常感谢 Moritz,很幸运你来了!我应该添加断点以外的其他内容吗?因为标记没有停止..
    • 你说得对,Emma,我注意到动画并不关心航点。它只关心路径对象中的步数和坐标。
    • @Emma 请在上面的回复中查看我的编辑。我测试了它,它现在停在一个航路点。为了使停止更平滑一点,您可以调整逻辑以仅在接近实际停止时触发。
    • 顶!你的代码有效,我承认我已经放弃了一点,我在网上找遍了,mapbox 缺少文档,教程,找不到,谢谢 Moritz 抽出时间来帮助我,我会尽量适应我的代码...
    猜你喜欢
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-18
    • 2020-03-08
    • 1970-01-01
    • 2018-09-01
    相关资源
    最近更新 更多