From 0c8d5988114441e27c2c8690ff0249750c02d98d Mon Sep 17 00:00:00 2001 From: Scott Hunter Date: Tue, 7 Jun 2016 17:22:34 -0400 Subject: [PATCH 1/3] Move logic for real-time mode (SYSTEM_CLOCK) into Clock itself. SYSTEM_CLOCK implies animating forward at a 1x multiplier. Centralize the logic for dealing with coordinating clock settings in Clock itself. When switching to SYSTEM_CLOCK, other values are immediately updated to be consistent. When changing other values, e.g. current time or multiplier, SYSTEM_CLOCK is deactivated. This fixes some inconsistencies in the UI where the logic was not consistent, due to being scattered around. Specifically, when you dragged the timeline while in realtime mode, you ended up in a hybrid state where the mode was still set to SYSTEM_CLOCK and therefore the label in the UI still said "Today" etc. --- Source/Core/Clock.js | 248 +++++++--- .../Widgets/Animation/AnimationViewModel.js | 26 +- Source/Widgets/ClockViewModel.js | 207 +++------ Specs/Core/ClockSpec.js | 438 +++++++++++------- .../Animation/AnimationViewModelSpec.js | 8 +- 5 files changed, 533 insertions(+), 394 deletions(-) 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/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..c57bd337eae0 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() { From 05c3018f0a6bd7fcd3ad5d3f86c8f89cd9a32d66 Mon Sep 17 00:00:00 2001 From: Scott Hunter Date: Tue, 7 Jun 2016 17:39:07 -0400 Subject: [PATCH 2/3] update CHANGES --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 7f5bc7b50672..f485ff5a375c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ Change Log * Add a `rotatable2D` option to to `Scene`, `CesiumWidget` and `Viewer` to enable a rotatable map in 2D. [#3897](https://github.com/AnalyticalGraphicsInc/cesium/issues/3897) * `Camera.setView` and `Camera.flyTo` will now use the `orientation.heading` parameter in 2D if the map is rotatable. +* `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 From 8176ef2e02088bdffc3080dd9672c938acff205a Mon Sep 17 00:00:00 2001 From: Scott Hunter Date: Thu, 9 Jun 2016 17:05:22 -0400 Subject: [PATCH 3/3] Fix tests. Clean up DataSourceClock. Apply clockStep setting last since it may overrule other settings. --- Source/DataSources/DataSourceClock.js | 28 +++++++++++++++------------ Source/Widgets/ClockViewModel.js | 2 +- Specs/Widgets/Viewer/ViewerSpec.js | 11 +++++++++-- 3 files changed, 26 insertions(+), 15 deletions(-) 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/ClockViewModel.js b/Source/Widgets/ClockViewModel.js index c57bd337eae0..96bd1cf9351e 100644 --- a/Source/Widgets/ClockViewModel.js +++ b/Source/Widgets/ClockViewModel.js @@ -107,7 +107,7 @@ define([ }, this); /** - * Gets or sets the clock range setting + * Gets or sets the clock range setting. * See {@link Clock#clockRange}. * This property is observable. * @type {ClockRange} 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() {