原文链接及内容

效果如下视频所示:

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
const viewer = new Cesium.Viewer("cesiumContainer", {
geocoder: false,
sceneModePicker: false,
homeButton: false,
navigationHelpButton: false,
navigationInstructionsInitiallyVisible: false,
fullscreenButton: false,
selectionIndicator: false,
skyBox: false,
timeline: true,
animation: false,
shouldAnimate: true,
baseLayerPicker: false,
});
viewer.cesiumWidget.creditContainer.style.display = "none";

//定义了模型运行的时间窗口:从2018年11月12日15:00开始,持续30秒。
const start = Cesium.JulianDate.fromDate(new Date(2018, 11, 12, 15));
const totalSeconds = 30;
const stop = Cesium.JulianDate.addSeconds(
start,
totalSeconds,
new Cesium.JulianDate()
);
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
/**
* ClockRange.LOOP_STOP:前进方向不同,则含义不同:
* - 正向运行:时间从 startTime 增加到 stopTime,到达 stopTime 后,currentTime 跳回 startTime,形成循环。
* - 倒向运行:时间从 stopTime 减少到 startTime,到达 startTime 后停止,不再继续倒退。
*/
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
viewer.timeline.zoomTo(start, stop);//调整时间轴 UI,聚焦于指定时间段

// 通过在两个位置之间进行线性插值来为模型创建一条路径。
const position = new Cesium.SampledPositionProperty();
const distance = new Cesium.SampledProperty(Number);
const startPosition = new Cesium.Cartesian3(
-2379556.799372864,
-4665528.205030263,
3628013.106599678
);
const endPosition = new Cesium.Cartesian3(
-2379603.7074103747,
-4665623.48990283,
3627860.82704567
);
// 速度矢量属性(velocity vector property)将给出实体在任何给定时间的速度和方向。
const velocityVectorProperty = new Cesium.VelocityVectorProperty(
position,
false
);
const velocityVector = new Cesium.Cartesian3();

const numberOfSamples = 100;
let prevLocation = startPosition;
let totalDistance = 0;
for (let i = 0; i <= numberOfSamples; ++i) {
const factor = i / numberOfSamples;
const time = Cesium.JulianDate.addSeconds(
start,
factor * totalSeconds,
new Cesium.JulianDate()
);

/**
* lerp虽然是线性插值,但是由于使用的是非线性因子(factor),因此模型能进行加速。
*/
const locationFactor = Math.pow(factor, 2);
const location = Cesium.Cartesian3.lerp(
startPosition,
endPosition,
locationFactor,
new Cesium.Cartesian3()
);
position.addSample(time, location);
distance.addSample(
time,
(totalDistance += Cesium.Cartesian3.distance(location, prevLocation))
);
prevLocation = location;
}

function updateSpeedLabel(time, result) {
velocityVectorProperty.getValue(time, velocityVector);
const metersPerSecond = Cesium.Cartesian3.magnitude(velocityVector);
const kmPerHour = Math.round(metersPerSecond * 3.6);

return `${kmPerHour} km/hr`;
}

// 添加模型
try {
const modelPrimitive = viewer.scene.primitives.add(
await Cesium.Model.fromGltfAsync({
url: "../SampleData/models/CesiumMan/Cesium_Man.glb",
scale: 4,
})
);

//动画控制
modelPrimitive.readyEvent.addEventListener(() => {
modelPrimitive.activeAnimations.addAll({
loop: Cesium.ModelAnimationLoop.REPEAT,
animationTime: function (duration) {
return distance.getValue(viewer.clock.currentTime) / duration;
},
multiplier: 0.25,
});
});

//控制模型的面向方向
const rotation = new Cesium.Matrix3();
viewer.scene.preUpdate.addEventListener(function () {
const time = viewer.clock.currentTime;
const pos = position.getValue(time);
const vel = velocityVectorProperty.getValue(time);
Cesium.Cartesian3.normalize(vel, vel);
Cesium.Transforms.rotationMatrixFromPositionVelocity(
pos,
vel,
viewer.scene.globe.ellipsoid,
rotation
);
Cesium.Matrix4.fromRotationTranslation(
rotation,
pos,
modelPrimitive.modelMatrix
);
});
} catch (error) {
window.alert(error);
}

const modelLabel = viewer.entities.add({
position: position,
//自动将模型的方向设置为其所面向的方向。
orientation: new Cesium.VelocityOrientationProperty(position),
label: {
text: new Cesium.CallbackProperty(updateSpeedLabel, false),//实时更新速度标签
font: "20px sans-serif",
showBackground: true,
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 100.0),
eyeOffset: new Cesium.Cartesian3(0, 7.2, 0),
},
});
viewer.trackedEntity = modelLabel;
modelLabel.viewFrom = new Cesium.Cartesian3(-30.0, -10.0, 10.0);