一、概念
- 只要你做地图相关开发,一定会在工作中遇到需要轨迹回放的情况。
- so,什么是轨迹回放?我的理解:把一个物体在一个时间段内移动过的路径绘制出来,并且还原这个物体沿轨迹移动的动画,就是轨迹回放。
二、思路
(一)首先得有一个路径
- 路径就按坐标点依次绘制就行,但是会涉及到一个问题,就是如果传进来的路径空隙太大,会出现模型在两个点之间瞬移的现象,所以要对路径进行插值处理。
- 在这里有一个插件gsap:是一个从flash时代一直发展到今天的专业动画库。速度快。GSAP专门优化了动画性能,使之实现和CSS一样的高性能动画效果。轻量与模块化。模块化与插件式的结构保持了核心引擎的轻量,TweenLite包非常小(基本上低于7kb)。GSAP提供了TweenLite, TimelineLite, TimelineMax 和 TweenMax不同功能的动画模块,你可以按需使用。没有依赖。灵活控制。不用受限于线性序列,可以重叠动画序列,你可以通过精确时间控制,灵活地使用最少的代码实现动画。
(二)动起来
- cesium 中实现动画必须用到时间轴,物体的状态与时间联动就能实现动画效果。
三、实现
-
创建时间轴 --> 创建实体 --> 在实体中添加定时器、位置、模型、轨迹路线 --> 开启时钟并把视野跟随到模型上
-
以下是一段项目中实现轨迹回放的真实代码
// 仿真初始化
const initSimulation = simulationData => {
const start = Cesium.JulianDate.fromDate(new Date(simulationData.startTime)); //开始时间
const stop = Cesium.JulianDate.fromDate(new Date(simulationData.endTime)); //结束时间
viewer.clock.startTime = start.clone(); //设置cesium时钟开始时间
viewer.clock.stopTime = stop.clone(); //设置cesium时钟结束时间
viewer.timeline.zoomTo(start, stop); //设置时间轴的起止时间
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //设置播放类型为循环播放
const position = computeFlight(simulationData, start); //使用差值算法计算路径所需要的动画时长
//创建一个新的实体
entity = viewer.entities.add({
//定时器集合
availability: new Cesium.TimeIntervalCollection([
//把刚刚设置的开始结束时间传进来
new Cesium.TimeInterval({
start,
stop,
}),
]),
position, //把刚刚差值算法计算的结果传进来
orientation: new Cesium.VelocityOrientationProperty(position), //自动计算角度
//导入模型
model: {
uri: './libs/models/crazyflie.glb', //模型路径
scale: 1, //缩放比例
minimumPixelSize: 90, //模型缩小到多少像素后,不再能被缩小
},
//绘制轨迹
path: {
resolution: 1,//将路径显示为以1秒为增量采样的路径线
//设置材质
material: new Cesium.PolylineGlowMaterialProperty({
glowPower: 1,
color: Cesium.Color.YELLOW,
}),
width: 10,//设置宽度
},
});
viewer.clock.shouldAnimate = true;//开启时钟
viewer.trackedEntity = entity;//视角会锁定到设定目标实体
};
//差值算法(类似 threejs 或者其他地方使用 gsgp )
const computeFlight = (simulationData, start) => {
const property = new Cesium.SampledPositionProperty();
simulationData.routes.forEach((item, i) => {
const time = Cesium.JulianDate.addSeconds(start, i * 5, new Cesium.JulianDate());
const position = Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, 50);
property.addSample(time, position);
});
return property;
};