Mapbox gl HTML latitude and longitude point rendering, dynamic track playback, custom graphics and arrow direction display on the track

Mapbox gl HTML latitude and longitude point rendering, dynamic track playback, custom graphics and arrow direction display on the track

Today I want to troubleshoot a problem. I need to display the direction of connecting multiple latitude and longitude points into line segments, so I try to display it.

1. Mapbox renders longitude and latitude points, lines, multi-lines, and surfaces
2. Add arrow directions to the motion trajectory
3. Add an image (such as a car, etc.) The tomcat kitten icon used in this article can control the motion trajectory, start, play, and stop

1. Rendering

Line rendering:

Insert image description here

Point and line rendering:

Insert image description here

Add arrows to show the direction, and play the tomcat kitten:

Insert image description here
Screenshot during track playback:

Insert image description here

Insert image description here

Add the trajectory direction arrow and the screenshot of the kitten during playback is as follows:
Insert image description here
Modify the map background color and real-time trajectory line color, and the screenshot during playback is as follows:
Insert image description here

2. Source code

2.1 line.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Add a GeoJSON line</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
    <link href="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css" rel="stylesheet">
    <script src="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.js"></script>
    <style>
        body {
      
      
            margin: 0;
            padding: 0;
        }

        #map {
      
      
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }
    </style>
</head>
<body>
<div id="map"></div>
<script>
    // TO MAKE THE MAP APPEAR YOU MUST
    // ADD YOUR ACCESS TOKEN FROM
    // https://account.mapbox.com
    mapboxgl.accessToken = 'pk.eyJ1******************Lc99g';
    var map = new mapboxgl.Map({
      
      
        container: 'map',
        style: 'mapbox://styles/mapbox/streets-v11',
// center: [-122.486052, 37.830348],
// center: [116.239749,40.0717456],
// center: [117.85448020099696,35.96263648233899],
        center: [116.25456103528076, 40.07649758667226],
        zoom: 14
    });

    map.on('load', function () {
      
      
        map.addSource('route', {
      
      
            'type': 'geojson',
            'data': {
      
      
                'type': 'FeatureCollection',
                'features': [
                    {
      
      
                        'type': 'Feature',
                        'properties': {
      
      },
                        'geometry': {
      
      
                            'type': 'LineString',
                            'coordinates': [[116.25456103528076, 40.07649758667226, 32.60466429684311],
                                [116.25459033603693, 40.076511383622965, 32.46827581245452],
                                [116.25455860845449, 40.07650334314173, 32.52390295546502],
                                [116.25460283054188, 40.07651455000795, 32.44636987615377]]
                        }
                    },
                    {
      
      
                        'type': 'Feature',
                        'geometry': {
      
      
                            'type': 'Point',
                            'coordinates': [116.25456103528076, 40.07649758667226, 32.60466429684311]
                        }
                    },
                    {
      
      
                        'type': 'Feature',
                        'geometry': {
      
      
                            'type': 'Point',
                            'coordinates': [116.25459033603693, 40.076511383622965, 32.46827581245452]
                        }
                    },
                    {
      
      
                        'type': 'Feature',
                        'geometry': {
      
      
                            'type': 'Point',
                            'coordinates': [116.25455860845449, 40.07650334314173, 32.52390295546502]
                        }
                    },
                    {
      
      
                        'type': 'Feature',
                        'geometry': {
      
      
                            'type': 'Point',
                            'coordinates': [116.25460283054188, 40.07651455000795, 32.44636987615377]
                        }
                    }
                ]
            }
        });
        map.addLayer({
      
      
            'id': 'route',
            'type': 'line',
            'source': 'route',
            'layout': {
      
      
                'line-join': 'round',
                'line-cap': 'round'
            },
            'paint': {
      
      
                'line-color': '#DC143C',
                'line-width': 5
            }
        });

        map.addLayer({
      
      
            'id': 'routePoint',
            'type': 'circle',
            'source': 'route',
            'paint': {
      
      
                'circle-radius': 6,
                'circle-color': '#0000FF'
            },
            'filter': ['==', '$type', 'Point']
        });
    });
</script>

</body>
</html>

2.2line_arrow.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Add a GeoJSON line,with Arrow</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
    <link href="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css" rel="stylesheet">
    <script src="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.js"></script>
    <script src="https://unpkg.com/@turf/[email protected]/turf.min.js"></script>
    <style>
        body {
      
      
            margin: 0;
            padding: 0;
        }

        .menuBar {
      
      
            position: relative;
            top: 10px;
            margin: 0 50px;
            padding: 5px;
            border-radius: 3px;
            z-index: 999;
            background-color: rgba(0, 168, 0, 0.7);
        }

        input[type=button] {
      
      
            font-size: 16px;
        }

        #map {
      
      
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        /* 删除mapbox logo */
        .mapboxgl-ctrl {
      
      
            display: none !important;
        }
    </style>
</head>

