mapbox-在地图上实现一个小动画

540 阅读2分钟

mapbox 框架可以在地图上实现动画移动的效果,这种效果用来模拟人行走,或车辆移动都是很好用的。

具体逻辑为: 1、addSource 将需要移动的坐标点作为源先添加进map
2、addLayer 需要移动的图片或marker显示在地图上
3、切割路线为很多个相隔不远的点位组成
4、map.getSource('point').setData(point) 通过不断更新piont点位源数据中的坐标点来不断改变位置,实现移动效果

屏幕截图 2024-02-08 150223.png

屏幕截图 2024-02-08 150242.png

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <script src='https://npmcdn.com/@turf/turf/turf.min.js'></script>
  <link href="https://api.mapbox.com/mapbox-gl-js/v3.0.1/mapbox-gl.css" rel="stylesheet">
  <script src="https://api.mapbox.com/mapbox-gl-js/v3.0.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>
    mapboxgl.accessToken = 'pk.eyJ1IjoiYXl1MjM4OSIsImEiOiJjbGU2dTJtc2IwOHplM3JtcnljODZqNWszIn0.iszjybKhsIp0AYyfu8sQmg'
    const map = new mapboxgl.Map({
      container: 'map',
      // You can add layers to the predetermined slots within the Standard style basemap.
      style: 'mapbox://styles/mapbox/streets-v11', // mapbox官方给出了几种底图可以选择
      center: [104.6826114635814, 28.82097174542686], // 默认地图中心位置 宜宾学院
      zoom: 17 // 地图缩放级别
    })

    const geojson = {
      'type': 'FeatureCollection',
      'features': [
        {
          "geometry": {
            "coordinates": [
              [
                104.68070521337489,
                28.821763271107827
              ],
              [
                104.68251002531275,
                28.820279087189235
              ],
              [
                104.68382875754492,
                28.821495063150238
              ],
              [
                104.68198292373376,
                28.823004875622075
              ],
              [
                104.68075614319605,
                28.82182382735529
              ]
            ],
            "type": "LineString"
          },
          "type": "Feature",
          "properties": {}
        }
      ]
    }

    let newCoord = []
    for (let i = 0; i < geojson.features[0].geometry.coordinates.length - 1; i++) {
      var from = turf.point(geojson.features[0].geometry.coordinates[i])
      var to = turf.point(geojson.features[0].geometry.coordinates[i + 1])
      let lDistance = turf.distance(from, to)
      let rings = lineMore(from, to, lDistance, 0.0004)
      newCoord = newCoord.concat(rings)
    }

    console.log(newCoord)

    const point = {
      'type': 'FeatureCollection',
      'features': [{
        'type': 'Feature',
        'properties': {},
        'geometry': {
          'type': 'Point',
          'coordinates': [
            104.68070521337489,
            28.821763271107827
          ]
        }
      }]
    }

    map.on('load', () => {
      // 先向mapbox加入源数据(geojson数据格式  urban-areas为ID,唯一标记该源数据)
      map.addSource('urban-areas', {
        'type': 'geojson',
        'data': {
          'type': 'FeatureCollection',
          'features': [
            {
              "type": "Feature",
              "geometry": {
                "coordinates": [
                  [
                    [
                      104.68224393266865,
                      28.820825119811616
                    ],
                    [
                      104.68237853175276,
                      28.820806143131804
                    ],
                    [
                      104.68253324334302,
                      28.820821053380044
                    ],
                    [
                      104.68263999433981,
                      28.820854940301558
                    ],
                    [
                      104.68275912226375,
                      28.820936268867015
                    ],
                    [
                      104.68286742037816,
                      28.82104877327741
                    ],
                    [
                      104.68289526846553,
                      28.82113416811103
                    ],
                    [
                      104.68287515595705,
                      28.821333422448802
                    ],
                    [
                      104.68282255401743,
                      28.82143237174087
                    ],
                    [
                      104.68183509950171,
                      28.822183326112793
                    ],
                    [
                      104.68168404453667,
                      28.822164945238
                    ],
                    [
                      104.68153298957174,
                      28.82207426620606
                    ],
                    [
                      104.68144627283152,
                      28.82203015205387
                    ],
                    [
                      104.68134696817822,
                      28.821940698298548
                    ],
                    [
                      104.68130504534406,
                      28.82174906388728
                    ],
                    [
                      104.68130581736818,
                      28.821644899952986
                    ],
                    [
                      104.68134441858416,
                      28.821514356693072
                    ],
                    [
                      104.68200651171475,
                      28.820943623997778
                    ],
                    [
                      104.68224393266865,
                      28.820825119811616
                    ]
                  ]
                ],
                "type": "Polygon"
              },
              "properties": {
                'color': '#FF0000',
                'height': 20
              }
            },
            {
              "geometry": {
                "coordinates": [
                  [
                    [
                      104.68249981776768,
                      28.822209737427144
                    ],
                    [
                      104.68327453745434,
                      28.82160047562293
                    ],
                    [
                      104.68299946596244,
                      28.82133219016545
                    ],
                    [
                      104.6822274898658,
                      28.821938871178958
                    ],
                    [
                      104.68249981776768,
                      28.822209737427144
                    ]
                  ]
                ],
                "type": "Polygon"
              },
              "type": "Feature",
              "properties": {
                'color': '#9f5f9f',
                'height': 40
              }
            }
          ]
        }
      })

      map.addSource('line', {
        type: 'geojson',
        data: geojson
      })

      // urban-areas源数据加入图层,通过geojson数据里的properties获取color和height实现颜色高度自定义
      map.addLayer({
        'id': 'urban-areas-fill',
        'type': 'fill-extrusion',
        'source': "urban-areas",
        'paint': {
          'fill-extrusion-color': ['get', 'color'], // 获取properties里面的color属性值
          'fill-extrusion-height': ['get', 'height'], // 获取properties里面的height属性值
          'fill-extrusion-opacity': 0.9, // 透明度
          'fill-extrusion-base': 0, // 距离底层地图的距离
        }
      })

      map.addLayer({
        type: 'line',
        source: 'line',
        id: 'line-background',
        paint: {
          'line-color': 'blue',
          'line-width': 6,
          'line-opacity': 0.4
        }
      })

      map.loadImage(
        'https://docs.mapbox.com/mapbox-gl-js/assets/cat.png',
        (error, image) => {
          if (error) throw error
          map.addSource('point', {
            'type': 'geojson',
            'data': point
          })
          // Add the image to the map style.
          map.addImage('cat', image)
          map.addLayer({
            'id': 'point',
            'source': 'point',
            'type': 'symbol',
            'layout': {
              'icon-image': 'cat',
              'icon-size': 0.1,
              'icon-rotate': ['get', 'bearing'],
              // 'icon-rotation-alignment': 'map',
              'icon-allow-overlap': true,
              'icon-ignore-placement': true
            }
          })
        }
      )
    })

    const steps = newCoord.length
    let counter = 0
    function animate() {
      const start = newCoord[counter]
      const end = newCoord[counter + 1]
      point.features[0].geometry.coordinates = start

      point.features[0].properties.bearing = turf.bearing(
        turf.point(start),
        turf.point(end)
      )

      map.getSource('point').setData(point)
      if (counter < steps - 2) {
        requestAnimationFrame(animate)
      }

      counter = counter + 1
    }

    setTimeout(() => {
      animate()
    }, 2000)

    function lineMore(from, to, distance, splitLength) {
      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)
        rings.push(pnt.geometry.coordinates)
      }
      if (leftLength > 0) {
        rings.push(to.geometry.coordinates)
      }
      return rings
    }
  </script>

</body>

</html>