准备工作
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>