<body>
<div id="map"></div>
<div class="menuBar">
    <input type="button" value="开始" onclick="startClick()"/>
    <input type="button" value="暂停" onclick="pauseClick()"/>
    <input type="button" value="停止" onclick="stopClick()"/>
    <div id="canvas"></div>
</div>
<script>
    // TO MAKE THE MAP APPEAR YOU MUST ADD YOUR ACCESS TOKEN FROM
    // https://account.mapbox.com
    mapboxgl.accessToken = 'pk.eyJ********';
    var map = new mapboxgl.Map({
      
      
        container: 'map',
        style: 'mapbox://styles/mapbox/streets-v11',
        // center: [116.25456103528076, 40.07649758667226],
        // zoom: 24
        center: [116.390619, 39.924317], // starting position [lng, lat]
        zoom: 13 // starting zoom
    });
    // 背景色
    // map.setStyle('mapbox://styles/mapbox/dark-v9');

    // 箭头-右
    var svgXML =
        `<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
                <path d="M529.6128 512L239.9232 222.4128 384.7168 77.5168 819.2 512 384.7168 946.4832 239.9232 801.5872z" p-id="9085" fill="#ff00ff"></path>
            </svg>
            `
    //给图片对象写入base64编码的svg流
    var svgBase64 = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(svgXML)));

    map.on('load', function () {
      
      
        let arrowIcon = new Image(20, 20)
        arrowIcon.src = svgBase64
        arrowIcon.onload = function () {
      
      
            map.addImage('arrowIcon', arrowIcon)
            console.log("----------1 " + arrowIcon)
            map.loadImage('img/arrowR.png', function (error, arrowIcon2) {
      
      
                if (arrowIcon2) {
      
      
                    map.addImage('arrowIcon2', arrowIcon2);
                }
            })
            map.loadImage('img/car.png', function (error, carIcon) {
      
      
                if (carIcon) {
      
      
                    console.log("----------2 " + arrowIcon)
                    map.addImage('carIcon', carIcon);
                    setRouteData()
                }
                console.log("----------3 " + arrowIcon)
            });
        }
    })

    var isPlay = false
    var counter = 0
    var steps = 0
    let aLength = 0;
    var routeGeoJson = {
      
      
        'type': 'FeatureCollection',
        'features': [{
      
      
            'type': 'Feature',
            'geometry': {
      
      
                'type': 'LineString',
                'coordinates': [
                    [116.391844, 39.898457],
                    [116.377947, 39.898595],
                    [116.368001, 39.898341],
                    [116.357144, 39.898063],
                    [116.351934, 39.899095],
                    [116.35067, 39.905871],
                    [116.3498, 39.922329],
                    [116.349671, 39.931017],
                    [116.349225, 39.939104],
                    [116.34991, 39.942233],
                    [116.366892, 39.947263],
                    [116.387537, 39.947568],
                    [116.401988, 39.947764],
                    [116.410824, 39.947929],
                    [116.42674, 39.947558],
                    [116.427338, 39.9397],
                    [116.427919, 39.932404],
                    [116.428377, 39.923109],
                    [116.429583, 39.907094],
                    [116.41404, 39.906858],
                    [116.405321, 39.906622],
                    [116.394954, 39.906324],
                    [116.391264, 39.906308],
                    [116.390748, 39.916611]
                ]
                /*[
                    [116.25456103528076, 40.07649758667226, 32.60466429684311],
                    [116.25459033603693, 40.076511383622965, 32.46827581245452],
                    [116.25455860845449, 40.07650334314173, 32.52390295546502],
                    [116.25460283054188, 40.07651455000795, 32.44636987615377]
                ]*/
            }
        }]
    }

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

    var animatePointGeoJson = {
      
      
        'type': 'FeatureCollection',
        'features': [{
      
      
            'type': 'Feature',
            'properties': {
      
      },
            'geometry': {
      
      
                'type': 'Point',
                'coordinates': []
            }
        }]
    }

    // 获取轨迹数据
    function setRouteData() {
      
      
        animatePointGeoJson.features[0].geometry.coordinates = routeGeoJson.features[0].geometry.coordinates[0]
        aLength = routeGeoJson.features[0].geometry.coordinates.length;
        newRouteGeoJson = resetRoute(routeGeoJson.features[0], 1000, 'kilometers')
        steps = newRouteGeoJson.geometry.coordinates.length

        addRoutelayer() // 添加轨迹线图层
        addRealRouteSource() // 添加实时轨迹线图层
        addArrowlayer() // 添加箭头图层
        addAnimatePointSource() // 添加动态点图层
    }

    // 添加轨迹线图层
    function addRoutelayer() {
      
      
        map.addLayer({
      
      
            'id': 'routeLayer',
            'type': 'line',
            'source': {
      
      
                'type': 'geojson',
                'lineMetrics': true,
                'data': routeGeoJson
            },
            'paint': {
      
      
                'line-width': 10,
                'line-opacity': 1,
                'line-color': '#009EFF',
            }
        });
    }

    // 添加实时轨迹线
    function addRealRouteSource() {
      
      
        map.addLayer({
      
      
            'id': 'realRouteLayer',
            'type': 'line',
            'source': {
      
      
                'type': 'geojson',
                'lineMetrics': true,
                'data': realRouteGeoJson
            },
            'paint': {
      
      
                'line-width': 3,
                'line-opacity': 1,
                'line-color': '#FF0000',
            }
        });
    }

    // 添加箭头图层
    function addArrowlayer() {
      
      
        console.log("-------addArrowlayer")
        map.addLayer({
      
      
            'id': 'arrowLayer',
            'type': 'symbol',
            'source': {
      
      
                'type': 'geojson',
                'data': routeGeoJson //轨迹geojson格式数据
            },
            'layout': {
      
      
                'symbol-placement': 'line',
                'symbol-spacing': 50, // 图标间隔,默认为250
                'icon-image': 'arrowIcon2', //箭头图标
                'icon-size': 0.5,
                'icon-rotate': ['get', 'bearing'],
                'icon-rotation-alignment': 'map',
                'icon-allow-overlap': true,
                'icon-ignore-placement': true
            }
        });
        console.log("-------addArrowlayer end...")
    }

    // 添加动态点图层
    function addAnimatePointSource() {
      
      
        map.addLayer({
      
      
            'id': 'animatePointLayer',
            'type': 'symbol',
            'source': {
      
      
                'type': 'geojson',
                'data': animatePointGeoJson
            },
            'layout': {
      
      
                'icon-image': 'carIcon',
                'icon-size': 0.5,
                'icon-rotate': ['get', 'bearing'],
                'icon-rotation-alignment': 'map',
                'icon-allow-overlap': true,
                'icon-ignore-placement': true
            }
        });

        animate()
    }

    function animate() {
      
      
        if (counter >= steps) {
      
      
            return
        }
        var startPnt, endPnt
        if (counter == 0) {
      
      
            realRouteGeoJson.features[0].geometry.coordinates = []
            startPnt = newRouteGeoJson.geometry.coordinates[counter]
            endPnt = newRouteGeoJson.geometry.coordinates[counter + 1]
        } else if (counter !== 0) {
      
      
            startPnt = newRouteGeoJson.geometry.coordinates[counter - 1]
            endPnt = newRouteGeoJson.geometry.coordinates[counter]
        }

        animatePointGeoJson.features[0].properties.bearing = turf.bearing(
            turf.point(startPnt),
            turf.point(endPnt)
        ) - 90;
        animatePointGeoJson.features[0].geometry.coordinates = newRouteGeoJson.geometry.coordinates[counter];
        realRouteGeoJson.features[0].geometry.coordinates.push(animatePointGeoJson.features[0].geometry.coordinates)

        map.getSource('animatePointLayer').setData(animatePointGeoJson);
        map.getSource('realRouteLayer').setData(realRouteGeoJson);
        if (isPlay) {
      
      
            requestAnimationFrame(animate);
        }
        counter = counter + 1;
    }

    function resetRoute(route, nstep, units) {
      
      
        var newroute = {
      
      
            'type': 'Feature',
            'geometry': {
      
      
                'type': 'LineString',
                'coordinates': []
            }
        }
        var lineDistance = turf.lineDistance(route);
        var nDistance = lineDistance / nstep;
        for (let i = 0; i < aLength - 1; i++) {
      
      
            var from = turf.point(route.geometry.coordinates[i]);
            var to = turf.point(route.geometry.coordinates[i + 1]);
            let lDistance = turf.distance(from, to, {
      
      
                units: units
            });
            if (i == 0) {
      
      
                newroute.geometry.coordinates.push(route.geometry.coordinates[0])
            }
            if (lDistance > nDistance) {
      
      
                let rings = lineMore(from, to, lDistance, nDistance, units)
                newroute.geometry.coordinates = newroute.geometry.coordinates.concat(rings)
            } else {
      
      
                newroute.geometry.coordinates.push(route.geometry.coordinates[i + 1])
            }
        }
        return newroute
    }

    function lineMore(from, to, distance, splitLength, units) {
      
      
        var step = parseInt(distance / splitLength)
        var leftLength = distance - step * splitLength
        var rings = []
        var route = turf.lineString([from.geometry.coordinates, to.geometry.coordinates])
        for (let i = 1; i <= step; i++) {
      
      
            let nlength = i * splitLength
            let pnt = turf.along(route, nlength, {
      
      
                units: units
            });
            rings.push(pnt.geometry.coordinates)
        }
        if (leftLength > 0) {
      
      
            rings.push(to.geometry.coordinates)
        }
        return rings
    }

    function startClick() {
      
      
        if (!isPlay) {
      
      
            isPlay = true
            animate()
        }
    }

    function pauseClick() {
      
      
        isPlay = false
        animate()
    }

    function stopClick() {
      
      
        isPlay = false
        counter = 0
        animate()
    }
</script>

</body>

</html>

reference

Guess you like

Origin blog.csdn.net/qq_40985985/article/details/132805417