Vue中使用mapBox完成轨迹回放

准备工作

1、在项目中安装相关依赖: npm i mapbox-gl -S npm install @turf/turf

2、下面只是一些实现步骤,有需要的朋友们可以自己套来实现一下功能(不喜勿喷,谢谢)

3、 我也是借鉴别人的,源码在这

代码如下

<template>
  <div id="mapBox" style="width:100% ; height: 100%"></div>
</template>

<script>
import { getTrack } from '@/api/device'
import mapboxgl from 'mapbox-gl'
import 'mapbox-gl/dist/mapbox-gl.css'
import { lineDistance, distance, bearing, along, lineString, point } from '@turf/turf'
export default {
  data() {
    return {
      counter: 0,
      steps: 0,
      isPlay: true,
      aLength: '',
      realRouteGeoJson: '',
      newRouteGeoJson: '',
      animatePointGeoJson: '',
      layers: [],
      sources: [],
      images: []
    }
  },
  mounted() {
    this.loadMap()
  },
  methods: {
    loadMap() {
      mapboxgl.accessToken = '你的token'
      var map = new mapboxgl.Map({
        container: document.getElementById('mapBox'), // 容器必须有明确的宽和高
        style: 'mapbox://styles/mapbox/streets-v9',
        center: [116.478935, 39.997761],
        zoom: 6
      })
      this.map = map
      var nav = new mapboxgl.NavigationControl()
      this.map.addControl(nav, 'bottom-right')
    },
    async getTrack() {
      const res = await getTrack({
        // 参数
      })
      var linerArr = []
      var startPoint = '你的起点坐标'
      //  参数处理得到linerArr

      this.startAnimation(linerArr, startPoint) // 调用startAnimation 开始图层构建
    },

    startAnimation(linerArr, startPoint) {
      // 创建轨迹线
      var routeGeoJson = {
        'type': 'FeatureCollection',
        'features': [{
          'type': 'Feature',
          'geometry': {
            'type': 'LineString',
            'coordinates': linerArr
          }
        }]
      }
      this.map.addLayer({ // 添加图层
        'id': 'routeLayer',
        'type': 'line',
        'source': {
          'type': 'geojson',
          'lineMetrics': true,
          'data': routeGeoJson
        },
        'paint': {
          'line-color': '#28F',
          'line-width': 10
        },
        'layout': {
          'line-join': 'round',
          'line-cap': 'round'
        }
      })
      this.layers.push('routeLayer') // 为清空地图的图层做准备

      // fit bounds for line
      const coordinates = routeGeoJson.features[0].geometry.coordinates
      if (coordinates) {
        const bounds = coordinates.reduce(function(bounds, coord) {
          return bounds.extend(coord)
        }, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]))

        this.map.fitBounds(bounds, {
          padding: 20
        })
      }

      this.addArrowIcon(linerArr, startPoint) // 添加箭头图层
      this.addPoint(startPoint) // 添加marker 图层
      this.addRealRouteSource() // 添加真实轨迹图层
      this.aLength = routeGeoJson.features[0].geometry.coordinates.length
      this.newRouteGeoJson = this.resetRoute(routeGeoJson.features[0], 1000, 'kilometers')
      this.steps = this.newRouteGeoJson.geometry.coordinates.length
      this.$nextTick(() => {
        this.animate()
      })
    },

    // 添加marker 图层, 即动点图层
    addPoint(startPoint) {
      this.animatePointGeoJson = {
        'type': 'FeatureCollection',
        'features': [{
          'type': 'Feature',
          'properties': {
          },
          'geometry': {
            'type': 'Point',
            'coordinates': startPoint
          }
        }]
      }
      var that = this
      this.map.loadImage(require('@/assets/marker.png'), function(error, image) {
        if (error) throw error
        that.map.addImage('marker', image)
        that.images.push('marker')
        that.map.addLayer({
          'id': 'animatePointLayer',
          'source': {
            'type': 'geojson',
            'data': that.animatePointGeoJson
          },
          'type': 'symbol',
          'layout': {
            'icon-image': 'marker',
            'icon-size': 0.2,
            'icon-rotation-alignment': 'map',
            'icon-allow-overlap': true,
            'icon-ignore-placement': true,
            'icon-offset': [-15, -50]

          }
        })
        that.layers.push('animatePointLayer')
      })
    },

    // 添加箭头图层
    addArrowIcon(linerArr) {
      var that = this
      var arrow = {
        'type': 'FeatureCollection',
        'features': [{
          'type': 'Feature',
          'geometry': {
            'type': 'LineString',
            'coordinates': linerArr
          }
        }]
      }
      this.map.loadImage(require('@/assets/arrow.png'), function(error, image) {
        if (error) throw error
        that.map.addImage('arrow', image)
        that.images.push('arrow')
        that.map.addLayer({
          'id': 'arrowLayer',
          'type': 'symbol',
          'source': {
            'type': 'geojson',
            'data': arrow // 轨迹geojson格式数据
          },
          'layout': {
            'symbol-placement': 'line',
            'symbol-spacing': 1, // 图标间隔,默认为250
            'icon-image': 'arrow', // 箭头图标
            'icon-size': 0.06
          }
        })
        that.layers.push('arrowLayer')
      })
    },

    resetRoute(route, nstep, units) {
      try {
        var newroute = {
          'type': 'Feature',
          'geometry': {
            'type': 'LineString',
            'coordinates': []
          }
        }
        var lineDistance1 = lineDistance(route)
        var nDistance = lineDistance1 / nstep
        for (let i = 0; i < this.aLength - 1; i++) {
          var from = point(route.geometry.coordinates[i])
          var to = point(route.geometry.coordinates[i + 1])
          const lDistance = distance(from, to, units)
          if (i === 0) {
            newroute.geometry.coordinates.push(route.geometry.coordinates[0])
          }
          if (lDistance > nDistance) {
            const rings = this.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
      } catch (e) {
        console.log(e)
      }
    },

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

    // 添加真实轨迹图层,即实时轨迹线
    addRealRouteSource() {
      this.realRouteGeoJson = {
        'type': 'FeatureCollection',
        'features': [{
          'type': 'Feature',
          'geometry': {
            'type': 'LineString',
            'coordinates': []
          }
        }]
      }
      this.map.addLayer({
        'id': 'realRouteLayer',
        'type': 'line',
        'source': {
          'type': 'geojson',
          'lineMetrics': true,
          'data': this.realRouteGeoJson
        },
        'paint': {
          'line-width': 10,
          'line-color': '#00838f'
        },
        'layout': {
          'line-join': 'round',
          'line-cap': 'round'
        }
      })
      this.layers.push('realRouteLayer')
    },

    // 运动函数
    animate() {
      if (this.counter >= this.steps) {
        this.searchStatus = false
        return
      }
      var startPnt, endPnt
      if (this.counter === 0) {
        this.realRouteGeoJson.features[0].geometry.coordinates = []
        startPnt = this.newRouteGeoJson.geometry.coordinates[this.counter]
        endPnt = this.newRouteGeoJson.geometry.coordinates[this.counter + 1]
      } else if (this.counter !== 0) {
        startPnt = this.newRouteGeoJson.geometry.coordinates[this.counter - 1]
        endPnt = this.newRouteGeoJson.geometry.coordinates[this.counter]
      }

      this.animatePointGeoJson.features[0].properties.bearing = bearing(
        point(startPnt),
        point(endPnt)
      ) - 90
      this.animatePointGeoJson.features[0].geometry.coordinates = this.newRouteGeoJson.geometry.coordinates[this.counter]
      this.realRouteGeoJson.features[0].geometry.coordinates.push(this.animatePointGeoJson.features[0].geometry.coordinates)
      if (this.map.getSource('animatePointLayer')) this.map.getSource('animatePointLayer').setData(this.animatePointGeoJson)
      if (this.map.getSource('realRouteLayer')) this.map.getSource('realRouteLayer').setData(this.realRouteGeoJson)
      if (this.isPlay) {
        requestAnimationFrame(this.animate)
      }
      this.counter = this.counter + 1
    },

    // 清空地图图层 有需要可以用
    clearMap() {
      this.sources = this.layers
      this.layers.forEach(item => {
        this.map.removeLayer(item)
      })
      this.sources.forEach(item => {
        this.map.removeSource(item)
      })

      this.images.forEach(item => {
        this.map.removeImage(item)
      })
      // 清空数据
      this.layers = []
      this.sources = []
      this.images = []
    }
  }
}
</script>

<style>

</style>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容