-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
Copy pathClock.js
313 lines (280 loc) · 12 KB
/
Clock.js
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
define([
'./ClockRange',
'./ClockStep',
'./defaultValue',
'./defined',
'./defineProperties',
'./DeveloperError',
'./Event',
'./getTimestamp',
'./JulianDate'
], function(
ClockRange,
ClockStep,
defaultValue,
defined,
defineProperties,
DeveloperError,
Event,
getTimestamp,
JulianDate) {
'use strict';
/**
* A simple clock for keeping track of simulated time.
*
* @alias Clock
* @constructor
*
* @param {Object} [options] Object with the following properties:
* @param {JulianDate} [options.startTime] The start time of the clock.
* @param {JulianDate} [options.stopTime] The stop time of the clock.
* @param {JulianDate} [options.currentTime] The current time.
* @param {Number} [options.multiplier=1.0] Determines how much time advances when {@link Clock#tick} is called, negative values allow for advancing backwards.
* @param {ClockStep} [options.clockStep=ClockStep.SYSTEM_CLOCK_MULTIPLIER] Determines if calls to {@link Clock#tick} are frame dependent or system clock dependent.
* @param {ClockRange} [options.clockRange=ClockRange.UNBOUNDED] Determines how the clock should behave when {@link Clock#startTime} or {@link Clock#stopTime} is reached.
* @param {Boolean} [options.canAnimate=true] Indicates whether {@link Clock#tick} can advance time. This could be false if data is being buffered, for example. The clock will only tick when both {@link Clock#canAnimate} and {@link Clock#shouldAnimate} are true.
* @param {Boolean} [options.shouldAnimate=false] Indicates whether {@link Clock#tick} should attempt to advance time. The clock will only tick when both {@link Clock#canAnimate} and {@link Clock#shouldAnimate} are true.
*
* @exception {DeveloperError} startTime must come before stopTime.
*
*
* @example
* // Create a clock that loops on Christmas day 2013 and runs in real-time.
* var clock = new Cesium.Clock({
* startTime : Cesium.JulianDate.fromIso8601("2013-12-25"),
* currentTime : Cesium.JulianDate.fromIso8601("2013-12-25"),
* stopTime : Cesium.JulianDate.fromIso8601("2013-12-26"),
* clockRange : Cesium.ClockRange.LOOP_STOP,
* clockStep : Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER
* });
*
* @see ClockStep
* @see ClockRange
* @see JulianDate
*/
function Clock(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
var currentTime = options.currentTime;
var startTime = options.startTime;
var stopTime = options.stopTime;
if (!defined(currentTime)) {
// if not specified, current time is the start time,
// or if that is not specified, 1 day before the stop time,
// or if that is not specified, then now.
if (defined(startTime)) {
currentTime = JulianDate.clone(startTime);
} else if (defined(stopTime)) {
currentTime = JulianDate.addDays(stopTime, -1.0, new JulianDate());
} else {
currentTime = JulianDate.now();
}
} else {
currentTime = JulianDate.clone(currentTime);
}
if (!defined(startTime)) {
// if not specified, start time is the current time
// (as determined above)
startTime = JulianDate.clone(currentTime);
} else {
startTime = JulianDate.clone(startTime);
}
if (!defined(stopTime)) {
// if not specified, stop time is 1 day after the start time
// (as determined above)
stopTime = JulianDate.addDays(startTime, 1.0, new JulianDate());
} else {
stopTime = JulianDate.clone(stopTime);
}
//>>includeStart('debug', pragmas.debug);
if (JulianDate.greaterThan(startTime, stopTime)) {
throw new DeveloperError('startTime must come before stopTime.');
}
//>>includeEnd('debug');
/**
* The start time of the clock.
* @type {JulianDate}
*/
this.startTime = startTime;
/**
* The stop time of the clock.
* @type {JulianDate}
*/
this.stopTime = stopTime;
/**
* Determines how the clock should behave when
* {@link Clock#startTime} or {@link Clock#stopTime}
* is reached.
* @type {ClockRange}
* @default {@link ClockRange.UNBOUNDED}
*/
this.clockRange = defaultValue(options.clockRange, ClockRange.UNBOUNDED);
/**
* Indicates whether {@link Clock#tick} can advance time. This could be false if data is being buffered,
* for example. The clock will only advance time when both
* {@link Clock#canAnimate} and {@link Clock#shouldAnimate} are true.
* @type {Boolean}
* @default true
*/
this.canAnimate = defaultValue(options.canAnimate, true);
/**
* An {@link Event} that is fired whenever {@link Clock#tick} is called.
* @type {Event}
*/
this.onTick = new Event();
this._currentTime = undefined;
this._multiplier = undefined;
this._clockStep = undefined;
this._shouldAnimate = undefined;
this._lastSystemTime = getTimestamp();
// set values using the property setters to
// make values consistent.
this.currentTime = currentTime;
this.multiplier = defaultValue(options.multiplier, 1.0);
this.shouldAnimate = defaultValue(options.shouldAnimate, false);
this.clockStep = defaultValue(options.clockStep, ClockStep.SYSTEM_CLOCK_MULTIPLIER);
}
defineProperties(Clock.prototype, {
/**
* The current time.
* Changing this property will change
* {@link Clock#clockStep} from {@link ClockStep.SYSTEM_CLOCK} to
* {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}.
* @memberof Clock.prototype
* @type {JulianDate}
*/
currentTime : {
get : function() {
return this._currentTime;
},
set : function(value) {
if (JulianDate.equals(this._currentTime, value)) {
return;
}
if (this._clockStep === ClockStep.SYSTEM_CLOCK) {
this._clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
}
this._currentTime = value;
}
},
/**
* Gets or sets how much time advances when {@link Clock#tick} is called. Negative values allow for advancing backwards.
* If {@link Clock#clockStep} is set to {@link ClockStep.TICK_DEPENDENT}, this is the number of seconds to advance.
* If {@link Clock#clockStep} is set to {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}, this value is multiplied by the
* elapsed system time since the last call to {@link Clock#tick}.
* Changing this property will change
* {@link Clock#clockStep} from {@link ClockStep.SYSTEM_CLOCK} to
* {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}.
* @memberof Clock.prototype
* @type {Number}
* @default 1.0
*/
multiplier : {
get : function() {
return this._multiplier;
},
set : function(value) {
if (this._multiplier === value) {
return;
}
if (this._clockStep === ClockStep.SYSTEM_CLOCK) {
this._clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
}
this._multiplier = value;
}
},
/**
* Determines if calls to {@link Clock#tick} are frame dependent or system clock dependent.
* Changing this property to {@link ClockStep.SYSTEM_CLOCK} will set
* {@link Clock#multiplier} to 1.0, {@link Clock#shouldAnimate} to true, and
* {@link Clock#currentTime} to the current system clock time.
* @memberof Clock.prototype
* @type ClockStep
* @default {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}
*/
clockStep : {
get : function() {
return this._clockStep;
},
set : function(value) {
if (value === ClockStep.SYSTEM_CLOCK) {
this._multiplier = 1.0;
this._shouldAnimate = true;
this._currentTime = JulianDate.now();
}
this._clockStep = value;
}
},
/**
* Indicates whether {@link Clock#tick} should attempt to advance time.
* The clock will only advance time when both
* {@link Clock#canAnimate} and {@link Clock#shouldAnimate} are true.
* Changing this property will change
* {@link Clock#clockStep} from {@link ClockStep.SYSTEM_CLOCK} to
* {@link ClockStep.SYSTEM_CLOCK_MULTIPLIER}.
* @memberof Clock.prototype
* @type {Boolean}
* @default true
*/
shouldAnimate : {
get : function() {
return this._shouldAnimate;
},
set : function(value) {
if (this._shouldAnimate === value) {
return;
}
if (this._clockStep === ClockStep.SYSTEM_CLOCK) {
this._clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
}
this._shouldAnimate = value;
}
}
});
/**
* Advances the clock from the current time based on the current configuration options.
* tick should be called every frame, regardless of whether animation is taking place
* or not. To control animation, use the {@link Clock#shouldAnimate} property.
*
* @returns {JulianDate} The new value of the {@link Clock#currentTime} property.
*/
Clock.prototype.tick = function() {
var currentSystemTime = getTimestamp();
var currentTime = JulianDate.clone(this._currentTime);
if (this.canAnimate && this._shouldAnimate) {
var clockStep = this._clockStep;
if (clockStep === ClockStep.SYSTEM_CLOCK) {
currentTime = JulianDate.now(currentTime);
} else {
var multiplier = this._multiplier;
if (clockStep === ClockStep.TICK_DEPENDENT) {
currentTime = JulianDate.addSeconds(currentTime, multiplier, currentTime);
} else {
var milliseconds = currentSystemTime - this._lastSystemTime;
currentTime = JulianDate.addSeconds(currentTime, multiplier * (milliseconds / 1000.0), currentTime);
}
var clockRange = this.clockRange;
var startTime = this.startTime;
var stopTime = this.stopTime;
if (clockRange === ClockRange.CLAMPED) {
if (JulianDate.lessThan(currentTime, startTime)) {
currentTime = JulianDate.clone(startTime, currentTime);
} else if (JulianDate.greaterThan(currentTime, stopTime)) {
currentTime = JulianDate.clone(stopTime, currentTime);
}
} else if (clockRange === ClockRange.LOOP_STOP) {
if (JulianDate.lessThan(currentTime, startTime)) {
currentTime = JulianDate.clone(startTime, currentTime);
}
while (JulianDate.greaterThan(currentTime, stopTime)) {
currentTime = JulianDate.addSeconds(startTime, JulianDate.secondsDifference(currentTime, stopTime), currentTime);
}
}
}
}
this._currentTime = currentTime;
this._lastSystemTime = currentSystemTime;
this.onTick.raiseEvent(this);
return currentTime;
};
return Clock;
});