路径回放
import * as turf from '@turf/turf'
export default class RouteReplay {
/**
*
* @param {*} map mapbox实例对象
* @param {*} routejson 路径geojson type = lineString
* @param {*} nsteps nsteps type = number
* @param {*} realRouteLayerId 线条realRouteLayerId type = string
* @param {*} animatePointLayerId animatePointLayerId type = string
* @param {*} width 线条width type = number
* @param {*} opacity 线条opacity type = number
* @param {*} color 线条color type = string
*/
map: any
json: any
realRouteId: string
animatePointId: string
animated: boolean
counter: number
steps: number
nsteps: number
newRouteGeoJson: any
timer: any
layerList: Array
width: number
opacity: number
color: string
finish: boolean
constructor(map: any,
routejson: {
type: string;
features: {
type: string;
geometry: {
type: string;
coordinates: number[][]
}
}[] | {
type: string;
geometry: {
type: string;
coordinates: number[][]
}
}[] },
nsteps: number,
realRouteLayerId: string,
animatePointLayerId: string,
width: {
type: number;
default: 5
},
opacity: {
type: number,
default: 1
},
color: {
type: string,
default: 'rgba(0,255,255,1)'
}) {
this.map = map
this.json = routejson
this.realRouteId = realRouteLayerId
this.animatePointId = animatePointLayerId
this.animated = false
this.counter = 0
this.steps = 0
this.nsteps = nsteps
this.newRouteGeoJson = null
this.timer = null
this.layerList = []
this.width = width
this.opacity = opacity
this.color = color
this.finish = false
// 进中的路线
this.realRouteGeoJson = {
'type': 'FeatureCollection',
'features': [{
'type': 'Feature',
'geometry': {
'type': 'LineString',
'coordinates': []
}
}]
}
// 实时点
this.animatePointGeoJson = {
'type': 'FeatureCollection',
'features': [{
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Point',
'coordinates': []
}
}]
}
this.init()
}
init() {
// eslint-disable-next-line prefer-destructuring
this.animatePointGeoJson.features[0].geometry.coordinates = this.json.features[0].geometry.coordinates[0]
// 轨迹点json
this.newRouteGeoJson = this.resetRoute(this.json.features[0], this.nsteps, 'kilometers')
// 轨迹点json的点数量
this.steps = this.newRouteGeoJson.geometry.coordinates.length
this.addRealRouteSource(this.realRouteId) // 添加实时轨迹线图层
this.addAnimatePointSource(this.animatePointId) // 添加动态点图层
this.layerList.push(`realRouteLayer${this.realRouteId}`, `animatePointLayer${this.animatePointId}`,)
}
animate() {
this.finish = false
if (this.counter >= this.steps) {
this.finish = true
return
}
let startPnt
let 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]
} else if (this.counter !== 0) {
startPnt = this.newRouteGeoJson.geometry.coordinates[this.counter - 1]
endPnt = this.newRouteGeoJson.geometry.coordinates[this.counter]
}
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)
// 已经走过的轨迹更新
this.map.getSource(`realRouteLayer${this.realRouteId}`).setData(this.realRouteGeoJson)
if (this.animated) {
this.timer = requestAnimationFrame(() => { this.animate() })
}
// eslint-disable-next-line no-plusplus
this.counter++
}
addRealRouteSource(layerId) {
this.map.addLayer({
'id': `realRouteLayer${layerId}`,
'type': 'line',
'source': {
'type': 'geojson',
'lineMetrics': true,
'data': this.realRouteGeoJson
},
'paint': {
'line-width': this.width,
'line-opacity': this.opacity,
'line-color': this.color,
}
})
}
// 添加动态点图层
addAnimatePointSource(layerId) {
this.map.addLayer({
'id': `animatePointLayer${layerId}`,
'type': 'symbol',
'source': {
'type': 'geojson',
'data': this.animatePointGeoJson
},
// 'layout': {
// 'icon-image': '',
// 'icon-size': 0,
// 'icon-rotate': ['get', 'bearing'],
// 'icon-rotation-alignment': 'map',
// 'icon-allow-overlap': true,
// 'icon-ignore-placement': true
// }
})
}
resetRoute(route, nstep, units) {
const newroute = {
'type': 'Feature',
'geometry': {
'type': 'LineString',
'coordinates': []
}
}
// 指定点集合的总路长
const lineDistance = turf.lineDistance(route)
// 每一段的平均距离
const nDistance = lineDistance / nstep
const {length} = this.json.features[0].geometry.coordinates
// eslint-disable-next-line no-plusplus
for (let i = 0; i < length - 1; i++) {
let from = turf.point(route.geometry.coordinates[i]) // type 为 point的feature
let 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 = this.splitLine(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
}
// 过长的两点轨迹点分段
// eslint-disable-next-line class-methods-use-this
splitLine(from, to, distance, splitLength, units) {
var step = parseInt(distance / splitLength, 10)
const leftLength = distance - step * splitLength
const rings = []
const route = turf.lineString([from.geometry.coordinates, to.geometry.coordinates])
// eslint-disable-next-line no-plusplus
for (let i = 1; i <= step; i++) {
let nlength = i * splitLength
// turf.alone返回沿着route<LineString>距离为nlength<number>的点
let pnt = turf.along(route, nlength, {
units: units
});
rings.push(pnt.geometry.coordinates)
}
if (leftLength > 0) {
rings.push(to.geometry.coordinates)
}
return rings
}
start() {
if (!this.animated) {
this.animated = true
this.animate()
}
}
pause() {
this.animated = false
this.animate()
}
end() {
window.cancelAnimationFrame(this.timer)
this.animated = false
this.counter = 0
this.animate()
}
remove() {
window.cancelAnimationFrame(this.timer)
// eslint-disable-next-line array-callback-return
this.layerList.map(layer => {
// console.log(layer)
if (this.map.getSource(layer)) {
this.map.removeLayer(layer)
this.map.removeSource(layer)
}
})
}
finished(){
return this.finish
}
}
使用
new RouteReplay(map对象, 数据, 50, `${index}`, `${index}`, 5,1,'rgba(0,255,255,1)')