实现思路
创建一个marker,用n记录次数
用turf工具库计算路线每帧要走的点数组、相对正北的旋转角度数组
requestAnimation更新n,移动marker到数组的第n项并设置其旋转角度
计算点数组、旋转角度数组
主要用到turf计算两点距离和向北的偏转角度
// data:LineString的geojson数据
// v:速度,m/s
// t:轮询间隔,s
function createPath(data, v = 30, t = 5) {
// 因为这里data我用的是LineString类型,所以数组这样取,实际上找到连续的点位二维数组即可
const lineArray = data.features[0].geometry.coordinates;
// 存储所有算出来的点(每隔t要移动的点位数组)
const allPath = [];
for (let i = 0; i < lineArray.length - 1; i++) {
const pre = lineArray[i];
const next = lineArray[i + 1];
// 计算距离,也可以用地图自带的工具
const dis = turf.distance(pre, next)*1000;
const time = dis / v;
const n = parseInt(time / t);
// next最多到lineArray倒数第1位
const ary = cutLine(pre, next, n);
// 将分隔出来的点合并保存
allPath.push(...ary);
}
// 将最后一个点手动加到末尾
allPath.push(lineArray[lineArray.length - 1]);
// 存储要旋转的角度数组(每隔t要旋转的角度)
const res = [];
for (let i = 0; i < allPath.length - 1; i++) {
const pre = allPath[i];
const next = allPath[i + 1];
// 计算2点与正北的夹角
res.push(turf.rhumbBearing(turf.point(pre), turf.point(next)));
}
return { allPath, allRotate: res };
}
// 将一条线段分成n段,返回所有的点的二维数组(不包括最后一个)
function cutLine(p1, p2, n) {
const x1 = p1[0],
x2 = p2[0],
y1 = p1[1],
y2 = p2[1];
const ary = [];
// 这里并没有放p2
for (let i = 0; i < n; i++) {
ary.push([x1 + ((x2 - x1) / n) * i, y1 + ((y2 - y1) / n) * i]);
}
return ary;
}
更新动画
let timer =null // requestAnimation
let marker = null // 点位,这里用真实dom
let ary= [] // 转换后的位置数组
let rotateAry=[] //转换的角度数组
let length =0 // 记录转换后的数组长度
let n = 0 // 记录当前循环到第几个点
// 地图加载后初始化一个marker
// 这里请自行查阅相关地图方法手写
map.on('load',()=>{
//marker = initMarker()
// 用上面的方法生成地图,这里的时间按60帧的时间取16.7ms,也可以写个方法计算下帧间隔
const { allPath, allRotate } = createPath(lineData, 30, 16.7/1000);
ary = allPath;
rotateAry = allRotate;
length = ary.length;
// 初始化定时器
timer = requestAnimationFrame(updatePoint);
})
//
// 更新动画
updatePoint() {
if (n < length) {
console.log(n);
// 更新marker位置和角度
marker.setLngLat(ary[n]);
marker.setRotation(rotateAry[n]);
n = n + 1;
//再次回调
updatePoint()
}
}
//
其他说明
- 之所以用marker去移动位置,而不是用canvas重新绘制,是因为计算出来的数组可能很长,移动dom反而能省去很多GPU渲染的消耗,其实这个计算本身并不耗时
- requestAnimationFrame的机制就是浏览器后台时不会运行,所以,如果想保持后台运行请用setTimeout或setInterval代替,内存会占用稍多点,渲染间隔不宜过长,适合模拟1~3秒上报一次位置的情景
- 计算2点距离turfjs.fenxianglu.cn/category/me…
- 计算2点恒向线夹角turfjs.fenxianglu.cn/category/me…
- 类似效果参考高德lbs.amap.com/demo/jsapi-…