diff --git a/CHANGES.md b/CHANGES.md index 465e85390cc7..21af77015935 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Change Log * Fix some large polygon triangulations. [#2788](https://github.com/AnalyticalGraphicsInc/cesium/issues/2788) * Improved performance and accuracy of polygon triangulation by using the [earcut](https://github.com/mapbox/earcut) library. Loading a GeoJSON with polygons for each country was 2x faster. * Added CZML support for Box, Corridor and Cylinder +* `Clock` now keeps its configuration settings self-consistent. Previously, this was done by `AnimationViewModel` and could become inconsistent in certain cases. [#4007](https://github.com/AnalyticalGraphicsInc/cesium/pull/4007) ### 1.22 - 2016-06-01 diff --git a/Source/Core/Clock.js b/Source/Core/Clock.js index a7a67672b213..f310104c5440 100644 --- a/Source/Core/Clock.js +++ b/Source/Core/Clock.js @@ -4,6 +4,7 @@ define([ './ClockStep', './defaultValue', './defined', + './defineProperties', './DeveloperError', './Event', './getTimestamp', @@ -13,6 +14,7 @@ define([ ClockStep, defaultValue, defined, + defineProperties, DeveloperError, Event, getTimestamp, @@ -29,11 +31,11 @@ define([ * @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 tick is called, negative values allow for advancing backwards. - * @param {ClockStep} [options.clockStep=ClockStep.SYSTEM_CLOCK_MULTIPLIER] Determines if calls to tick are frame dependent or system clock dependent. - * @param {ClockRange} [options.clockRange=ClockRange.UNBOUNDED] Determines how the clock should behave when startTime or stopTime is reached. - * @param {Boolean} [options.canAnimate=true] Indicates whether tick can advance time. This could be false if data is being buffered, for example. The clock will only tick when both canAnimate and shouldAnimate are true. - * @param {Boolean} [options.shouldAnimate=true] Indicates whether tick should attempt to advance time. The clock will only tick when both canAnimate and shouldAnimate are true. + * @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=true] 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. * @@ -47,7 +49,7 @@ define([ * clockRange : Cesium.ClockRange.LOOP_STOP, * clockStep : Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER * }); - * + * * @see ClockStep * @see ClockRange * @see JulianDate @@ -55,34 +57,39 @@ define([ function Clock(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); + var currentTime = options.currentTime; var startTime = options.startTime; - var startTimeUndefined = !defined(startTime); - var stopTime = options.stopTime; - var stopTimeUndefined = !defined(stopTime); - var currentTime = options.currentTime; - var currentTimeUndefined = !defined(currentTime); + 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 (startTimeUndefined && stopTimeUndefined && currentTimeUndefined) { - currentTime = JulianDate.now(); - startTime = JulianDate.clone(currentTime); - stopTime = JulianDate.addDays(currentTime, 1.0, new JulianDate()); - } else if (startTimeUndefined && stopTimeUndefined) { + if (!defined(startTime)) { + // if not specified, start time is the current time + // (as determined above) startTime = JulianDate.clone(currentTime); - stopTime = JulianDate.addDays(currentTime, 1.0, new JulianDate()); - } else if (startTimeUndefined && currentTimeUndefined) { - startTime = JulianDate.addDays(stopTime, -1.0, new JulianDate()); - currentTime = JulianDate.clone(startTime); - } else if (currentTimeUndefined && stopTimeUndefined) { - currentTime = JulianDate.clone(startTime); + } 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 if (currentTimeUndefined) { - currentTime = JulianDate.clone(startTime); - } else if (stopTimeUndefined) { - stopTime = JulianDate.addDays(currentTime, 1.0, new JulianDate()); - } else if (startTimeUndefined) { - startTime = JulianDate.clone(currentTime); + } else { + stopTime = JulianDate.clone(stopTime); } //>>includeStart('debug', pragmas.debug); @@ -103,93 +110,190 @@ define([ */ 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.clockStep = defaultValue(options.clockStep, ClockStep.SYSTEM_CLOCK_MULTIPLIER); + this.shouldAnimate = defaultValue(options.shouldAnimate, true); + } + + 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} */ - this.currentTime = currentTime; + 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; + } + }, /** - * Determines how much time advances when tick is called, negative values allow for advancing backwards. - * If clockStep is set to ClockStep.TICK_DEPENDENT this is the number of seconds to advance. - * If clockStep is set to ClockStep.SYSTEM_CLOCK_MULTIPLIER this value is multiplied by the - * elapsed system time since the last call to tick. + * 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 */ - this.multiplier = defaultValue(options.multiplier, 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 tick are frame dependent or system clock dependent. + * 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} */ - this.clockStep = defaultValue(options.clockStep, 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(); + } - /** - * Determines how the clock should behave when startTime or stopTime is reached. - * @type {ClockRange} - * @default {@link ClockRange.UNBOUNDED} - */ - this.clockRange = defaultValue(options.clockRange, ClockRange.UNBOUNDED); + this._clockStep = value; + } + }, - /** - * Indicates whether tick can advance time. This could be false if data is being buffered, - * for example. The clock will only tick when both canAnimate and shouldAnimate are true. - * @type {Boolean} - * @default true - */ - this.canAnimate = defaultValue(options.canAnimate, true); /** - * Indicates whether tick should attempt to advance time. - * The clock will only tick when both canAnimate and shouldAnimate are true. + * 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 */ - this.shouldAnimate = defaultValue(options.shouldAnimate, true); + shouldAnimate : { + get : function() { + return this._shouldAnimate; + }, + set : function(value) { + if (this._shouldAnimate === value) { + return; + } - /** - * An {@link Event} that is fired whenever tick. - * @type {Event} - */ - this.onTick = new Event(); + if (this._clockStep === ClockStep.SYSTEM_CLOCK) { + this._clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER; + } - this._lastSystemTime = getTimestamp(); - } + this._shouldAnimate = value; + } + } + }); /** - * Advances the clock from the currentTime based on the current configuration options. + * 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 shouldAnimate property. + * or not. To control animation, use the {@link Clock#shouldAnimate} property. * - * @returns {JulianDate} The new value of the currentTime 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); - var startTime = this.startTime; - var stopTime = this.stopTime; - var multiplier = this.multiplier; + var currentTime = JulianDate.clone(this._currentTime); - if (this.canAnimate && this.shouldAnimate) { - if (this.clockStep === ClockStep.SYSTEM_CLOCK) { + if (this.canAnimate && this._shouldAnimate) { + var clockStep = this._clockStep; + if (clockStep === ClockStep.SYSTEM_CLOCK) { currentTime = JulianDate.now(currentTime); } else { - if (this.clockStep === ClockStep.TICK_DEPENDENT) { + 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); } - if (this.clockRange === ClockRange.CLAMPED) { + 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 (this.clockRange === ClockRange.LOOP_STOP) { + } else if (clockRange === ClockRange.LOOP_STOP) { if (JulianDate.lessThan(currentTime, startTime)) { currentTime = JulianDate.clone(startTime, currentTime); } @@ -200,7 +304,7 @@ define([ } } - this.currentTime = currentTime; + this._currentTime = currentTime; this._lastSystemTime = currentSystemTime; this.onTick.raiseEvent(this); return currentTime; diff --git a/Source/DataSources/DataSourceClock.js b/Source/DataSources/DataSourceClock.js index a9dc430fb1b6..454d8fe7b050 100644 --- a/Source/DataSources/DataSourceClock.js +++ b/Source/DataSources/DataSourceClock.js @@ -20,7 +20,8 @@ define([ 'use strict'; /** - * Represents CZML document-level clock settings. + * Represents desired clock settings for a particular {@link DataSource}. These settings may be applied + * to the {@link Clock} when the DataSource is loaded. * * @alias DataSourceClock * @constructor @@ -50,45 +51,48 @@ define([ }, /** - * Gets or sets the start time of the clock to use when looping or clamped. + * Gets or sets the desired start time of the clock. + * See {@link Clock#startTime}. * @memberof DataSourceClock.prototype * @type {JulianDate} */ startTime : createRawPropertyDescriptor('startTime'), /** - * Gets or sets the stop time of the clock to use when looping or clamped. + * Gets or sets the desired stop time of the clock. + * See {@link Clock#stopTime}. * @memberof DataSourceClock.prototype * @type {JulianDate} */ stopTime : createRawPropertyDescriptor('stopTime'), /** - * Gets or sets the initial time to use when switching to this clock. + * Gets or sets the desired current time when this data source is loaded. + * See {@link Clock#currentTime}. * @memberof DataSourceClock.prototype * @type {JulianDate} */ currentTime : createRawPropertyDescriptor('currentTime'), /** - * Gets or sets how the clock should behave when startTime or stopTime is reached. + * Gets or sets the desired clock range setting. + * See {@link Clock#clockRange}. * @memberof DataSourceClock.prototype * @type {ClockRange} */ clockRange : createRawPropertyDescriptor('clockRange'), /** - * Gets or sets if clock advancement is frame dependent or system clock dependent. + * Gets or sets the desired clock step setting. + * See {@link Clock#clockStep}. * @memberof DataSourceClock.prototype * @type {ClockStep} */ clockStep : createRawPropertyDescriptor('clockStep'), /** - * Gets or sets how much time advances with each tick, negative values allow for advancing backwards. - * If clockStep is set to ClockStep.TICK_DEPENDENT this is the number of seconds to advance. - * If clockStep is set to ClockStep.SYSTEM_CLOCK_MULTIPLIER this value is multiplied by the - * elapsed system time since the last call to tick. + * Gets or sets the desired clock multiplier. + * See {@link Clock#multiplier}. * @memberof DataSourceClock.prototype * @type {Number} */ @@ -163,10 +167,10 @@ define([ } result.startTime = this.startTime; result.stopTime = this.stopTime; + result.currentTime = this.currentTime; result.clockRange = this.clockRange; - result.clockStep = this.clockStep; result.multiplier = this.multiplier; - result.currentTime = this.currentTime; + result.clockStep = this.clockStep; return result; }; diff --git a/Source/Widgets/Animation/AnimationViewModel.js b/Source/Widgets/Animation/AnimationViewModel.js index 08b734d69b2e..6409bf9d9250 100644 --- a/Source/Widgets/Animation/AnimationViewModel.js +++ b/Source/Widgets/Animation/AnimationViewModel.js @@ -29,18 +29,6 @@ define([ var realtimeShuttleRingAngle = 15; var maxShuttleRingAngle = 105; - function cancelRealtime(clockViewModel) { - if (clockViewModel.clockStep === ClockStep.SYSTEM_CLOCK) { - clockViewModel.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER; - clockViewModel.multiplier = 1; - } - } - - function unpause(clockViewModel) { - cancelRealtime(clockViewModel); - clockViewModel.shouldAnimate = true; - } - function numberComparator(left, right) { return left - right; } @@ -284,10 +272,9 @@ define([ var pauseCommand = createCommand(function() { var clockViewModel = that._clockViewModel; if (clockViewModel.shouldAnimate) { - cancelRealtime(clockViewModel); clockViewModel.shouldAnimate = false; } else if (that._canAnimate) { - unpause(clockViewModel); + clockViewModel.shouldAnimate = true; } }); @@ -300,7 +287,6 @@ define([ var playReverseCommand = createCommand(function() { var clockViewModel = that._clockViewModel; - cancelRealtime(clockViewModel); var multiplier = clockViewModel.multiplier; if (multiplier > 0) { clockViewModel.multiplier = -multiplier; @@ -317,7 +303,6 @@ define([ var playForwardCommand = createCommand(function() { var clockViewModel = that._clockViewModel; - cancelRealtime(clockViewModel); var multiplier = clockViewModel.multiplier; if (multiplier < 0) { clockViewModel.multiplier = -multiplier; @@ -333,15 +318,12 @@ define([ }); var playRealtimeCommand = createCommand(function() { - var clockViewModel = that._clockViewModel; - clockViewModel.clockStep = ClockStep.SYSTEM_CLOCK; - clockViewModel.multiplier = 1.0; - clockViewModel.shouldAnimate = true; + that._clockViewModel.clockStep = ClockStep.SYSTEM_CLOCK; }, knockout.getObservable(this, '_isSystemTimeAvailable')); this._playRealtimeViewModel = new ToggleButtonViewModel(playRealtimeCommand, { toggled : knockout.computed(function() { - return clockViewModel.shouldAnimate && clockViewModel.clockStep === ClockStep.SYSTEM_CLOCK; + return clockViewModel.clockStep === ClockStep.SYSTEM_CLOCK; }), tooltip : knockout.computed(function() { return that._isSystemTimeAvailable ? 'Today (real-time)' : 'Current time not in range'; @@ -350,7 +332,6 @@ define([ this._slower = createCommand(function() { var clockViewModel = that._clockViewModel; - cancelRealtime(clockViewModel); var shuttleRingTicks = that._allShuttleRingTicks; var multiplier = clockViewModel.multiplier; var index = getTypicalMultiplierIndex(multiplier, shuttleRingTicks) - 1; @@ -361,7 +342,6 @@ define([ this._faster = createCommand(function() { var clockViewModel = that._clockViewModel; - cancelRealtime(clockViewModel); var shuttleRingTicks = that._allShuttleRingTicks; var multiplier = clockViewModel.multiplier; var index = getTypicalMultiplierIndex(multiplier, shuttleRingTicks) + 1; diff --git a/Source/Widgets/ClockViewModel.js b/Source/Widgets/ClockViewModel.js index fccea3e39686..96bd1cf9351e 100644 --- a/Source/Widgets/ClockViewModel.js +++ b/Source/Widgets/ClockViewModel.js @@ -35,168 +35,120 @@ define([ this._eventHelper = new EventHelper(); this._eventHelper.add(clock.onTick, this.synchronize, this); - var startTime = knockout.observable(clock.startTime); - startTime.equalityComparer = JulianDate.equals; - /** - * Gets the current system time. This property is observable. + * Gets the current system time. + * This property is observable. * @type {JulianDate} - * @default JulianDate() */ this.systemTime = knockout.observable(JulianDate.now()); this.systemTime.equalityComparer = JulianDate.equals; - knockout.track(this, ['systemTime']); - /** - * Gets or sets the start time of the clock. This property is observable. + * Gets or sets the start time of the clock. + * See {@link Clock#startTime}. + * This property is observable. * @type {JulianDate} - * @default undefined */ - this.startTime = undefined; - knockout.defineProperty(this, 'startTime', { - get : startTime, - set : function(value) { - startTime(value); - clock.startTime = value; - } - }); - - var stopTime = knockout.observable(clock.stopTime); - stopTime.equalityComparer = JulianDate.equals; + this.startTime = knockout.observable(clock.startTime); + this.startTime.equalityComparer = JulianDate.equals; + this.startTime.subscribe(function(value) { + clock.startTime = value; + this.synchronize(); + }, this); /** - * Gets or sets the stop time of the clock. This property is observable. + * Gets or sets the stop time of the clock. + * See {@link Clock#stopTime}. + * This property is observable. * @type {JulianDate} - * @default undefined */ - this.stopTime = undefined; - knockout.defineProperty(this, 'stopTime', { - get : stopTime, - set : function(value) { - clock.stopTime = value; - stopTime(value); - } - }); - - var currentTime = knockout.observable(clock.currentTime); - currentTime.equalityComparer = JulianDate.equals; + this.stopTime = knockout.observable(clock.stopTime); + this.stopTime.equalityComparer = JulianDate.equals; + this.stopTime.subscribe(function(value) { + clock.stopTime = value; + this.synchronize(); + }, this); /** - * Gets or sets the current time. This property is observable. + * Gets or sets the current time. + * See {@link Clock#currentTime}. + * This property is observable. * @type {JulianDate} - * @default undefined */ - this.currentTime = undefined; - knockout.defineProperty(this, 'currentTime', { - get : currentTime, - set : function(value) { - clock.currentTime = value; - currentTime(value); - } - }); + this.currentTime = knockout.observable(clock.currentTime); + this.currentTime.equalityComparer = JulianDate.equals; + this.currentTime.subscribe(function(value) { + clock.currentTime = value; + this.synchronize(); + }, this); - var multiplier = knockout.observable(clock.multiplier); /** - * Gets or sets how much time advances when tick is called, negative values allow for advancing backwards. - * If clockStep is set to ClockStep.TICK_DEPENDENT this is the number of seconds to advance. - * If clockStep is set to ClockStep.SYSTEM_CLOCK_MULTIPLIER this value is multiplied by the - * elapsed system time since the last call to tick. This property is observable. + * Gets or sets the clock multiplier. + * See {@link Clock#multiplier}. + * This property is observable. * @type {Number} - * @default undefined */ - this.multiplier = undefined; - knockout.defineProperty(this, 'multiplier', { - get : multiplier, - set : function(value) { - clock.multiplier = value; - multiplier(value); - } - }); - - var clockStep = knockout.observable(clock.clockStep); - clockStep.equalityComparer = function(a, b) { - return a === b; - }; + this.multiplier = knockout.observable(clock.multiplier); + this.multiplier.subscribe(function(value) { + clock.multiplier = value; + this.synchronize(); + }, this); /** - * Gets or sets whether calls to Clock.tick are frame dependent or system clock dependent. + * Gets or sets the clock step setting. + * See {@link Clock#clockStep}. * This property is observable. * @type {ClockStep} - * @default undefined */ - this.clockStep = undefined; - knockout.defineProperty(this, 'clockStep', { - get : clockStep, - set : function(value) { - clockStep(value); - clock.clockStep = value; - } - }); - - var clockRange = knockout.observable(clock.clockRange); - clockRange.equalityComparer = function(a, b) { - return a === b; - }; + this.clockStep = knockout.observable(clock.clockStep); + this.clockStep.subscribe(function(value) { + clock.clockStep = value; + this.synchronize(); + }, this); /** - * Gets or sets how tick should behave when startTime or stopTime is reached. + * Gets or sets the clock range setting. + * See {@link Clock#clockRange}. * This property is observable. * @type {ClockRange} - * @default undefined */ - this.clockRange = undefined; - knockout.defineProperty(this, 'clockRange', { - get : clockRange, - set : function(value) { - clockRange(value); - clock.clockRange = value; - } - }); - - var canAnimate = knockout.observable(clock.canAnimate); + this.clockRange = knockout.observable(clock.clockRange); + this.clockRange.subscribe(function(value) { + clock.clockRange = value; + this.synchronize(); + }, this); /** - * Gets or sets whether or not Clock.tick can advance time. - * This could be false if data is being buffered, for example. - * The clock will only tick when both canAnimate and shouldAnimate are true. + * Gets or sets whether the clock can animate. + * See {@link Clock#canAnimate}. * This property is observable. * @type {Boolean} - * @default undefined */ - this.canAnimate = undefined; - knockout.defineProperty(this, 'canAnimate', { - get : canAnimate, - set : function(value) { - canAnimate(value); - clock.canAnimate = value; - } - }); - - var shouldAnimate = knockout.observable(clock.shouldAnimate); + this.canAnimate = knockout.observable(clock.canAnimate); + this.canAnimate.subscribe(function(value) { + clock.canAnimate = value; + this.synchronize(); + }, this); /** - * Gets or sets whether or not Clock.tick should attempt to advance time. - * The clock will only tick when both canAnimate and shouldAnimate are true. + * Gets or sets whether the clock should animate. + * See {@link Clock#shouldAnimate}. * This property is observable. * @type {Boolean} - * @default undefined */ - this.shouldAnimate = undefined; - knockout.defineProperty(this, 'shouldAnimate', { - get : shouldAnimate, - set : function(value) { - shouldAnimate(value); - clock.shouldAnimate = value; - } - }); + this.shouldAnimate = knockout.observable(clock.shouldAnimate); + this.shouldAnimate.subscribe(function(value) { + clock.shouldAnimate = value; + this.synchronize(); + }, this); + + knockout.track(this, ['systemTime', 'startTime', 'stopTime', 'currentTime', 'multiplier', 'clockStep', 'clockRange', 'canAnimate', 'shouldAnimate']); } defineProperties(ClockViewModel.prototype, { /** * Gets the underlying Clock. * @memberof ClockViewModel.prototype - * * @type {Clock} */ clock : { @@ -214,24 +166,15 @@ define([ ClockViewModel.prototype.synchronize = function() { var clock = this._clock; - var startTime = clock.startTime; - var stopTime = clock.stopTime; - var currentTime = clock.currentTime; - var multiplier = clock.multiplier; - var clockStep = clock.clockStep; - var clockRange = clock.clockRange; - var canAnimate = clock.canAnimate; - var shouldAnimate = clock.shouldAnimate; - this.systemTime = JulianDate.now(); - this.startTime = startTime; - this.stopTime = stopTime; - this.currentTime = currentTime; - this.multiplier = multiplier; - this.clockStep = clockStep; - this.clockRange = clockRange; - this.canAnimate = canAnimate; - this.shouldAnimate = shouldAnimate; + this.startTime = clock.startTime; + this.stopTime = clock.stopTime; + this.currentTime = clock.currentTime; + this.multiplier = clock.multiplier; + this.clockStep = clock.clockStep; + this.clockRange = clock.clockRange; + this.canAnimate = clock.canAnimate; + this.shouldAnimate = clock.shouldAnimate; }; /** diff --git a/Specs/Core/ClockSpec.js b/Specs/Core/ClockSpec.js index c0003f2509fc..b7ba51e50e97 100644 --- a/Specs/Core/ClockSpec.js +++ b/Specs/Core/ClockSpec.js @@ -3,26 +3,30 @@ defineSuite([ 'Core/Clock', 'Core/ClockRange', 'Core/ClockStep', + 'Core/defined', 'Core/JulianDate', 'Specs/pollToPromise' ], function( Clock, ClockRange, ClockStep, + defined, JulianDate, pollToPromise) { 'use strict'; - it('constructor sets default parameters', function() { + it('sets default parameters when constructed', function() { var clock = new Clock(); expect(clock.stopTime).toEqual(JulianDate.addDays(clock.startTime, 1, new JulianDate())); expect(clock.startTime).toEqual(clock.currentTime); + expect(clock.multiplier).toEqual(1.0); expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK_MULTIPLIER); expect(clock.clockRange).toEqual(ClockRange.UNBOUNDED); - expect(clock.multiplier).toEqual(1.0); + expect(clock.canAnimate).toEqual(true); + expect(clock.shouldAnimate).toEqual(true); }); - it('constructor sets provided parameters correctly', function() { + it('sets provided constructor parameters correctly', function() { var start = new JulianDate(12); var stop = new JulianDate(112); var currentTime = new JulianDate(13); @@ -30,67 +34,84 @@ defineSuite([ var range = ClockRange.LOOP_STOP; var multiplier = 1.5; var clock = new Clock({ + startTime : start, + stopTime : stop, currentTime : currentTime, clockStep : step, multiplier : multiplier, - startTime : start, - stopTime : stop, clockRange : range }); + expect(clock.startTime).toEqual(start); + expect(clock.startTime).not.toBe(start); expect(clock.stopTime).toEqual(stop); + expect(clock.stopTime).not.toBe(stop); expect(clock.currentTime).toEqual(currentTime); + expect(clock.currentTime).not.toBe(currentTime); expect(clock.clockStep).toEqual(step); expect(clock.clockRange).toEqual(range); expect(clock.multiplier).toEqual(multiplier); + expect(clock.canAnimate).toEqual(true); + expect(clock.shouldAnimate).toEqual(true); + + clock = new Clock({ + canAnimate : false + }); + expect(clock.canAnimate).toEqual(false); + + clock = new Clock({ + shouldAnimate : false + }); + expect(clock.shouldAnimate).toEqual(false); }); - it('constructor works with no currentTime parameter', function() { + it('works when constructed with no currentTime parameter', function() { var start = new JulianDate(12); var stop = new JulianDate(112); - var currentTime = new JulianDate(12); var step = ClockStep.TICK_DEPENDENT; var range = ClockRange.LOOP_STOP; var multiplier = 1.5; var clock = new Clock({ - clockStep : step, - multiplier : multiplier, startTime : start, stopTime : stop, + clockStep : step, + multiplier : multiplier, clockRange : range }); expect(clock.startTime).toEqual(start); expect(clock.stopTime).toEqual(stop); - expect(clock.currentTime).toEqual(currentTime); + expect(clock.currentTime).toEqual(start); expect(clock.clockStep).toEqual(step); expect(clock.clockRange).toEqual(range); expect(clock.multiplier).toEqual(multiplier); + expect(clock.canAnimate).toEqual(true); + expect(clock.shouldAnimate).toEqual(true); }); - it('constructor works with no startTime parameter', function() { + it('works when constructed with no startTime parameter', function() { var stop = new JulianDate(112); var currentTime = new JulianDate(13); var step = ClockStep.TICK_DEPENDENT; var range = ClockRange.LOOP_STOP; var multiplier = 1.5; var clock = new Clock({ + stopTime : stop, currentTime : currentTime, clockStep : step, multiplier : multiplier, - stopTime : stop, clockRange : range }); - expect(clock.startTime).toEqual(clock.currentTime); + expect(clock.startTime).toEqual(currentTime); expect(clock.stopTime).toEqual(stop); expect(clock.currentTime).toEqual(currentTime); expect(clock.clockStep).toEqual(step); expect(clock.clockRange).toEqual(range); expect(clock.multiplier).toEqual(multiplier); + expect(clock.canAnimate).toEqual(true); + expect(clock.shouldAnimate).toEqual(true); }); - it('constructor works with no start or stop time', function() { - var start = new JulianDate(12); - var stop = new JulianDate(13); + it('works when constructed with no startTime or stopTime', function() { var currentTime = new JulianDate(12); var step = ClockStep.TICK_DEPENDENT; var range = ClockRange.LOOP_STOP; @@ -101,93 +122,108 @@ defineSuite([ multiplier : multiplier, clockRange : range }); - expect(clock.startTime).toEqual(start); - expect(clock.stopTime).toEqual(stop); + var expectedStop = JulianDate.addDays(currentTime, 1.0, new JulianDate()); + expect(clock.startTime).toEqual(currentTime); + expect(clock.stopTime).toEqual(expectedStop); expect(clock.currentTime).toEqual(currentTime); expect(clock.clockStep).toEqual(step); expect(clock.clockRange).toEqual(range); expect(clock.multiplier).toEqual(multiplier); + expect(clock.canAnimate).toEqual(true); + expect(clock.shouldAnimate).toEqual(true); }); - it('constructor works with no start or current time', function() { - var start = new JulianDate(12); + it('works when constructed with no startTime or currentTime', function() { var stop = new JulianDate(13); - var currentTime = new JulianDate(12); var step = ClockStep.TICK_DEPENDENT; var range = ClockRange.LOOP_STOP; var multiplier = 1.5; var clock = new Clock({ + stopTime : stop, clockStep : step, multiplier : multiplier, - stopTime : stop, clockRange : range }); - expect(clock.startTime).toEqual(start); + var expectedStart = JulianDate.addDays(stop, -1.0, new JulianDate()); + expect(clock.startTime).toEqual(expectedStart); expect(clock.stopTime).toEqual(stop); - expect(clock.currentTime).toEqual(currentTime); + expect(clock.currentTime).toEqual(expectedStart); expect(clock.clockStep).toEqual(step); expect(clock.clockRange).toEqual(range); expect(clock.multiplier).toEqual(multiplier); + expect(clock.canAnimate).toEqual(true); + expect(clock.shouldAnimate).toEqual(true); }); - - it('constructor works with no current or stop time', function() { + it('works when constructed with no currentTime or stopTime', function() { var start = new JulianDate(12); - var stop = new JulianDate(13); - var currentTime = new JulianDate(12); var step = ClockStep.TICK_DEPENDENT; var range = ClockRange.LOOP_STOP; var multiplier = 1.5; var clock = new Clock({ + startTime : start, clockStep : step, multiplier : multiplier, - startTime : start, clockRange : range }); + var expectedStop = JulianDate.addDays(start, 1.0, new JulianDate()); expect(clock.startTime).toEqual(start); - expect(clock.stopTime).toEqual(stop); - expect(clock.currentTime).toEqual(currentTime); + expect(clock.stopTime).toEqual(expectedStop); + expect(clock.currentTime).toEqual(start); expect(clock.clockStep).toEqual(step); expect(clock.clockRange).toEqual(range); expect(clock.multiplier).toEqual(multiplier); + expect(clock.canAnimate).toEqual(true); + expect(clock.shouldAnimate).toEqual(true); }); - it('constructor works with no stopTime parameter', function() { + it('works when constructed with no stopTime parameter', function() { var start = new JulianDate(12); - var stop = new JulianDate(13); var currentTime = new JulianDate(12); var step = ClockStep.TICK_DEPENDENT; var range = ClockRange.LOOP_STOP; var multiplier = 1.5; var clock = new Clock({ + startTime : start, currentTime : currentTime, clockStep : step, multiplier : multiplier, - startTime : start, clockRange : range }); + var expectedStop = JulianDate.addDays(start, 1.0, new JulianDate()); expect(clock.startTime).toEqual(start); - expect(clock.stopTime).toEqual(stop); + expect(clock.stopTime).toEqual(expectedStop); expect(clock.currentTime).toEqual(currentTime); expect(clock.clockStep).toEqual(step); expect(clock.clockRange).toEqual(range); expect(clock.multiplier).toEqual(multiplier); + expect(clock.canAnimate).toEqual(true); + expect(clock.shouldAnimate).toEqual(true); }); - it('Tick dependant clock step works animating forward.', function() { + it('throws when constructed if start time is after stop time', function() { + var start = new JulianDate(1); + var stop = new JulianDate(0); + expect(function() { + return new Clock({ + startTime : start, + stopTime : stop + }); + }).toThrowDeveloperError(); + }); + + it('animates forward in TICK_DEPENDENT mode', function() { var start = new JulianDate(0); var stop = new JulianDate(1); var currentTime = new JulianDate(0.5); - var step = ClockStep.TICK_DEPENDENT; - var range = ClockRange.LOOP_STOP; var multiplier = 1.5; var clock = new Clock({ - currentTime : currentTime, - clockStep : step, - multiplier : multiplier, startTime : start, stopTime : stop, - clockRange : range + currentTime : currentTime, + clockStep : ClockStep.TICK_DEPENDENT, + multiplier : multiplier, + clockRange : ClockRange.LOOP_STOP }); expect(clock.currentTime).toEqual(currentTime); @@ -200,20 +236,18 @@ defineSuite([ expect(clock.currentTime).toEqual(currentTime); }); - it('Tick dependant clock step works animating backwards.', function() { + it('animates backwards in TICK_DEPENDENT mode', function() { var start = new JulianDate(0); var stop = new JulianDate(1); var currentTime = new JulianDate(0.5); - var step = ClockStep.TICK_DEPENDENT; - var range = ClockRange.LOOP_STOP; var multiplier = -1.5; var clock = new Clock({ - currentTime : currentTime, - clockStep : step, - multiplier : multiplier, startTime : start, stopTime : stop, - clockRange : range + currentTime : currentTime, + clockStep : ClockStep.TICK_DEPENDENT, + multiplier : multiplier, + clockRange : ClockRange.LOOP_STOP }); expect(clock.currentTime).toEqual(currentTime); @@ -226,20 +260,18 @@ defineSuite([ expect(clock.currentTime).toEqual(currentTime); }); - it('Tick dependant clock step works unbounded animating forward.', function() { + it('animates forwards past stop time in UNBOUNDED TICK_DEPENDENT mode', function() { var start = new JulianDate(0); var stop = new JulianDate(1); - var currentTime = new JulianDate(1); - var step = ClockStep.TICK_DEPENDENT; - var range = ClockRange.UNBOUNDED; + var currentTime = stop; var multiplier = 1.5; var clock = new Clock({ - currentTime : currentTime, - clockStep : step, - multiplier : multiplier, startTime : start, stopTime : stop, - clockRange : range + currentTime : currentTime, + clockStep : ClockStep.TICK_DEPENDENT, + multiplier : multiplier, + clockRange : ClockRange.UNBOUNDED }); expect(clock.currentTime).toEqual(currentTime); @@ -252,20 +284,18 @@ defineSuite([ expect(clock.currentTime).toEqual(currentTime); }); - it('Tick dependant clock step works unbounded animating backwards.', function() { + it('animates backwards past start time in UNBOUNDED TICK_DEPENDENT mode', function() { var start = new JulianDate(0); var stop = new JulianDate(1); - var currentTime = new JulianDate(0); - var step = ClockStep.TICK_DEPENDENT; - var range = ClockRange.UNBOUNDED; + var currentTime = start; var multiplier = -1.5; var clock = new Clock({ - currentTime : currentTime, - clockStep : step, - multiplier : multiplier, startTime : start, stopTime : stop, - clockRange : range + currentTime : currentTime, + clockStep : ClockStep.TICK_DEPENDENT, + multiplier : multiplier, + clockRange : ClockRange.UNBOUNDED }); expect(clock.currentTime).toEqual(currentTime); @@ -278,20 +308,18 @@ defineSuite([ expect(clock.currentTime).toEqual(currentTime); }); - it('Tick dependant clock loops animating forward.', function() { + it('loops back to start time when animating forward past stop time in LOOP_STOP TICK_DEPENDENT mode', function() { var start = new JulianDate(0); var stop = new JulianDate(1); - var currentTime = new JulianDate(1); - var step = ClockStep.TICK_DEPENDENT; - var range = ClockRange.LOOP_STOP; + var currentTime = stop; var multiplier = 1.5; var clock = new Clock({ - currentTime : currentTime, - clockStep : step, - multiplier : multiplier, startTime : start, stopTime : stop, - clockRange : range + currentTime : currentTime, + clockStep : ClockStep.TICK_DEPENDENT, + multiplier : multiplier, + clockRange : ClockRange.LOOP_STOP }); expect(clock.currentTime).toEqual(currentTime); @@ -304,21 +332,18 @@ defineSuite([ expect(clock.currentTime).toEqual(currentTime); }); - it('Tick dependant clock step stops at start when animating backwards with ClockRange.LOOP_STOP.', function() { + it('stops at start when animating backwards past start time in LOOP_STOP TICK_DEPENDENT mode', function() { var start = new JulianDate(0); var stop = new JulianDate(1); - - var currentTime = new JulianDate(0); - var step = ClockStep.TICK_DEPENDENT; - var range = ClockRange.LOOP_STOP; + var currentTime = start; var multiplier = -100.0; var clock = new Clock({ - currentTime : currentTime, - clockStep : step, - multiplier : multiplier, startTime : start, stopTime : stop, - clockRange : range + currentTime : currentTime, + clockStep : ClockStep.TICK_DEPENDENT, + multiplier : multiplier, + clockRange : ClockRange.LOOP_STOP }); expect(clock.currentTime).toEqual(currentTime); @@ -326,21 +351,18 @@ defineSuite([ expect(start).toEqual(clock.currentTime); }); - it('Tick dependant clock step stops at end when animating forwards.', function() { + it('stops at stop time when animating forwards past stop time in CLAMPED TICK_DEPENDENT mode', function() { var start = new JulianDate(0); var stop = new JulianDate(1); - - var currentTime = new JulianDate(1); - var step = ClockStep.TICK_DEPENDENT; - var range = ClockRange.CLAMPED; + var currentTime = stop; var multiplier = 100.0; var clock = new Clock({ - currentTime : currentTime, - clockStep : step, - multiplier : multiplier, startTime : start, stopTime : stop, - clockRange : range + currentTime : currentTime, + clockStep : ClockStep.TICK_DEPENDENT, + multiplier : multiplier, + clockRange : ClockRange.CLAMPED }); expect(clock.currentTime).toEqual(currentTime); @@ -348,35 +370,18 @@ defineSuite([ expect(stop).toEqual(clock.currentTime); }); - it('Ticks in real-time.', function() { - //We can't numerically validate the real-time clock, but we - //can at least make sure the code executes. - var clock = new Clock({ - clockStep : ClockStep.SYSTEM_CLOCK - }); - var time1 = JulianDate.clone(clock.tick()); - - return pollToPromise(function() { - var time2 = clock.tick(); - return JulianDate.greaterThan(time2, time1); - }); - }); - - it('Tick dependant clock step stops at start animating backwards.', function() { + it('stops at start time when animating backwards past start time in CLAMPED TICK_DEPENDENT mode', function() { var start = new JulianDate(0); var stop = new JulianDate(1); - - var currentTime = new JulianDate(0); - var step = ClockStep.TICK_DEPENDENT; - var range = ClockRange.CLAMPED; + var currentTime = start; var multiplier = -100.0; var clock = new Clock({ - currentTime : currentTime, - clockStep : step, - multiplier : multiplier, startTime : start, stopTime : stop, - clockRange : range + currentTime : currentTime, + clockStep : ClockStep.TICK_DEPENDENT, + multiplier : multiplier, + clockRange : ClockRange.CLAMPED }); expect(clock.currentTime).toEqual(currentTime); @@ -384,66 +389,173 @@ defineSuite([ expect(start).toEqual(clock.currentTime); }); - it('throws if start time is after stop time.', function() { - var start = new JulianDate(1); - var stop = new JulianDate(0); - expect(function() { - return new Clock({ - startTime : start, - stopTime : stop - }); - }).toThrowDeveloperError(); - }); + describe('SYSTEM_CLOCK modes', function() { + var baseDate = new Date(2016, 6, 7); - it('system clock multiplier clock step works fine', function() { - var clock = new Clock({ - clockStep : ClockStep.SYSTEM_CLOCK_MULTIPLIER + beforeEach(function() { + jasmine.clock().install(); + jasmine.clock().mockDate(baseDate); + + if (typeof performance !== 'undefined' && defined(performance.now)) { + spyOn(performance, 'now').and.callFake(function() { + return Date.now(); + }); + } + }); + + afterEach(function() { + jasmine.clock().uninstall(); }); - var time1 = JulianDate.clone(clock.tick()); - return pollToPromise(function() { + it('uses current time in SYSTEM_CLOCK mode (real-time mode)', function() { + var clock = new Clock({ + clockStep : ClockStep.SYSTEM_CLOCK + }); + + expect(clock.currentTime).toEqual(JulianDate.fromDate(baseDate)); + expect(clock.multiplier).toEqual(1.0); + expect(clock.shouldAnimate).toEqual(true); + + var time1 = clock.tick(); + expect(time1).toEqual(JulianDate.fromDate(baseDate)); + + jasmine.clock().tick(1000); + var time2 = clock.tick(); - return JulianDate.greaterThan(time2, time1); + expect(time2).toEqual(JulianDate.addSeconds(JulianDate.fromDate(baseDate), 1.0, new JulianDate())); }); - }); - it('clock does not advance if shouldAnimate is false and advances if true', function() { - var clock = new Clock(); - var time1; - var time2; + it('switches out of SYSTEM_CLOCK mode when changing currentTime', function() { + var clock = new Clock({ + clockStep : ClockStep.SYSTEM_CLOCK + }); + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); - clock.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER; - var currentTime = clock.currentTime; - clock.shouldAnimate = false; - expect(currentTime).toEqual(clock.tick()); - expect(clock.currentTime).toEqual(currentTime); - clock.shouldAnimate = true; - time1 = JulianDate.clone(clock.tick()); + clock.currentTime = clock.currentTime; + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + + clock.currentTime = new JulianDate(1); + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK_MULTIPLIER); + }); + + it('switches out of SYSTEM_CLOCK mode when changing multiplier', function() { + var clock = new Clock({ + clockStep : ClockStep.SYSTEM_CLOCK + }); + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + + clock.multiplier = clock.multiplier; + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + + clock.multiplier = 1.5; + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK_MULTIPLIER); + }); + + it('switches out of SYSTEM_CLOCK mode when changing shouldAnimate', function() { + var clock = new Clock({ + clockStep : ClockStep.SYSTEM_CLOCK + }); + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + + clock.shouldAnimate = clock.shouldAnimate; + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + + clock.shouldAnimate = false; + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK_MULTIPLIER); + }); + + it('sets currentTime, multiplier and shouldAnimate when switching to SYSTEM_CLOCK mode', function() { + var clock = new Clock({ + currentTime : new JulianDate(1), + clockStep : ClockStep.SYSTEM_CLOCK_MULTIPLIER, + multiplier : 1.5, + shouldAnimate : false + }); - return pollToPromise(function() { - time2 = clock.tick(); - return JulianDate.greaterThan(time2, time1); - }).then(function() { clock.clockStep = ClockStep.SYSTEM_CLOCK; - currentTime = clock.currentTime; + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + expect(clock.currentTime).toEqual(JulianDate.fromDate(baseDate)); + expect(clock.multiplier).toEqual(1.0); + expect(clock.shouldAnimate).toEqual(true); + }); + + it('stays in SYSTEM_CLOCK mode when changing other unrelated properties', function() { + var clock = new Clock({ + clockStep : ClockStep.SYSTEM_CLOCK + }); + + clock.startTime = new JulianDate(1); + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + + clock.stopTime = new JulianDate(2); + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + + clock.clockRange = ClockRange.CLAMP; + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + + clock.canAnimate = false; + expect(clock.clockStep).toEqual(ClockStep.SYSTEM_CLOCK); + }); + + it('uses multiplier in SYSTEM_CLOCK_MULTIPLIER mode', function() { + var clock = new Clock({ + clockStep : ClockStep.SYSTEM_CLOCK_MULTIPLIER, + multiplier : 2.0 + }); + + var time1 = clock.tick(); + expect(time1).toEqual(JulianDate.fromDate(baseDate)); + + jasmine.clock().tick(1000); + + var time2 = clock.tick(); + expect(time2).toEqual(JulianDate.addSeconds(JulianDate.fromDate(baseDate), 2.0, new JulianDate())); + }); + + it('does not advance if shouldAnimate is false and does advance if true', function() { + var start = JulianDate.fromDate(baseDate); + + var clock = new Clock({ + startTime : start, + clockStep : ClockStep.SYSTEM_CLOCK_MULTIPLIER + }); + + expect(clock.currentTime).toEqual(start); clock.shouldAnimate = false; - expect(currentTime).toEqual(clock.tick()); - expect(clock.currentTime).toEqual(currentTime); + + jasmine.clock().tick(1000); + + var time1 = clock.tick(); + expect(time1).toEqual(start); + expect(clock.currentTime).toEqual(start); + clock.shouldAnimate = true; - time1 = JulianDate.clone(clock.tick()); - - return pollToPromise(function() { - time2 = clock.tick(); - return JulianDate.greaterThan(time2, time1); - }).then(function() { - clock.clockStep = ClockStep.TICK_DEPENDENT; - currentTime = JulianDate.clone(clock.currentTime); - clock.shouldAnimate = false; - expect(currentTime).toEqual(clock.tick()); - expect(clock.currentTime).toEqual(currentTime); - clock.shouldAnimate = true; - expect(JulianDate.greaterThan(clock.tick(), currentTime)).toEqual(true); - }); + + jasmine.clock().tick(1000); + + time1 = clock.tick(); + + expect(time1).toEqual(JulianDate.addSeconds(JulianDate.fromDate(baseDate), 1.0, new JulianDate())); + + jasmine.clock().tick(1000); + + var time2 = clock.tick(); + + expect(time2).toEqual(JulianDate.addSeconds(JulianDate.fromDate(baseDate), 2.0, new JulianDate())); + + clock.currentTime = start; + clock.clockStep = ClockStep.TICK_DEPENDENT; + + clock.shouldAnimate = false; + + time1 = clock.tick(); + expect(time1).toEqual(start); + expect(clock.currentTime).toEqual(start); + + clock.shouldAnimate = true; + time1 = clock.tick(); + + expect(time1).toEqual(JulianDate.addSeconds(JulianDate.fromDate(baseDate), 1.0, new JulianDate())); }); }); }); diff --git a/Specs/Widgets/Animation/AnimationViewModelSpec.js b/Specs/Widgets/Animation/AnimationViewModelSpec.js index 639d99a90336..1d7b3a9b61fc 100644 --- a/Specs/Widgets/Animation/AnimationViewModelSpec.js +++ b/Specs/Widgets/Animation/AnimationViewModelSpec.js @@ -486,9 +486,9 @@ defineSuite([ viewModel.playRealtimeViewModel.command(); verifyRealtimeState(viewModel); - //Play breaks realtime state + //Play does not break realtime state viewModel.playForwardViewModel.command(); - verifyForwardState(viewModel); + verifyRealtimeState(viewModel); expect(clockViewModel.multiplier).toEqual(1); viewModel.playRealtimeViewModel.command(); @@ -499,7 +499,7 @@ defineSuite([ verifyForwardState(viewModel); }); - it('real time mode toggles only if shouldAnimate is true', function() { + it('real time mode toggles off but not back on when shouldAnimate changes', function() { var viewModel = new AnimationViewModel(clockViewModel); viewModel.playRealtimeViewModel.command(); @@ -509,7 +509,7 @@ defineSuite([ expect(viewModel.playRealtimeViewModel.toggled).toEqual(false); clockViewModel.shouldAnimate = true; - expect(viewModel.playRealtimeViewModel.toggled).toEqual(true); + expect(viewModel.playRealtimeViewModel.toggled).toEqual(false); }); it('Shuttle ring angles set expected multipliers', function() { diff --git a/Specs/Widgets/Viewer/ViewerSpec.js b/Specs/Widgets/Viewer/ViewerSpec.js index 152c3c1aca64..5975bd670773 100644 --- a/Specs/Widgets/Viewer/ViewerSpec.js +++ b/Specs/Widgets/Viewer/ViewerSpec.js @@ -687,8 +687,8 @@ defineSuite([ dataSource.clock.stopTime = JulianDate.fromIso8601('2014-08-21T02:00Z'); dataSource.clock.currentTime = JulianDate.fromIso8601('2014-08-02T00:00Z'); dataSource.clock.clockRange = ClockRange.UNBOUNDED; - dataSource.clock.clockStep = ClockStep.SYSTEM_CLOCK; - dataSource.clock.multiplier = 20.0; + dataSource.clock.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER; + dataSource.clock.multiplier = 10.0; dataSource.changedEvent.raiseEvent(dataSource); @@ -698,6 +698,13 @@ defineSuite([ expect(viewer.clock.clockRange).toEqual(dataSource.clock.clockRange); expect(viewer.clock.clockStep).toEqual(dataSource.clock.clockStep); expect(viewer.clock.multiplier).toEqual(dataSource.clock.multiplier); + + dataSource.clock.clockStep = ClockStep.SYSTEM_CLOCK; + dataSource.clock.multiplier = 1.0; + + dataSource.changedEvent.raiseEvent(dataSource); + + expect(viewer.clock.clockStep).toEqual(dataSource.clock.clockStep); }); it('can manually control the clock tracking', function() {