轨迹运动的核心是不断变动marker的坐标。
最终效果:
主要参考了 Mapbox实现动态轨迹_mapbox 轨迹_二五25的博客-CSDN博客
mapbox轨迹动画效果_mapbox动画_Chaoying.的博客-CSDN博客
但是我们这里的需求有变化。使用turf.along和turf.lineChunk出来的数据,只包含坐标点.
不包含其他信息。需要携带其他的信息就没有办法。比如起点或者终点在室内,那么就办法设置楼层。
所以这里要对数组做处理。
数据处理一:将后台返回的数据处理成我们想要的格式
我这里请求路线返回的数据长这样。可以看出返回的数据结构不符合turf.lineString的要求。
处理数据,将所有的需要的数据,室内楼层,偏转角度,每段路线的终点,每段路线之间的距离通通通过handleRouteData函数处理拿到。
主要代码为:
function handleRouteData(route) { // 处理数据 返回线数据以及所以点集合
let pointCollects = []
for (let i = 0; i < route.length; i++) {
pointCollects.push({
"properties": {
"indoor": route[i].indoor,
"floor": route[i].startFloor
},
'geometry': route[i].geometry
});
let str = route[i].geometry.coordinates.join(',').split(',')
str = str.map(j => Number(j))
console.log("str", str)
let totalPoint = []
for (let i = 0; i < str.length; i++) {
if (i % 2 === 0) {
totalPoint.push([str[i], str[i + 1]])
}
}
let start = turf.point(totalPoint[0])
let end = turf.point(totalPoint[totalPoint.length - 1])
let bearing = turf.bearing(start, end)
if (i === route.length - 1) {
lastPoint = totalPoint[totalPoint.length - 1]
}
console.log("totalPoint", totalPoint)
splitLine.push(turf.lineString(totalPoint))
splitDis.push(turf.length(splitLine[i], { units: 'meters' }));
totalFloor.push(route[i].startFloor)
totalBearing.push(bearing)
totalIndoor.push(route[i].indoor)
}
return {
pointCollects, // 线数据
splitLine, // 每一段路线的线信息
splitDis, // 每一段路线的距离
totalFloor, // 每一段路线所在楼层数
totalBearing, // 每一段路线的偏移角度
totalIndoor, // 每一段路线是否在室内
lastPoint // 每一段路线的终点
}
}
数据处理二:将上一步处理好的数据,整合成数组。
主要代码是:
function dealData(speed) {
let anverageLine = []
for (let i = 0; i < res.splitDis.length; i++) {
let along = null
if (res.totalIndoor[i]) {
// 如果这一度在室内 那么就多分几个点吧--因为层级的原因
along = turf.lineChunk(res.splitLine[i], (5 * speed) * 0.4, { units: 'meters' });
} else {
along = turf.lineChunk(res.splitLine[i], 5 * speed, { units: 'meters' });
}
console.log(along);
along.features.map(j => {
j.geometry.coordinates.map(k => {
anverageLine.push([k, res.totalIndoor[i], res.totalFloor[i], res.totalBearing[i]])
})
})
if (i === res.splitDis.length - 1) {
anverageLine.push([lastPoint, res.totalIndoor[i], res.totalFloor[i], res.totalBearing[i]])
}
}
return anverageLine
}
这里的思路是,根据距离将线切割成N个点,因为每次切割的点不包括这段路的终点。所以这里必须要手动加入路线终点。不然marker运动的时候,无法走到路程尽头。
这里的anverageLine就是我们需要marker移动所需要的所有的信息。
marker移动速度的快慢就是通过speed的大小决定,speed越大,就表明这一段路线分割成的点就越少。运动速度就越快
室内层级比室外层级更大,marker移动肉眼可见变得快一点,猜测是近大远小的原理吧。所以室内的点分的更多一点。至于慢多少可以由自己决定,这里是0.4.
最后开启动画,使用requestAnimationFrame,让marker动起来。
主要代码是
var requestId;
function loop(speed) {
requestId = undefined;
let anverageLine = dealData(speed);
map.easeTo({
center: anverageLine[step][0],
zoom: 17,
duration: 50,
})
if (anverageLine[step][1]) {
map.setLevel(anverageLine[step][2])
map.easeTo({
center: anverageLine[step][0],
zoom: 19,
})
}
step = step + 1;
if (step === anverageLine.length - 1) {
requestId = undefined;
step = 0
return
}
go(speed);
marker.setLngLat(anverageLine[step][0])
}
function go(speed) {
if (!requestId) {
requestId = window.requestAnimationFrame(() => loop(1));
}
}
至此 大功告成