Compare commits
	
		
			5 Commits
		
	
	
		
			missing-it
			...
			time-api
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | be476aff43 | ||
|   | d62a3ca494 | ||
|   | d77ea6c024 | ||
|   | fae7cd69da | ||
|   | 80432710e0 | 
| @@ -20,7 +20,7 @@ | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define(['../../../platform/features/conductor/core/src/timeSystems/LocalClock'], function (LocalClock) { | ||||
| define(['../../../src/plugins/utcTimeSystem/LocalClock'], function (LocalClock) { | ||||
|     /** | ||||
|      * @implements TickSource | ||||
|      * @constructor | ||||
| @@ -28,14 +28,12 @@ define(['../../../platform/features/conductor/core/src/timeSystems/LocalClock'], | ||||
|     function LADTickSource ($timeout, period) { | ||||
|         LocalClock.call(this, $timeout, period); | ||||
|  | ||||
|         this.metadata = { | ||||
|             key: 'test-lad', | ||||
|             mode: 'lad', | ||||
|             cssClass: 'icon-clock', | ||||
|             label: 'Latest Available Data', | ||||
|             name: 'Latest available data', | ||||
|             description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.' | ||||
|         }; | ||||
|         this.key = 'test-lad'; | ||||
|         this.mode = 'lad'; | ||||
|         this.cssClass = 'icon-clock'; | ||||
|         this.label = 'Latest Available Data'; | ||||
|         this.name = 'Latest available data'; | ||||
|         this.description = 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'; | ||||
|     } | ||||
|     LADTickSource.prototype = Object.create(LocalClock.prototype); | ||||
|  | ||||
|   | ||||
| @@ -21,10 +21,9 @@ | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     '../../../platform/features/conductor/core/src/timeSystems/TimeSystem', | ||||
|     '../../../platform/features/conductor/core/src/timeSystems/LocalClock', | ||||
|     '../../../src/plugins/utcTimeSystem/LocalClock', | ||||
|     './LADTickSource' | ||||
| ], function (TimeSystem, LocalClock, LADTickSource) { | ||||
| ], function (LocalClock, LADTickSource) { | ||||
|     var THIRTY_MINUTES = 30 * 60 * 1000, | ||||
|         DEFAULT_PERIOD = 1000; | ||||
|  | ||||
| @@ -34,25 +33,20 @@ define([ | ||||
|      * @constructor | ||||
|      */ | ||||
|     function LocalTimeSystem ($timeout) { | ||||
|         TimeSystem.call(this); | ||||
|  | ||||
|         /** | ||||
|          * Some metadata, which will be used to identify the time system in | ||||
|          * the UI | ||||
|          * @type {{key: string, name: string, glyph: string}} | ||||
|          */ | ||||
|         this.metadata = { | ||||
|             'key': 'local', | ||||
|             'name': 'Local', | ||||
|             'glyph': '\u0043' | ||||
|         }; | ||||
|         this.key = 'local'; | ||||
|         this.name = 'Local'; | ||||
|         this.cssClass = '\u0043'; | ||||
|  | ||||
|         this.fmts = ['local-format']; | ||||
|         this.sources = [new LocalClock($timeout, DEFAULT_PERIOD), new LADTickSource($timeout, DEFAULT_PERIOD)]; | ||||
|     } | ||||
|  | ||||
|     LocalTimeSystem.prototype = Object.create(TimeSystem.prototype); | ||||
|  | ||||
|     LocalTimeSystem.prototype.formats = function () { | ||||
|         return this.fmts; | ||||
|     }; | ||||
| @@ -65,6 +59,10 @@ define([ | ||||
|         return this.sources; | ||||
|     }; | ||||
|  | ||||
|     LocalTimeSystem.prototype.isUTCBased = function () { | ||||
|         return true; | ||||
|     }; | ||||
|  | ||||
|     LocalTimeSystem.prototype.defaults = function (key) { | ||||
|         var now = Math.ceil(Date.now() / 1000) * 1000; | ||||
|         return { | ||||
|   | ||||
| @@ -84,11 +84,5 @@ define([ | ||||
|         return new Main().run(defaultRegistry); | ||||
|     }); | ||||
|  | ||||
|     // For now, install conductor by default | ||||
|     openmct.install(openmct.plugins.Conductor({ | ||||
|         showConductor: false | ||||
|     })); | ||||
|  | ||||
|  | ||||
|     return openmct; | ||||
| }); | ||||
|   | ||||
| @@ -41,7 +41,7 @@ define( | ||||
|             scope, | ||||
|             element | ||||
|         ) { | ||||
|             this.conductor = openmct.conductor; | ||||
|             this.timeAPI = openmct.time; | ||||
|             this.scope = scope; | ||||
|             this.element = element; | ||||
|  | ||||
| @@ -51,24 +51,26 @@ define( | ||||
|         } | ||||
|  | ||||
|         ConductorRepresenter.prototype.boundsListener = function (bounds) { | ||||
|             var timeSystem = this.timeAPI.getTimeSystem(this.timeAPI.timeSystem()); | ||||
|             this.scope.$broadcast('telemetry:display:bounds', { | ||||
|                 start: bounds.start, | ||||
|                 end: bounds.end, | ||||
|                 domain: this.conductor.timeSystem().metadata.key | ||||
|             }, this.conductor.follow()); | ||||
|                 domain: timeSystem | ||||
|             }, this.timeAPI.follow()); | ||||
|         }; | ||||
|  | ||||
|         ConductorRepresenter.prototype.timeSystemListener = function (timeSystem) { | ||||
|             var bounds = this.conductor.bounds(); | ||||
|         ConductorRepresenter.prototype.timeSystemListener = function (key) { | ||||
|             var bounds = this.timeAPI.bounds(); | ||||
|             var timeSystem = this.timeAPI.getTimeSystem(key); | ||||
|             this.scope.$broadcast('telemetry:display:bounds', { | ||||
|                 start: bounds.start, | ||||
|                 end: bounds.end, | ||||
|                 domain: timeSystem.metadata.key | ||||
|             }, this.conductor.follow()); | ||||
|                 domain: timeSystem | ||||
|             }, this.timeAPI.follow()); | ||||
|         }; | ||||
|  | ||||
|         ConductorRepresenter.prototype.followListener = function () { | ||||
|             this.boundsListener(this.conductor.bounds()); | ||||
|             this.boundsListener(this.timeAPI.bounds()); | ||||
|         }; | ||||
|  | ||||
|         // Handle a specific representation of a specific domain object | ||||
| @@ -76,16 +78,16 @@ define( | ||||
|             if (representation.key === 'browse-object') { | ||||
|                 this.destroy(); | ||||
|  | ||||
|                 this.conductor.on("bounds", this.boundsListener); | ||||
|                 this.conductor.on("timeSystem", this.timeSystemListener); | ||||
|                 this.conductor.on("follow", this.followListener); | ||||
|                 this.timeAPI.on("bounds", this.boundsListener); | ||||
|                 this.timeAPI.on("timeSystem", this.timeSystemListener); | ||||
|                 this.timeAPI.on("follow", this.followListener); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         ConductorRepresenter.prototype.destroy = function destroy() { | ||||
|             this.conductor.off("bounds", this.boundsListener); | ||||
|             this.conductor.off("timeSystem", this.timeSystemListener); | ||||
|             this.conductor.off("follow", this.followListener); | ||||
|             this.timeAPI.off("bounds", this.boundsListener); | ||||
|             this.timeAPI.off("timeSystem", this.timeSystemListener); | ||||
|             this.timeAPI.off("follow", this.followListener); | ||||
|         }; | ||||
|  | ||||
|         return ConductorRepresenter; | ||||
|   | ||||
| @@ -71,8 +71,7 @@ define([ | ||||
|                         "openmct", | ||||
|                         "timeConductorViewService", | ||||
|                         "formatService", | ||||
|                         "DEFAULT_TIMECONDUCTOR_MODE", | ||||
|                         "SHOW_TIMECONDUCTOR" | ||||
|                         "CONDUCTOR_CONFIG" | ||||
|                     ] | ||||
|                 }, | ||||
|                 { | ||||
| @@ -151,13 +150,6 @@ define([ | ||||
|                     "link": "https://github.com/d3/d3/blob/master/LICENSE" | ||||
|                 } | ||||
|             ], | ||||
|             "constants": [ | ||||
|                 { | ||||
|                     "key": "DEFAULT_TIMECONDUCTOR_MODE", | ||||
|                     "value": "realtime", | ||||
|                     "priority": "fallback" | ||||
|                 } | ||||
|             ], | ||||
|             "formats": [ | ||||
|                 { | ||||
|                     "key": "number", | ||||
|   | ||||
| @@ -22,8 +22,8 @@ | ||||
| <div class="contents"> | ||||
|     <div class="pane left menu-items"> | ||||
|         <ul> | ||||
|             <li ng-repeat="(key, metadata) in ngModel.options" | ||||
|                 ng-click="ngModel.selectedKey=key"> | ||||
|             <li ng-repeat="metadata in ngModel.options" | ||||
|                 ng-click="ngModel.selected = metadata"> | ||||
|                 <a ng-mouseover="ngModel.activeMetadata = metadata" | ||||
|                    ng-mouseleave="ngModel.activeMetadata = undefined" | ||||
|                    class="menu-item-a {{metadata.cssClass}}"> | ||||
| @@ -33,8 +33,7 @@ | ||||
|         </ul> | ||||
|     </div> | ||||
|     <div class="pane right menu-item-description"> | ||||
|         <div | ||||
|                 class="desc-area ui-symbol icon type-icon {{ngModel.activeMetadata.cssClass}}"></div> | ||||
|         <div class="desc-area ui-symbol icon type-icon {{ngModel.activeMetadata.cssClass}}"></div> | ||||
|         <div class="desc-area title"> | ||||
|             {{ngModel.activeMetadata.name}} | ||||
|         </div> | ||||
|   | ||||
| @@ -22,8 +22,7 @@ | ||||
| <span ng-controller="ClickAwayController as modeController"> | ||||
|     <div class="s-menu-button" | ||||
|          ng-click="modeController.toggle()"> | ||||
| 		<span class="title-label">{{ngModel.options[ngModel.selectedKey] | ||||
|             .label}}</span> | ||||
| 		<span class="title-label">{{ngModel.selected.name}}</span> | ||||
|     </div> | ||||
|     <div class="menu super-menu mini mode-selector-menu" | ||||
|          ng-show="modeController.isActive()"> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <!-- Parent holder for time conductor. follow-mode | fixed-mode --> | ||||
| <div ng-controller="TimeConductorController as tcController" | ||||
|     class="holder grows flex-elem l-flex-row l-time-conductor {{modeModel.selectedKey}}-mode {{timeSystemModel.selected.metadata.key}}-time-system" | ||||
|         ng-class="{'status-panning': tcController.panning}" ng-show="showTimeConductor"> | ||||
|         ng-class="{'status-panning': tcController.panning}"> | ||||
|     <div class="flex-elem holder time-conductor-icon"> | ||||
|         <div class="hand-little"></div> | ||||
|         <div class="hand-big"></div> | ||||
| @@ -99,14 +99,14 @@ | ||||
|         <div class="l-time-conductor-controls l-row-elem l-flex-row flex-elem"> | ||||
|             <mct-include | ||||
|                 key="'mode-selector'" | ||||
|                 ng-model="modeModel" | ||||
|                 ng-model="tcController.menu" | ||||
|                 class="holder flex-elem menus-up mode-selector"> | ||||
|             </mct-include> | ||||
|             <mct-control | ||||
|                     key="'menu-button'" | ||||
|                     class="holder flex-elem menus-up time-system" | ||||
|                     structure="{ | ||||
|                         text: timeSystemModel.selected.metadata.name, | ||||
|                         text: timeSystemModel.selected.name, | ||||
|                         click: tcController.selectTimeSystemByKey, | ||||
|                         options: timeSystemModel.options | ||||
|                     }"> | ||||
|   | ||||
| @@ -1,47 +0,0 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([], function () { | ||||
|     /** | ||||
|      * A tick source is an event generator such as a timing signal, or | ||||
|      * indicator of data availability, which can be used to advance the Time | ||||
|      * Conductor. Usage is simple, a listener registers a callback which is | ||||
|      * invoked when this source 'ticks'. | ||||
|      * | ||||
|      * @interface | ||||
|      * @constructor | ||||
|      */ | ||||
|     function TickSource() { | ||||
|         this.listeners = []; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param callback Function to be called when this tick source ticks. | ||||
|      * @returns an 'unlisten' function that will remove the callback from | ||||
|      * the registered listeners | ||||
|      */ | ||||
|     TickSource.prototype.listen = function (callback) { | ||||
|         throw new Error('Not implemented'); | ||||
|     }; | ||||
|  | ||||
|     return TickSource; | ||||
| }); | ||||
| @@ -1,107 +0,0 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([], function () { | ||||
|     /** | ||||
|      * @interface | ||||
|      * @constructor | ||||
|      */ | ||||
|     function TimeSystem() { | ||||
|         /** | ||||
|          * @typedef TimeSystemMetadata | ||||
|          * @property {string} key | ||||
|          * @property {string} name | ||||
|          * @property {string} description | ||||
|          * | ||||
|          * @type {TimeSystemMetadata} | ||||
|          */ | ||||
|         this.metadata = undefined; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Time formats are defined as extensions. Time systems that implement | ||||
|      * this interface should provide an array of format keys supported by them. | ||||
|      * | ||||
|      * @returns {string[]} An array of time format keys | ||||
|      */ | ||||
|     TimeSystem.prototype.formats = function () { | ||||
|         throw new Error('Not implemented'); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * @typedef DeltaFormat | ||||
|      * @property {string} type the type of MctControl used to represent this | ||||
|      * field. Typically 'datetime-field' for UTC based dates, or 'textfield' | ||||
|      * otherwise | ||||
|      * @property {string} [format] An optional field specifying the | ||||
|      * Format to use for delta fields in this time system. | ||||
|      */ | ||||
|     /** | ||||
|      * Specifies a format for deltas in this time system. | ||||
|      * | ||||
|      * @returns {DeltaFormat} a delta format specifier | ||||
|      */ | ||||
|     TimeSystem.prototype.deltaFormat = function () { | ||||
|         throw new Error('Not implemented'); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Returns the tick sources supported by this time system. Tick sources | ||||
|      * are event generators that can be used to advance the time conductor | ||||
|      * @returns {TickSource[]} The tick sources supported by this time system. | ||||
|      */ | ||||
|     TimeSystem.prototype.tickSources = function () { | ||||
|         throw new Error('Not implemented'); | ||||
|     }; | ||||
|  | ||||
|     /*** | ||||
|      * | ||||
|      * @typedef {object} TimeConductorZoom | ||||
|      * @property {number} min The largest time span that the time | ||||
|      * conductor can display in this time system. ie. the span of the time | ||||
|      * conductor in its most zoomed out state. | ||||
|      * @property {number} max The smallest time span that the time | ||||
|      * conductor can display in this time system. ie. the span of the time | ||||
|      * conductor bounds in its most zoomed in state. | ||||
|      * | ||||
|      * @typedef {object} TimeSystemDefault | ||||
|      * @property {TimeConductorDeltas} deltas The deltas to apply by default | ||||
|      * when this time system is active. Applies to real-time modes only | ||||
|      * @property {TimeConductorBounds} bounds The bounds to apply by default | ||||
|      * when this time system is active | ||||
|      * @property {TimeConductorZoom} zoom Default min and max zoom levels | ||||
|      * @returns {TimeSystemDefault[]} At least one set of default values for | ||||
|      * this time system. | ||||
|      */ | ||||
|     TimeSystem.prototype.defaults = function () { | ||||
|         throw new Error('Not implemented'); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * @return {boolean} | ||||
|      */ | ||||
|     TimeSystem.prototype.isUTCBased = function () { | ||||
|         return true; | ||||
|     }; | ||||
|  | ||||
|     return TimeSystem; | ||||
| }); | ||||
| @@ -35,14 +35,14 @@ define( | ||||
|         function ConductorAxisController(openmct, formatService, conductorViewService, scope, element) { | ||||
|             // Dependencies | ||||
|             this.formatService = formatService; | ||||
|             this.conductor = openmct.conductor; | ||||
|             this.timeAPI = openmct.time; | ||||
|             this.conductorViewService = conductorViewService; | ||||
|  | ||||
|             this.scope = scope; | ||||
|             this.initialized = false; | ||||
|  | ||||
|             this.bounds = this.conductor.bounds(); | ||||
|             this.timeSystem = this.conductor.timeSystem(); | ||||
|             this.bounds = this.timeAPI.bounds(); | ||||
|             this.timeSystem = this.timeAPI.timeSystem(); | ||||
|  | ||||
|             //Bind all class functions to 'this' | ||||
|             Object.keys(ConductorAxisController.prototype).filter(function (key) { | ||||
| @@ -58,8 +58,8 @@ define( | ||||
|          * @private | ||||
|          */ | ||||
|         ConductorAxisController.prototype.destroy = function () { | ||||
|             this.conductor.off('timeSystem', this.changeTimeSystem); | ||||
|             this.conductor.off('bounds', this.changeBounds); | ||||
|             this.timeAPI.off('timeSystem', this.changeTimeSystem); | ||||
|             this.timeAPI.off('bounds', this.changeBounds); | ||||
|             this.conductorViewService.off("zoom", this.onZoom); | ||||
|             this.conductorViewService.off("zoom-stop", this.onZoomStop); | ||||
|         }; | ||||
| @@ -87,8 +87,8 @@ define( | ||||
|             } | ||||
|  | ||||
|             //Respond to changes in conductor | ||||
|             this.conductor.on("timeSystem", this.changeTimeSystem); | ||||
|             this.conductor.on("bounds", this.changeBounds); | ||||
|             this.timeAPI.on("timeSystem", this.changeTimeSystem); | ||||
|             this.timeAPI.on("bounds", this.changeBounds); | ||||
|  | ||||
|             this.scope.$on("$destroy", this.destroy); | ||||
|  | ||||
| @@ -111,7 +111,7 @@ define( | ||||
|          */ | ||||
|         ConductorAxisController.prototype.setScale = function () { | ||||
|             var width = this.target.offsetWidth; | ||||
|             var timeSystem = this.conductor.timeSystem(); | ||||
|             var timeSystem = this.timeAPI.getTimeSystem(this.timeAPI.timeSystem()); | ||||
|             var bounds = this.bounds; | ||||
|  | ||||
|             if (timeSystem.isUTCBased()) { | ||||
| @@ -134,13 +134,15 @@ define( | ||||
|          * When the time system changes, update the scale and formatter used for showing times. | ||||
|          * @param timeSystem | ||||
|          */ | ||||
|         ConductorAxisController.prototype.changeTimeSystem = function (timeSystem) { | ||||
|             this.timeSystem = timeSystem; | ||||
|         ConductorAxisController.prototype.changeTimeSystem = function (key) { | ||||
|             var timeSystem = this.timeAPI.getTimeSystem(key); | ||||
|  | ||||
|             this.timeSystem = key; | ||||
|  | ||||
|             var key = timeSystem.formats()[0]; | ||||
|             if (key !== undefined) { | ||||
|                 var format = this.formatService.getFormat(key); | ||||
|                 var bounds = this.conductor.bounds(); | ||||
|                 var bounds = this.timeAPI.bounds(); | ||||
|  | ||||
|                 //The D3 scale used depends on the type of time system as d3 | ||||
|                 // supports UTC out of the box. | ||||
| @@ -178,7 +180,7 @@ define( | ||||
|         ConductorAxisController.prototype.panStop = function () { | ||||
|             //resync view bounds with time conductor bounds | ||||
|             this.conductorViewService.emit("pan-stop"); | ||||
|             this.conductor.bounds(this.bounds); | ||||
|             this.timeAPI.bounds(this.bounds); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
| @@ -214,9 +216,9 @@ define( | ||||
|          * @fires platform.features.conductor.ConductorAxisController~pan | ||||
|          */ | ||||
|         ConductorAxisController.prototype.pan = function (delta) { | ||||
|             if (!this.conductor.follow()) { | ||||
|             if (!this.timeAPI.follow()) { | ||||
|                 var deltaInMs = delta[0] * this.msPerPixel; | ||||
|                 var bounds = this.conductor.bounds(); | ||||
|                 var bounds = this.timeAPI.bounds(); | ||||
|                 var start = Math.floor((bounds.start - deltaInMs) / 1000) * 1000; | ||||
|                 var end = Math.floor((bounds.end - deltaInMs) / 1000) * 1000; | ||||
|                 this.bounds = { | ||||
|   | ||||
| @@ -30,7 +30,7 @@ define( | ||||
|          * @memberof platform.features.conductor | ||||
|          */ | ||||
|         function ConductorTOIController($scope, openmct, conductorViewService) { | ||||
|             this.conductor = openmct.conductor; | ||||
|             this.timeAPI = openmct.time; | ||||
|             this.conductorViewService = conductorViewService; | ||||
|  | ||||
|             //Bind all class functions to 'this' | ||||
| @@ -40,11 +40,11 @@ define( | ||||
|                 this[key] = ConductorTOIController.prototype[key].bind(this); | ||||
|             }.bind(this)); | ||||
|  | ||||
|             this.conductor.on('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.timeAPI.on('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.conductorViewService.on('zoom', this.setOffsetFromZoom); | ||||
|             this.conductorViewService.on('pan', this.setOffsetFromBounds); | ||||
|  | ||||
|             var timeOfInterest = this.conductor.timeOfInterest(); | ||||
|             var timeOfInterest = this.timeAPI.timeOfInterest(); | ||||
|             if (timeOfInterest) { | ||||
|                 this.changeTimeOfInterest(timeOfInterest); | ||||
|             } | ||||
| @@ -56,7 +56,7 @@ define( | ||||
|          * @private | ||||
|          */ | ||||
|         ConductorTOIController.prototype.destroy = function () { | ||||
|             this.conductor.off('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.timeAPI.off('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.conductorViewService.off('zoom', this.setOffsetFromZoom); | ||||
|             this.conductorViewService.off('pan', this.setOffsetFromBounds); | ||||
|         }; | ||||
| @@ -70,7 +70,7 @@ define( | ||||
|          * @param {TimeConductorBounds} bounds | ||||
|          */ | ||||
|         ConductorTOIController.prototype.setOffsetFromBounds = function (bounds) { | ||||
|             var toi = this.conductor.timeOfInterest(); | ||||
|             var toi = this.timeAPI.timeOfInterest(); | ||||
|             if (toi !== undefined) { | ||||
|                 var offset = toi - bounds.start; | ||||
|                 var duration = bounds.end - bounds.start; | ||||
| @@ -94,7 +94,7 @@ define( | ||||
|          * @private | ||||
|          */ | ||||
|         ConductorTOIController.prototype.changeTimeOfInterest = function () { | ||||
|             var bounds = this.conductor.bounds(); | ||||
|             var bounds = this.timeAPI.bounds(); | ||||
|             if (bounds) { | ||||
|                 this.setOffsetFromBounds(bounds); | ||||
|             } | ||||
| @@ -112,10 +112,10 @@ define( | ||||
|                 var width = element.width(); | ||||
|                 var relativeX = e.pageX - element.offset().left; | ||||
|                 var percX = relativeX / width; | ||||
|                 var bounds = this.conductor.bounds(); | ||||
|                 var bounds = this.timeAPI.bounds(); | ||||
|                 var timeRange = bounds.end - bounds.start; | ||||
|  | ||||
|                 this.conductor.timeOfInterest(timeRange * percX + bounds.start); | ||||
|                 this.timeAPI.timeOfInterest(timeRange * percX + bounds.start); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|   | ||||
| @@ -47,8 +47,7 @@ define( | ||||
|             openmct, | ||||
|             conductorViewService, | ||||
|             formatService, | ||||
|             DEFAULT_MODE, | ||||
|             SHOW_TIMECONDUCTOR | ||||
|             config | ||||
|         ) { | ||||
|  | ||||
|             var self = this; | ||||
| @@ -64,19 +63,22 @@ define( | ||||
|             this.$window = $window; | ||||
|             this.$location = $location; | ||||
|             this.conductorViewService = conductorViewService; | ||||
|             this.conductor = openmct.conductor; | ||||
|             this.timeAPI = openmct.time; | ||||
|             this.modes = conductorViewService.availableModes(); | ||||
|             this.validation = new TimeConductorValidation(this.conductor); | ||||
|             this.validation = new TimeConductorValidation(this.timeAPI); | ||||
|             this.formatService = formatService; | ||||
|             this.config = config; | ||||
|  | ||||
|             //Check if the default mode defined is actually available | ||||
|             if (this.modes[DEFAULT_MODE] === undefined) { | ||||
|                 DEFAULT_MODE = 'fixed'; | ||||
|             } | ||||
|             this.DEFAULT_MODE = DEFAULT_MODE; | ||||
|             var options = this.optionsFromConfig(config); | ||||
|             this.menu = { | ||||
|                 selected: options[0], | ||||
|                 options: options | ||||
|             }; | ||||
|  | ||||
|             // Construct the provided time system definitions | ||||
|             this.timeSystems = conductorViewService.systems; | ||||
|             this.timeSystems = config.menuOptions.map(function (menuOption){ | ||||
|                 return openmct.time.getTimeSystem(menuOption.timeSystem); | ||||
|             }); | ||||
|  | ||||
|             this.initializeScope(); | ||||
|             var searchParams = JSON.parse(JSON.stringify(this.$location.search())); | ||||
| @@ -84,9 +86,9 @@ define( | ||||
|             this.setStateFromSearchParams(searchParams); | ||||
|  | ||||
|             //Set the initial state of the UI from the conductor state | ||||
|             var timeSystem = this.conductor.timeSystem(); | ||||
|             var timeSystem = this.timeAPI.timeSystem(); | ||||
|             if (timeSystem) { | ||||
|                 this.changeTimeSystem(this.conductor.timeSystem()); | ||||
|                 this.changeTimeSystem(timeSystem); | ||||
|             } | ||||
|  | ||||
|             var deltas = this.conductorViewService.deltas(); | ||||
| @@ -94,7 +96,7 @@ define( | ||||
|                 this.setFormFromDeltas(deltas); | ||||
|             } | ||||
|  | ||||
|             var bounds = this.conductor.bounds(); | ||||
|             var bounds = this.timeAPI.bounds(); | ||||
|             if (bounds && bounds.start !== undefined && bounds.end !== undefined) { | ||||
|                 this.changeBounds(bounds); | ||||
|             } | ||||
| @@ -105,12 +107,31 @@ define( | ||||
|             }.bind(this)); | ||||
|  | ||||
|             //Respond to any subsequent conductor changes | ||||
|             this.conductor.on('bounds', this.changeBounds); | ||||
|             this.conductor.on('timeSystem', this.changeTimeSystem); | ||||
|  | ||||
|             this.$scope.showTimeConductor = SHOW_TIMECONDUCTOR; | ||||
|             this.timeAPI.on('bounds', this.changeBounds); | ||||
|             this.timeAPI.on('timeSystem', this.changeTimeSystem); | ||||
|         } | ||||
|  | ||||
|         TimeConductorController.prototype.optionsFromConfig = function (config) { | ||||
|             var options = [{ | ||||
|                 name: 'Fixed Timespan Mode', | ||||
|                 description: 'Query and explore data that falls between two fixed datetimes', | ||||
|                 cssClass: 'icon-calendar', | ||||
|                 clock: undefined | ||||
|             }]; | ||||
|             var timeAPI = this.timeAPI; | ||||
|  | ||||
|             (config.menuOptions || []).forEach(function (menuOption) { | ||||
|                 options.push({ | ||||
|                     name: menuOption.name, | ||||
|                     description: menuOption.description, | ||||
|                     cssClass: menuOption.cssClass || '', | ||||
|                     clock: timeAPI.getClock(menuOption.clock) | ||||
|                 }); | ||||
|             }.bind(this)); | ||||
|  | ||||
|             return options; | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Used as a url search param setter in place of $location.search(...) | ||||
|          * | ||||
| @@ -129,7 +150,7 @@ define( | ||||
|          */ | ||||
|         TimeConductorController.prototype.initializeScope = function () { | ||||
|             //Set time Conductor bounds in the form | ||||
|             this.$scope.boundsModel = this.conductor.bounds(); | ||||
|             this.$scope.boundsModel = this.timeAPI.bounds(); | ||||
|  | ||||
|             //If conductor has a time system selected already, populate the | ||||
|             //form from it | ||||
| @@ -154,11 +175,11 @@ define( | ||||
|             //Set mode from url if changed | ||||
|             if (searchParams[SEARCH.MODE] === undefined || | ||||
|                 searchParams[SEARCH.MODE] !== this.$scope.modeModel.selectedKey) { | ||||
|                 this.setMode(searchParams[SEARCH.MODE] || this.DEFAULT_MODE); | ||||
|                 this.setMode(searchParams[SEARCH.MODE] || 'fixed'); | ||||
|             } | ||||
|  | ||||
|             if (searchParams[SEARCH.TIME_SYSTEM] && | ||||
|                 searchParams[SEARCH.TIME_SYSTEM] !== this.conductor.timeSystem().metadata.key) { | ||||
|                 searchParams[SEARCH.TIME_SYSTEM] !== this.timeAPI.timeSystem()) { | ||||
|                 //Will select the specified time system on the conductor | ||||
|                 this.selectTimeSystemByKey(searchParams[SEARCH.TIME_SYSTEM]); | ||||
|             } | ||||
| @@ -184,7 +205,7 @@ define( | ||||
|                 !isNaN(searchParams[SEARCH.END_BOUND]); | ||||
|  | ||||
|             if (validBounds) { | ||||
|                 this.conductor.bounds({ | ||||
|                 this.timeAPI.bounds({ | ||||
|                     start: parseInt(searchParams[SEARCH.START_BOUND]), | ||||
|                     end: parseInt(searchParams[SEARCH.END_BOUND]) | ||||
|                 }); | ||||
| @@ -195,8 +216,8 @@ define( | ||||
|          * @private | ||||
|          */ | ||||
|         TimeConductorController.prototype.destroy = function () { | ||||
|             this.conductor.off('bounds', this.changeBounds); | ||||
|             this.conductor.off('timeSystem', this.changeTimeSystem); | ||||
|             this.timeAPI.off('bounds', this.changeBounds); | ||||
|             this.timeAPI.off('timeSystem', this.changeTimeSystem); | ||||
|  | ||||
|             this.conductorViewService.off('pan', this.onPan); | ||||
|             this.conductorViewService.off('pan-stop', this.onPanStop); | ||||
| @@ -253,10 +274,7 @@ define( | ||||
|             this.$scope.modeModel.selectedKey = mode; | ||||
|             //Synchronize scope with time system on mode | ||||
|             this.$scope.timeSystemModel.options = | ||||
|                 this.conductorViewService.availableTimeSystems() | ||||
|                 .map(function (t) { | ||||
|                     return t.metadata; | ||||
|                 }); | ||||
|                 this.conductorViewService.availableTimeSystems(); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
| @@ -289,7 +307,7 @@ define( | ||||
|          * @param formModel | ||||
|          */ | ||||
|         TimeConductorController.prototype.setBounds = function (boundsModel) { | ||||
|             this.conductor.bounds({ | ||||
|             this.timeAPI.bounds({ | ||||
|                 start: boundsModel.start, | ||||
|                 end: boundsModel.end | ||||
|             }); | ||||
| @@ -364,7 +382,7 @@ define( | ||||
|             })[0]; | ||||
|             if (selected) { | ||||
|                 this.supportsZoom = !!(selected.defaults() && selected.defaults().zoom); | ||||
|                 this.conductor.timeSystem(selected, selected.defaults().bounds); | ||||
|                 this.timeAPI.timeSystem(selected, selected.defaults().bounds); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
| @@ -376,9 +394,11 @@ define( | ||||
|          * | ||||
|          * @param newTimeSystem | ||||
|          */ | ||||
|         TimeConductorController.prototype.changeTimeSystem = function (newTimeSystem) { | ||||
|         TimeConductorController.prototype.changeTimeSystem = function (key) { | ||||
|             var newTimeSystem = this.timeAPI.getTimeSystem(key); | ||||
|  | ||||
|             //Set time system in URL on change | ||||
|             this.setParam(SEARCH.TIME_SYSTEM, newTimeSystem.metadata.key); | ||||
|             this.setParam(SEARCH.TIME_SYSTEM, key); | ||||
|  | ||||
|             if (newTimeSystem && (newTimeSystem !== this.$scope.timeSystemModel.selected)) { | ||||
|                 this.supportsZoom = !!(newTimeSystem.defaults() && newTimeSystem.defaults().zoom); | ||||
| @@ -401,9 +421,9 @@ define( | ||||
|          * @returns {number} a value between 0.01 and 0.99, in increments of .01 | ||||
|          */ | ||||
|         TimeConductorController.prototype.toSliderValue = function (timeSpan) { | ||||
|             var timeSystem = this.conductor.timeSystem(); | ||||
|             var timeSystem = this.timeAPI.getTimeSystem(this.timeAPI.timeSystem()); | ||||
|             if (timeSystem) { | ||||
|                 var zoomDefaults = this.conductor.timeSystem().defaults().zoom; | ||||
|                 var zoomDefaults = timeSystem.defaults().zoom; | ||||
|                 var perc = timeSpan / (zoomDefaults.min - zoomDefaults.max); | ||||
|                 return 1 - Math.pow(perc, 1 / 4); | ||||
|             } | ||||
| @@ -415,8 +435,9 @@ define( | ||||
|          * @param {TimeSpan} timeSpan | ||||
|          */ | ||||
|         TimeConductorController.prototype.toTimeUnits = function (timeSpan) { | ||||
|             if (this.conductor.timeSystem()) { | ||||
|                 var timeFormat = this.formatService.getFormat(this.conductor.timeSystem().formats()[0]); | ||||
|             var timeSystem = this.timeAPI.getTimeSystem(this.timeAPI.timeSystem()); | ||||
|             if (this.timeAPI.timeSystem()) { | ||||
|                 var timeFormat = this.formatService.getFormat(timeSystem.formats()[0]); | ||||
|                 this.$scope.timeUnits = timeFormat.timeUnits && timeFormat.timeUnits(timeSpan); | ||||
|             } | ||||
|         }; | ||||
| @@ -429,7 +450,8 @@ define( | ||||
|          * @param bounds | ||||
|          */ | ||||
|         TimeConductorController.prototype.onZoom = function (sliderValue) { | ||||
|             var zoomDefaults = this.conductor.timeSystem().defaults().zoom; | ||||
|             var timeSystem = this.timeAPI.getTimeSystem(this.timeAPI.timeSystem()); | ||||
|             var zoomDefaults = timeSystem.defaults().zoom; | ||||
|             var timeSpan = Math.pow((1 - sliderValue), 4) * (zoomDefaults.min - zoomDefaults.max); | ||||
|  | ||||
|             var zoom = this.conductorViewService.zoom(timeSpan); | ||||
|   | ||||
| @@ -31,38 +31,23 @@ define( | ||||
|          * @memberof platform.features.conductor | ||||
|          * @param {TimeConductorMetadata} metadata | ||||
|          */ | ||||
|         function TimeConductorMode(metadata, conductor, timeSystems) { | ||||
|             this.conductor = conductor; | ||||
|         function TimeConductorMode(metadata, timeAPI) { | ||||
|             this.timeAPI = timeAPI; | ||||
|  | ||||
|             this.mdata = metadata; | ||||
|             this.deltasVal = undefined; | ||||
|             this.source = undefined; | ||||
|             this.sourceUnlisten = undefined; | ||||
|             this.systems = timeSystems; | ||||
|             this.availableSources = undefined; | ||||
|             this.changeTimeSystem = this.changeTimeSystem.bind(this); | ||||
|             this.tick = this.tick.bind(this); | ||||
|  | ||||
|             var timeSystem = this.timeAPI.timeSystem(); | ||||
|  | ||||
|             //Set the time system initially | ||||
|             if (conductor.timeSystem()) { | ||||
|                 this.changeTimeSystem(conductor.timeSystem()); | ||||
|             if (timeSystem) { | ||||
|                 this.changeTimeSystem(timeSystem); | ||||
|             } | ||||
|  | ||||
|             //Listen for subsequent changes to time system | ||||
|             conductor.on('timeSystem', this.changeTimeSystem); | ||||
|             timeAPI.on('timeSystem', this.changeTimeSystem); | ||||
|  | ||||
|             if (metadata.key === 'fixed') { | ||||
|                 //Fixed automatically supports all time systems | ||||
|                 this.availableSystems = timeSystems; | ||||
|             } else { | ||||
|                 this.availableSystems = timeSystems.filter(function (timeSystem) { | ||||
|                     //Only include time systems that have tick sources that | ||||
|                     // support the current mode | ||||
|                     return timeSystem.tickSources().some(function (tickSource) { | ||||
|                         return metadata.key === tickSource.metadata.mode; | ||||
|                     }); | ||||
|                 }); | ||||
|             } | ||||
|             this.availableSystems = timeAPI.availableTimeSystems(); | ||||
|         } | ||||
|  | ||||
|         /** | ||||
| @@ -70,7 +55,8 @@ define( | ||||
|          * @param timeSystem | ||||
|          * @returns {TimeSystem} the currently selected time system | ||||
|          */ | ||||
|         TimeConductorMode.prototype.changeTimeSystem = function (timeSystem) { | ||||
|         TimeConductorMode.prototype.changeTimeSystem = function (key) { | ||||
|             var timeSystem = this.timeAPI.getTimeSystem(key); | ||||
|             // On time system change, apply default deltas | ||||
|             var defaults = timeSystem.defaults() || { | ||||
|                     bounds: { | ||||
| @@ -83,20 +69,8 @@ define( | ||||
|                     } | ||||
|                 }; | ||||
|  | ||||
|             this.conductor.bounds(defaults.bounds); | ||||
|             this.timeAPI.bounds(defaults.bounds); | ||||
|             this.deltas(defaults.deltas); | ||||
|  | ||||
|             // Tick sources are mode-specific, so restrict tick sources to only those supported by the current mode. | ||||
|             var key = this.mdata.key; | ||||
|             var tickSources = timeSystem.tickSources(); | ||||
|             if (tickSources) { | ||||
|                 this.availableSources = tickSources.filter(function (source) { | ||||
|                     return source.metadata.mode === key; | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             // Set an appropriate tick source from the new time system | ||||
|             this.tickSource(this.availableTickSources(timeSystem)[0]); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
| @@ -110,15 +84,6 @@ define( | ||||
|             return this.availableSystems; | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Tick sources are mode-specific. This returns a filtered list of the tick sources available in the currently selected mode | ||||
|          * @param timeSystem | ||||
|          * @returns {Array.<T>} | ||||
|          */ | ||||
|         TimeConductorMode.prototype.availableTickSources = function (timeSystem) { | ||||
|             return this.availableSources; | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Get or set tick source. Setting tick source will also start | ||||
|          * listening to it and unlisten from any existing tick source | ||||
| @@ -127,49 +92,28 @@ define( | ||||
|          */ | ||||
|         TimeConductorMode.prototype.tickSource = function (tickSource) { | ||||
|             if (arguments.length > 0) { | ||||
|                 if (this.sourceUnlisten) { | ||||
|                     this.sourceUnlisten(); | ||||
|                 } | ||||
|                 this.source = tickSource; | ||||
|                 if (tickSource) { | ||||
|                     this.sourceUnlisten = tickSource.listen(this.tick); | ||||
|                     //Now following a tick source | ||||
|                     this.conductor.follow(true); | ||||
|                 } else { | ||||
|                     this.conductor.follow(false); | ||||
|                 } | ||||
|                 var timeSystem = this.timeAPI.getTimeSystem(this.timeAPI.timeSystem()); | ||||
|                 var defaults = timeSystem.defaults() || { | ||||
|                         bounds: { | ||||
|                             start: 0, | ||||
|                             end: 0 | ||||
|                         }, | ||||
|                         deltas: { | ||||
|                             start: 0, | ||||
|                             end: 0 | ||||
|                         } | ||||
|                     }; | ||||
|  | ||||
|                 this.timeAPI.tickSource(tickSource, defaults.deltas); | ||||
|             } | ||||
|             return this.source; | ||||
|             return this.timeAPI.tickSource(); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * @private | ||||
|          */ | ||||
|         TimeConductorMode.prototype.destroy = function () { | ||||
|             this.conductor.off('timeSystem', this.changeTimeSystem); | ||||
|  | ||||
|             if (this.sourceUnlisten) { | ||||
|                 this.sourceUnlisten(); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * @private | ||||
|          * @param {number} time some value that is valid in the current TimeSystem | ||||
|          */ | ||||
|         TimeConductorMode.prototype.tick = function (time) { | ||||
|             var deltas = this.deltas(); | ||||
|             var startTime = time; | ||||
|             var endTime = time; | ||||
|  | ||||
|             if (deltas) { | ||||
|                 startTime = time - deltas.start; | ||||
|                 endTime = time + deltas.end; | ||||
|             } | ||||
|             this.conductor.bounds({ | ||||
|                 start: startTime, | ||||
|                 end: endTime | ||||
|             }); | ||||
|             this.timeAPI.off('timeSystem', this.changeTimeSystem); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
| @@ -182,12 +126,13 @@ define( | ||||
|         TimeConductorMode.prototype.deltas = function (deltas) { | ||||
|             if (arguments.length !== 0) { | ||||
|                 var bounds = this.calculateBoundsFromDeltas(deltas); | ||||
|                 this.deltasVal = deltas; | ||||
|                 this.timeAPI.clockOffsets(deltas); | ||||
|  | ||||
|                 if (this.metadata().key !== 'fixed') { | ||||
|                     this.conductor.bounds(bounds); | ||||
|                     this.timeAPI.bounds(bounds); | ||||
|                 } | ||||
|             } | ||||
|             return this.deltasVal; | ||||
|             return this.timeAPI.clockOffsets(); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
| @@ -195,11 +140,12 @@ define( | ||||
|          * @returns {TimeConductorBounds} | ||||
|          */ | ||||
|         TimeConductorMode.prototype.calculateBoundsFromDeltas = function (deltas) { | ||||
|             var oldEnd = this.conductor.bounds().end; | ||||
|             var oldEnd = this.timeAPI.bounds().end; | ||||
|             var offsets = this.timeAPI.clockOffsets(); | ||||
|  | ||||
|             if (this.deltasVal && this.deltasVal.end !== undefined) { | ||||
|             if (offsets && offsets.end !== undefined) { | ||||
|                 //Calculate the previous raw end value (without delta) | ||||
|                 oldEnd = oldEnd - this.deltasVal.end; | ||||
|                 oldEnd = oldEnd - offsets.end; | ||||
|             } | ||||
|  | ||||
|             var bounds = { | ||||
| @@ -222,18 +168,19 @@ define( | ||||
|          */ | ||||
|         TimeConductorMode.prototype.calculateZoom = function (timeSpan) { | ||||
|             var zoom = {}; | ||||
|             var offsets; | ||||
|  | ||||
|             // If a tick source is defined, then the concept of 'now' is | ||||
|             // important. Calculate zoom based on 'now'. | ||||
|             if (this.tickSource()) { | ||||
|             if (this.timeAPI.follow()) { | ||||
|                 offsets = this.timeAPI.clockOffsets(); | ||||
|                 zoom.deltas = { | ||||
|                     start: timeSpan, | ||||
|                     end: this.deltasVal.end | ||||
|                     end: offsets.end | ||||
|                 }; | ||||
|                 zoom.bounds = this.calculateBoundsFromDeltas(zoom.deltas); | ||||
|                 // Calculate bounds based on deltas; | ||||
|             } else { | ||||
|                 var bounds = this.conductor.bounds(); | ||||
|                 var bounds = this.timeAPI.bounds(); | ||||
|                 var center = bounds.start + ((bounds.end - bounds.start)) / 2; | ||||
|                 bounds.start = center - timeSpan / 2; | ||||
|                 bounds.end = center + timeSpan / 2; | ||||
|   | ||||
| @@ -29,9 +29,9 @@ define( | ||||
|          * @param conductor | ||||
|          * @constructor | ||||
|          */ | ||||
|         function TimeConductorValidation(conductor) { | ||||
|         function TimeConductorValidation(timeAPI) { | ||||
|             var self = this; | ||||
|             this.conductor = conductor; | ||||
|             this.timeAPI = timeAPI; | ||||
|  | ||||
|             /* | ||||
|              * Bind all class functions to 'this' | ||||
| @@ -47,13 +47,13 @@ define( | ||||
|          * Validation methods below are invoked directly from controls in the TimeConductor form | ||||
|          */ | ||||
|         TimeConductorValidation.prototype.validateStart = function (start) { | ||||
|             var bounds = this.conductor.bounds(); | ||||
|             return this.conductor.validateBounds({start: start, end: bounds.end}) === true; | ||||
|             var bounds = this.timeAPI.bounds(); | ||||
|             return this.timeAPI.validateBounds({start: start, end: bounds.end}) === true; | ||||
|         }; | ||||
|  | ||||
|         TimeConductorValidation.prototype.validateEnd = function (end) { | ||||
|             var bounds = this.conductor.bounds(); | ||||
|             return this.conductor.validateBounds({start: bounds.start, end: end}) === true; | ||||
|             var bounds = this.timeAPI.bounds(); | ||||
|             return this.timeAPI.validateBounds({start: bounds.start, end: end}) === true; | ||||
|         }; | ||||
|  | ||||
|         TimeConductorValidation.prototype.validateStartDelta = function (startDelta) { | ||||
|   | ||||
| @@ -41,11 +41,7 @@ define( | ||||
|  | ||||
|             EventEmitter.call(this); | ||||
|  | ||||
|             this.systems = timeSystems.map(function (timeSystemConstructor) { | ||||
|                 return timeSystemConstructor(); | ||||
|             }); | ||||
|  | ||||
|             this.conductor = openmct.conductor; | ||||
|             this.timeAPI = openmct.time; | ||||
|             this.currentMode = undefined; | ||||
|  | ||||
|             /** | ||||
| @@ -67,39 +63,25 @@ define( | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             function hasTickSource(sourceType, timeSystem) { | ||||
|                 return timeSystem.tickSources().some(function (tickSource) { | ||||
|                     return tickSource.metadata.mode === sourceType; | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             var timeSystemsForMode = function (sourceType) { | ||||
|                 return this.systems.filter(hasTickSource.bind(this, sourceType)); | ||||
|             }.bind(this); | ||||
|  | ||||
|             //Only show 'real-time mode' if appropriate time systems available | ||||
|             if (timeSystemsForMode('realtime').length > 0) { | ||||
|                 var realtimeMode = { | ||||
|                     key: 'realtime', | ||||
|                     cssClass: 'icon-clock', | ||||
|                     label: 'Real-time', | ||||
|                     name: 'Real-time Mode', | ||||
|                     description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.' | ||||
|                 }; | ||||
|                 this.availModes[realtimeMode.key] = realtimeMode; | ||||
|             } | ||||
|             var realtimeMode = { | ||||
|                 key: 'realtime', | ||||
|                 cssClass: 'icon-clock', | ||||
|                 label: 'Real-time', | ||||
|                 name: 'Real-time Mode', | ||||
|                 description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.' | ||||
|             }; | ||||
|             this.availModes[realtimeMode.key] = realtimeMode; | ||||
|  | ||||
|             //Only show 'LAD mode' if appropriate time systems available | ||||
|             if (timeSystemsForMode('lad').length > 0) { | ||||
|                 var ladMode = { | ||||
|                     key: 'lad', | ||||
|                     cssClass: 'icon-database', | ||||
|                     label: 'LAD', | ||||
|                     name: 'LAD Mode', | ||||
|                     description: 'Latest Available Data mode monitors real-time streaming data as it comes in. The Time Conductor and displays will only advance when data becomes available.' | ||||
|                 }; | ||||
|                 this.availModes[ladMode.key] = ladMode; | ||||
|             } | ||||
|             var ladMode = { | ||||
|                 key: 'lad', | ||||
|                 cssClass: 'icon-database', | ||||
|                 label: 'LAD', | ||||
|                 name: 'LAD Mode', | ||||
|                 description: 'Latest Available Data mode monitors real-time streaming data as it comes in. The Time Conductor and displays will only advance when data becomes available.' | ||||
|             }; | ||||
|             this.availModes[ladMode.key] = ladMode; | ||||
|         } | ||||
|  | ||||
|         TimeConductorViewService.prototype = Object.create(EventEmitter.prototype); | ||||
| @@ -126,25 +108,25 @@ define( | ||||
|         TimeConductorViewService.prototype.mode = function (newModeKey) { | ||||
|             function contains(timeSystems, ts) { | ||||
|                 return timeSystems.filter(function (t) { | ||||
|                         return t.metadata.key === ts.metadata.key; | ||||
|                         return t.key === ts.key; | ||||
|                     }).length > 0; | ||||
|             } | ||||
|  | ||||
|             if (arguments.length === 1) { | ||||
|                 var timeSystem = this.conductor.timeSystem(); | ||||
|                 var timeSystem = this.timeAPI.getTimeSystem(this.timeAPI.timeSystem()); | ||||
|                 var modes = this.availableModes(); | ||||
|                 var modeMetaData = modes[newModeKey]; | ||||
|  | ||||
|                 if (this.currentMode) { | ||||
|                     this.currentMode.destroy(); | ||||
|                 } | ||||
|                 this.currentMode = new TimeConductorMode(modeMetaData, this.conductor, this.systems); | ||||
|                 this.currentMode = new TimeConductorMode(modeMetaData, this.timeAPI); | ||||
|  | ||||
|                 // If no time system set on time conductor, or the currently selected time system is not available in | ||||
|                 // the new mode, default to first available time system | ||||
|                 if (!timeSystem || !contains(this.currentMode.availableTimeSystems(), timeSystem)) { | ||||
|                     timeSystem = this.currentMode.availableTimeSystems()[0]; | ||||
|                     this.conductor.timeSystem(timeSystem, timeSystem.defaults().bounds); | ||||
|                     this.timeAPI.timeSystem(timeSystem.key, timeSystem.defaults().bounds); | ||||
|                 } | ||||
|             } | ||||
|             return this.currentMode ? this.currentMode.metadata().key : undefined; | ||||
| @@ -201,7 +183,7 @@ define( | ||||
|          * mode. Time systems and tick sources are mode dependent | ||||
|          */ | ||||
|         TimeConductorViewService.prototype.availableTimeSystems = function () { | ||||
|             return this.currentMode.availableTimeSystems(); | ||||
|             return this.timeAPI.availableTimeSystems(); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|   | ||||
| @@ -31,7 +31,7 @@ define( | ||||
|          * @constructor | ||||
|          */ | ||||
|         function TimeOfInterestController($scope, openmct, formatService) { | ||||
|             this.conductor = openmct.conductor; | ||||
|             this.timeAPI = openmct.time; | ||||
|             this.formatService = formatService; | ||||
|             this.format = undefined; | ||||
|             this.toiText = undefined; | ||||
| @@ -44,11 +44,11 @@ define( | ||||
|                 this[key] = TimeOfInterestController.prototype[key].bind(this); | ||||
|             }.bind(this)); | ||||
|  | ||||
|             this.conductor.on('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.conductor.on('timeSystem', this.changeTimeSystem); | ||||
|             if (this.conductor.timeSystem()) { | ||||
|                 this.changeTimeSystem(this.conductor.timeSystem()); | ||||
|                 var toi = this.conductor.timeOfInterest(); | ||||
|             this.timeAPI.on('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.timeAPI.on('timeSystem', this.changeTimeSystem); | ||||
|             if (this.timeAPI.timeSystem()) { | ||||
|                 this.changeTimeSystem(this.timeAPI.timeSystem()); | ||||
|                 var toi = this.timeAPI.timeOfInterest(); | ||||
|                 if (toi) { | ||||
|                     this.changeTimeOfInterest(toi); | ||||
|                 } | ||||
| @@ -76,7 +76,8 @@ define( | ||||
|          * When time system is changed, update the formatter used to | ||||
|          * display the current TOI label | ||||
|          */ | ||||
|         TimeOfInterestController.prototype.changeTimeSystem = function (timeSystem) { | ||||
|         TimeOfInterestController.prototype.changeTimeSystem = function (key) { | ||||
|             var timeSystem = this.timeAPI.getTimeSystem(key); | ||||
|             this.format = this.formatService.getFormat(timeSystem.formats()[0]); | ||||
|         }; | ||||
|  | ||||
| @@ -84,8 +85,8 @@ define( | ||||
|          * @private | ||||
|          */ | ||||
|         TimeOfInterestController.prototype.destroy = function () { | ||||
|             this.conductor.off('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.conductor.off('timeSystem', this.changeTimeSystem); | ||||
|             this.timeAPI.off('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.timeAPI.off('timeSystem', this.changeTimeSystem); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
| @@ -93,7 +94,7 @@ define( | ||||
|          * Time Conductor | ||||
|          */ | ||||
|         TimeOfInterestController.prototype.dismiss = function () { | ||||
|             this.conductor.timeOfInterest(undefined); | ||||
|             this.timeAPI.timeOfInterest(undefined); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
| @@ -101,7 +102,7 @@ define( | ||||
|          * the TOI displayed in views. | ||||
|          */ | ||||
|         TimeOfInterestController.prototype.resync = function () { | ||||
|             this.conductor.timeOfInterest(this.conductor.timeOfInterest()); | ||||
|             this.timeAPI.timeOfInterest(this.timeAPI.timeOfInterest()); | ||||
|         }; | ||||
|  | ||||
|         return TimeOfInterestController; | ||||
|   | ||||
| @@ -82,7 +82,7 @@ define( | ||||
|                 lastRange, | ||||
|                 lastDomain, | ||||
|                 handle; | ||||
|             var conductor = openmct.conductor; | ||||
|             var timeAPI = openmct.time; | ||||
|  | ||||
|             // Populate the scope with axis information (specifically, options | ||||
|             // available for each axis.) | ||||
| @@ -185,7 +185,7 @@ define( | ||||
|  | ||||
|             function changeTimeOfInterest(timeOfInterest) { | ||||
|                 if (timeOfInterest !== undefined) { | ||||
|                     var bounds = conductor.bounds(); | ||||
|                     var bounds = timeAPI.bounds(); | ||||
|                     var range = bounds.end - bounds.start; | ||||
|                     $scope.toiPerc = ((timeOfInterest - bounds.start) / range) * 100; | ||||
|                     $scope.toiPinned = true; | ||||
| @@ -208,8 +208,8 @@ define( | ||||
|                 ); | ||||
|                 replot(); | ||||
|  | ||||
|                 changeTimeOfInterest(conductor.timeOfInterest()); | ||||
|                 conductor.on("timeOfInterest", changeTimeOfInterest); | ||||
|                 changeTimeOfInterest(timeAPI.timeOfInterest()); | ||||
|                 timeAPI.on("timeOfInterest", changeTimeOfInterest); | ||||
|             } | ||||
|  | ||||
|             // Release the current subscription (called when scope is destroyed) | ||||
| @@ -218,7 +218,7 @@ define( | ||||
|                     handle.unsubscribe(); | ||||
|                     handle = undefined; | ||||
|                 } | ||||
|                 conductor.off("timeOfInterest", changeTimeOfInterest); | ||||
|                 timeAPI.off("timeOfInterest", changeTimeOfInterest); | ||||
|             } | ||||
|  | ||||
|             function requery() { | ||||
| @@ -262,7 +262,7 @@ define( | ||||
|                     requery(); | ||||
|                 } | ||||
|                 self.setUnsynchedStatus($scope.domainObject, follow && self.isZoomed()); | ||||
|                 changeTimeOfInterest(conductor.timeOfInterest()); | ||||
|                 changeTimeOfInterest(timeAPI.timeOfInterest()); | ||||
|             } | ||||
|  | ||||
|             this.modeOptions = new PlotModeOptions([], subPlotFactory); | ||||
| @@ -286,11 +286,11 @@ define( | ||||
|             ]; | ||||
|  | ||||
|             //Are some initialized bounds defined? | ||||
|             var bounds = conductor.bounds(); | ||||
|             var bounds = timeAPI.bounds(); | ||||
|             if (bounds && | ||||
|                 bounds.start !== undefined && | ||||
|                 bounds.end !== undefined) { | ||||
|                 changeDisplayBounds(undefined, conductor.bounds(), conductor.follow()); | ||||
|                 changeDisplayBounds(undefined, timeAPI.bounds(), timeAPI.follow()); | ||||
|             } | ||||
|  | ||||
|             // Watch for changes to the selected axis | ||||
|   | ||||
| @@ -27,7 +27,7 @@ define( | ||||
|             this.resultsHeader = this.element.find('.mct-table>thead').first(); | ||||
|             this.sizingTableBody = this.element.find('.sizing-table>tbody').first(); | ||||
|             this.$scope.sizingRow = {}; | ||||
|             this.conductor = openmct.conductor; | ||||
|             this.timeApi = openmct.time; | ||||
|             this.toiFormatter = undefined; | ||||
|             this.formatService = formatService; | ||||
|             this.callbacks = {}; | ||||
| @@ -65,6 +65,7 @@ define( | ||||
|             this.scrollable.on('scroll', this.onScroll); | ||||
|  | ||||
|             $scope.visibleRows = []; | ||||
|             $scope.displayRows = []; | ||||
|  | ||||
|             /** | ||||
|              * Set default values for optional parameters on a given scope | ||||
| @@ -113,7 +114,7 @@ define( | ||||
|                     $scope.sortDirection = 'asc'; | ||||
|                 } | ||||
|                 self.setRows($scope.rows); | ||||
|                 self.setTimeOfInterestRow(self.conductor.timeOfInterest()); | ||||
|                 self.setTimeOfInterestRow(self.timeApi.timeOfInterest()); | ||||
|             }; | ||||
|  | ||||
|             /* | ||||
| @@ -159,13 +160,13 @@ define( | ||||
|                 if (timeColumns) { | ||||
|                     this.destroyConductorListeners(); | ||||
|  | ||||
|                     this.conductor.on('timeSystem', this.changeTimeSystem); | ||||
|                     this.conductor.on('timeOfInterest', this.changeTimeOfInterest); | ||||
|                     this.conductor.on('bounds', this.changeBounds); | ||||
|                     this.timeApi.on('timeSystem', this.changeTimeSystem); | ||||
|                     this.timeApi.on('timeOfInterest', this.changeTimeOfInterest); | ||||
|                     this.timeApi.on('bounds', this.changeBounds); | ||||
|  | ||||
|                     // If time system defined, set initially | ||||
|                     if (this.conductor.timeSystem()) { | ||||
|                         this.changeTimeSystem(this.conductor.timeSystem()); | ||||
|                     if (this.timeApi.timeSystem()) { | ||||
|                         this.changeTimeSystem(this.timeApi.timeSystem()); | ||||
|                     } | ||||
|                 } | ||||
|             }.bind(this)); | ||||
| @@ -182,13 +183,14 @@ define( | ||||
|         } | ||||
|  | ||||
|         MCTTableController.prototype.destroyConductorListeners = function () { | ||||
|             this.conductor.off('timeSystem', this.changeTimeSystem); | ||||
|             this.conductor.off('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.conductor.off('bounds', this.changeBounds); | ||||
|             this.timeApi.off('timeSystem', this.changeTimeSystem); | ||||
|             this.timeApi.off('timeOfInterest', this.changeTimeOfInterest); | ||||
|             this.timeApi.off('bounds', this.changeBounds); | ||||
|         }; | ||||
|  | ||||
|         MCTTableController.prototype.changeTimeSystem = function () { | ||||
|             var format = this.conductor.timeSystem().formats()[0]; | ||||
|             var timeSystem = this.timeApi.getTimeSystem(this.timeApi.timeSystem()); | ||||
|             var format = timeSystem.formats()[0]; | ||||
|             this.toiFormatter = this.formatService.getFormat(format); | ||||
|         }; | ||||
|  | ||||
| @@ -220,7 +222,7 @@ define( | ||||
|                         } | ||||
|                     }.bind(this)); | ||||
|  | ||||
|                 var toi = this.conductor.timeOfInterest(); | ||||
|                 var toi = this.timeApi.timeOfInterest(); | ||||
|                 if (toi !== -1) { | ||||
|                     this.setTimeOfInterestRow(toi); | ||||
|                 } | ||||
| @@ -681,7 +683,7 @@ define( | ||||
|                 // perform DOM changes, otherwise scrollTo won't work. | ||||
|                 .then(function () { | ||||
|                     //If TOI specified, scroll to it | ||||
|                     var timeOfInterest = this.conductor.timeOfInterest(); | ||||
|                     var timeOfInterest = this.timeApi.timeOfInterest(); | ||||
|                     if (timeOfInterest) { | ||||
|                         this.setTimeOfInterestRow(timeOfInterest); | ||||
|                         this.scrollToRow(this.$scope.toiRowIndex); | ||||
| @@ -779,7 +781,7 @@ define( | ||||
|          * @param bounds | ||||
|          */ | ||||
|         MCTTableController.prototype.changeBounds = function (bounds) { | ||||
|             this.setTimeOfInterestRow(this.conductor.timeOfInterest()); | ||||
|             this.setTimeOfInterestRow(this.timeApi.timeOfInterest()); | ||||
|             if (this.$scope.toiRowIndex !== -1) { | ||||
|                 this.scrollToRow(this.$scope.toiRowIndex); | ||||
|             } | ||||
| @@ -794,7 +796,7 @@ define( | ||||
|                 if (selectedTime && | ||||
|                     this.toiFormatter.validate(selectedTime) && | ||||
|                     event.altKey) { | ||||
|                     this.conductor.timeOfInterest(this.toiFormatter.parse(selectedTime)); | ||||
|                     this.timeApi.timeOfInterest(this.toiFormatter.parse(selectedTime)); | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|   | ||||
| @@ -64,7 +64,7 @@ define( | ||||
|             $scope.rows = []; | ||||
|             this.table = new TableConfiguration($scope.domainObject, | ||||
|                 openmct); | ||||
|             this.lastBounds = this.openmct.conductor.bounds(); | ||||
|             this.lastBounds = this.openmct.time.bounds(); | ||||
|             this.lastRequestTime = 0; | ||||
|             this.telemetry = new TelemetryCollection(); | ||||
|  | ||||
| @@ -95,7 +95,7 @@ define( | ||||
|                 this.registerChangeListeners(); | ||||
|             }.bind(this)); | ||||
|  | ||||
|             this.setScroll(this.openmct.conductor.follow()); | ||||
|             this.setScroll(this.openmct.time.follow()); | ||||
|  | ||||
|             this.$scope.$on("$destroy", this.destroy); | ||||
|         } | ||||
| @@ -122,7 +122,7 @@ define( | ||||
|  | ||||
|             if (timeSystem) { | ||||
|                 this.table.columns.forEach(function (column) { | ||||
|                     if (column.getKey() === timeSystem.metadata.key) { | ||||
|                     if (column.getKey() === timeSystem) { | ||||
|                         sortColumn = column; | ||||
|                     } | ||||
|                 }); | ||||
| @@ -151,9 +151,9 @@ define( | ||||
|                     }.bind(this) | ||||
|                 ); | ||||
|  | ||||
|             this.openmct.conductor.on('timeSystem', this.sortByTimeSystem); | ||||
|             this.openmct.conductor.on('bounds', this.changeBounds); | ||||
|             this.openmct.conductor.on('follow', this.setScroll); | ||||
|             this.openmct.time.on('timeSystem', this.sortByTimeSystem); | ||||
|             this.openmct.time.on('bounds', this.changeBounds); | ||||
|             this.openmct.time.on('follow', this.setScroll); | ||||
|  | ||||
|             this.telemetry.on('added', this.addRowsToTable); | ||||
|             this.telemetry.on('discarded', this.removeRowsFromTable); | ||||
| @@ -188,7 +188,7 @@ define( | ||||
|          * @param {openmct.TimeConductorBounds~TimeConductorBounds} bounds | ||||
|          */ | ||||
|         TelemetryTableController.prototype.changeBounds = function (bounds) { | ||||
|             var follow = this.openmct.conductor.follow(); | ||||
|             var follow = this.openmct.time.follow(); | ||||
|             var isTick = follow && | ||||
|                 bounds.start !== this.lastBounds.start && | ||||
|                 bounds.end !== this.lastBounds.end; | ||||
| @@ -207,9 +207,9 @@ define( | ||||
|          */ | ||||
|         TelemetryTableController.prototype.destroy = function () { | ||||
|  | ||||
|             this.openmct.conductor.off('timeSystem', this.sortByTimeSystem); | ||||
|             this.openmct.conductor.off('bounds', this.changeBounds); | ||||
|             this.openmct.conductor.off('follow', this.setScroll); | ||||
|             this.openmct.time.off('timeSystem', this.sortByTimeSystem); | ||||
|             this.openmct.time.off('bounds', this.changeBounds); | ||||
|             this.openmct.time.off('follow', this.setScroll); | ||||
|  | ||||
|             this.subscriptions.forEach(function (subscription) { | ||||
|                 subscription(); | ||||
| @@ -260,7 +260,7 @@ define( | ||||
|                 // if data matches selected time system | ||||
|                 this.telemetry.sort(undefined); | ||||
|  | ||||
|                 var timeSystem = this.openmct.conductor.timeSystem(); | ||||
|                 var timeSystem = this.openmct.time.timeSystem(); | ||||
|                 if (timeSystem) { | ||||
|                     this.sortByTimeSystem(timeSystem); | ||||
|                 } | ||||
| @@ -278,7 +278,7 @@ define( | ||||
|         TelemetryTableController.prototype.getHistoricalData = function (objects) { | ||||
|             var self = this; | ||||
|             var openmct = this.openmct; | ||||
|             var bounds = openmct.conductor.bounds(); | ||||
|             var bounds = openmct.time.bounds(); | ||||
|             var scope = this.$scope; | ||||
|             var rowData = []; | ||||
|             var processedObjects = 0; | ||||
| @@ -432,7 +432,7 @@ define( | ||||
|             var scope = this.$scope; | ||||
|  | ||||
|             this.telemetry.clear(); | ||||
|             this.telemetry.bounds(this.openmct.conductor.bounds()); | ||||
|             this.telemetry.bounds(this.openmct.time.bounds()); | ||||
|  | ||||
|             this.$scope.loading = true; | ||||
|  | ||||
|   | ||||
| @@ -163,15 +163,15 @@ define( | ||||
|             } | ||||
|  | ||||
|             if (request.start === undefined && request.end === undefined) { | ||||
|                 bounds = this.openmct.conductor.bounds(); | ||||
|                 bounds = this.openmct.time.bounds(); | ||||
|                 fullRequest.start = bounds.start; | ||||
|                 fullRequest.end = bounds.end; | ||||
|             } | ||||
|  | ||||
|             if (request.domain === undefined) { | ||||
|                 timeSystem = this.openmct.conductor.timeSystem(); | ||||
|                 timeSystem = this.openmct.time.timeSystem(); | ||||
|                 if (timeSystem !== undefined) { | ||||
|                     fullRequest.domain = timeSystem.metadata.key; | ||||
|                     fullRequest.domain = timeSystem; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|   | ||||
| @@ -83,7 +83,7 @@ define([ | ||||
|          * @memberof module:openmct.MCT# | ||||
|          * @name conductor | ||||
|          */ | ||||
|         this.conductor = new api.TimeConductor(); | ||||
|         this.time = new api.TimeAPI(); | ||||
|  | ||||
|         /** | ||||
|          * An interface for interacting with the composition of domain objects. | ||||
|   | ||||
| @@ -1,122 +0,0 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2016, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define(['./TimeConductor'], function (TimeConductor) { | ||||
|     describe("The Time Conductor", function () { | ||||
|         var tc, | ||||
|             timeSystem, | ||||
|             bounds, | ||||
|             eventListener, | ||||
|             toi, | ||||
|             follow; | ||||
|  | ||||
|         beforeEach(function () { | ||||
|             tc = new TimeConductor(); | ||||
|             timeSystem = {}; | ||||
|             bounds = {start: 0, end: 0}; | ||||
|             eventListener = jasmine.createSpy("eventListener"); | ||||
|             toi = 111; | ||||
|             follow = true; | ||||
|         }); | ||||
|  | ||||
|         it("Supports setting and querying of time of interest and and follow mode", function () { | ||||
|             expect(tc.timeOfInterest()).not.toBe(toi); | ||||
|             tc.timeOfInterest(toi); | ||||
|             expect(tc.timeOfInterest()).toBe(toi); | ||||
|  | ||||
|             expect(tc.follow()).not.toBe(follow); | ||||
|             tc.follow(follow); | ||||
|             expect(tc.follow()).toBe(follow); | ||||
|         }); | ||||
|  | ||||
|         it("Allows setting of valid bounds", function () { | ||||
|             bounds = {start: 0, end: 1}; | ||||
|             expect(tc.bounds()).not.toBe(bounds); | ||||
|             expect(tc.bounds.bind(tc, bounds)).not.toThrow(); | ||||
|             expect(tc.bounds()).toEqual(bounds); | ||||
|         }); | ||||
|  | ||||
|         it("Disallows setting of invalid bounds", function () { | ||||
|             bounds = {start: 1, end: 0}; | ||||
|             expect(tc.bounds()).not.toEqual(bounds); | ||||
|             expect(tc.bounds.bind(tc, bounds)).toThrow(); | ||||
|             expect(tc.bounds()).not.toEqual(bounds); | ||||
|  | ||||
|             bounds = {start: 1}; | ||||
|             expect(tc.bounds()).not.toEqual(bounds); | ||||
|             expect(tc.bounds.bind(tc, bounds)).toThrow(); | ||||
|             expect(tc.bounds()).not.toEqual(bounds); | ||||
|         }); | ||||
|  | ||||
|         it("Allows setting of time system with bounds", function () { | ||||
|             expect(tc.timeSystem()).not.toBe(timeSystem); | ||||
|             expect(tc.timeSystem.bind(tc, timeSystem, bounds)).not.toThrow(); | ||||
|             expect(tc.timeSystem()).toBe(timeSystem); | ||||
|         }); | ||||
|  | ||||
|         it("Disallows setting of time system without bounds", function () { | ||||
|             expect(tc.timeSystem()).not.toBe(timeSystem); | ||||
|             expect(tc.timeSystem.bind(tc, timeSystem)).toThrow(); | ||||
|             expect(tc.timeSystem()).not.toBe(timeSystem); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when time system changes", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             tc.on("timeSystem", eventListener); | ||||
|             tc.timeSystem(timeSystem, bounds); | ||||
|             expect(eventListener).toHaveBeenCalledWith(timeSystem); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when time of interest changes", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             tc.on("timeOfInterest", eventListener); | ||||
|             tc.timeOfInterest(toi); | ||||
|             expect(eventListener).toHaveBeenCalledWith(toi); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when bounds change", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             tc.on("bounds", eventListener); | ||||
|             tc.bounds(bounds); | ||||
|             expect(eventListener).toHaveBeenCalledWith(bounds); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when follow mode changes", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             tc.on("follow", eventListener); | ||||
|             tc.follow(follow); | ||||
|             expect(eventListener).toHaveBeenCalledWith(follow); | ||||
|         }); | ||||
|  | ||||
|         it("If bounds are set and TOI lies inside them, do not change TOI", function () { | ||||
|             tc.timeOfInterest(6); | ||||
|             tc.bounds({start: 1, end: 10}); | ||||
|             expect(tc.timeOfInterest()).toEqual(6); | ||||
|         }); | ||||
|  | ||||
|         it("If bounds are set and TOI lies outside them, reset TOI", function () { | ||||
|             tc.timeOfInterest(11); | ||||
|             tc.bounds({start: 1, end: 10}); | ||||
|             expect(tc.timeOfInterest()).toBeUndefined(); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -21,7 +21,7 @@ | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './TimeConductor', | ||||
|     './time/TimeAPI', | ||||
|     './objects/ObjectAPI', | ||||
|     './composition/CompositionAPI', | ||||
|     './types/TypeRegistry', | ||||
| @@ -29,7 +29,7 @@ define([ | ||||
|     './ui/GestureAPI', | ||||
|     './telemetry/TelemetryAPI' | ||||
| ], function ( | ||||
|     TimeConductor, | ||||
|     TimeAPI, | ||||
|     ObjectAPI, | ||||
|     CompositionAPI, | ||||
|     TypeRegistry, | ||||
| @@ -38,7 +38,7 @@ define([ | ||||
|     TelemetryAPI | ||||
| ) { | ||||
|     return { | ||||
|         TimeConductor: TimeConductor, | ||||
|         TimeAPI: TimeAPI, | ||||
|         ObjectAPI: ObjectAPI, | ||||
|         CompositionAPI: CompositionAPI, | ||||
|         Dialog: Dialog, | ||||
|   | ||||
| @@ -22,6 +22,8 @@ | ||||
| 
 | ||||
| define(['EventEmitter'], function (EventEmitter) { | ||||
| 
 | ||||
|     var tick; | ||||
| 
 | ||||
|     /** | ||||
|      * The public API for setting and querying time conductor state. The | ||||
|      * time conductor is the means by which the temporal bounds of a view | ||||
| @@ -35,7 +37,7 @@ define(['EventEmitter'], function (EventEmitter) { | ||||
|      * @interface | ||||
|      * @memberof module:openmct | ||||
|      */ | ||||
|     function TimeConductor() { | ||||
|     function TimeAPI() { | ||||
|         EventEmitter.call(this); | ||||
| 
 | ||||
|         //The Time System
 | ||||
| @@ -48,21 +50,68 @@ define(['EventEmitter'], function (EventEmitter) { | ||||
|             end: undefined | ||||
|         }; | ||||
| 
 | ||||
|         //Default to fixed mode
 | ||||
|         this.followMode = false; | ||||
|         this.timeSystems = new Map(); | ||||
|         this.clocks = new Map(); | ||||
|         this.activeClock = undefined; | ||||
|         this.offsets = undefined; | ||||
| 
 | ||||
|         /** | ||||
|          * Tick is not exposed via public API, even @privately to avoid misuse. | ||||
|          */ | ||||
| 
 | ||||
|         tick = function (timestamp) { | ||||
|             var newBounds = { | ||||
|                 start: timestamp + this.offsets.start, | ||||
|                 end: timestamp + this.offsets.end | ||||
|             }; | ||||
| 
 | ||||
|             this.boundsVal = newBounds; | ||||
|             this.emit('bounds', this.boundsVal, true); | ||||
| 
 | ||||
|             // If a bounds change results in a TOI outside of the current
 | ||||
|             // bounds, unset it
 | ||||
|             if (this.toi < newBounds.start || this.toi > newBounds.end) { | ||||
|                 this.timeOfInterest(undefined); | ||||
|             } | ||||
|         }.bind(this); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     TimeConductor.prototype = Object.create(EventEmitter.prototype); | ||||
|     TimeAPI.prototype = Object.create(EventEmitter.prototype); | ||||
| 
 | ||||
|     TimeAPI.prototype.addTimeSystem = function (timeSystem) { | ||||
|         this.timeSystems.set(timeSystem.key, timeSystem); | ||||
|     }; | ||||
| 
 | ||||
|     TimeAPI.prototype.availableTimeSystems = function (key) { | ||||
|         return Array.from(this.timeSystems.values()); | ||||
|     } | ||||
| 
 | ||||
|     TimeAPI.prototype.getTimeSystem = function (key) { | ||||
|         return this.timeSystems.get(key); | ||||
|     }; | ||||
| 
 | ||||
|     TimeAPI.prototype.addClock = function (clock) { | ||||
|         this.clocks.set(clock.key, clock); | ||||
|     }; | ||||
| 
 | ||||
|     TimeAPI.prototype.getClock = function (key) { | ||||
|         return this.clocks.get(key); | ||||
|     }; | ||||
| 
 | ||||
|     TimeAPI.prototype.availableClocks = function (key) { | ||||
|         return Array.from(this.availableClocks.values()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Validate the given bounds. This can be used for pre-validation of | ||||
|      * bounds, for example by views validating user inputs. | ||||
|      * @param bounds The start and end time of the conductor. | ||||
|      * @returns {string | true} A validation error, or true if valid | ||||
|      * @memberof module:openmct.TimeConductor# | ||||
|      * @memberof module:openmct.TimeAPI# | ||||
|      * @method validateBounds | ||||
|      */ | ||||
|     TimeConductor.prototype.validateBounds = function (bounds) { | ||||
|     TimeAPI.prototype.validateBounds = function (bounds) { | ||||
|         if ((bounds.start === undefined) || | ||||
|             (bounds.end === undefined) || | ||||
|             isNaN(bounds.start) || | ||||
| @@ -75,51 +124,25 @@ define(['EventEmitter'], function (EventEmitter) { | ||||
|         return true; | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
|      * Get or set the follow mode of the time conductor. In follow mode the | ||||
|      * time conductor ticks, regularly updating the bounds from a timing | ||||
|      * source appropriate to the selected time system and mode of the time | ||||
|      * conductor. | ||||
|      * @fires module:openmct.TimeConductor~follow | ||||
|      * @param {boolean} followMode | ||||
|      * @returns {boolean} | ||||
|      * @memberof module:openmct.TimeConductor# | ||||
|      * @method follow | ||||
|      */ | ||||
|     TimeConductor.prototype.follow = function (followMode) { | ||||
|         if (arguments.length > 0) { | ||||
|             this.followMode = followMode; | ||||
|             /** | ||||
|              * The TimeConductor has toggled into or out of follow mode. | ||||
|              * @event follow | ||||
|              * @memberof module:openmct.TimeConductor~ | ||||
|              * @property {boolean} followMode true if follow mode is | ||||
|              *           enabled, otherwise false. | ||||
|              */ | ||||
|             this.emit('follow', this.followMode); | ||||
|         } | ||||
|         return this.followMode; | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
|      * @typedef {Object} TimeConductorBounds | ||||
|      * @property {number} start The start time displayed by the time conductor in ms since epoch. Epoch determined by current time system | ||||
|      * @property {number} end The end time displayed by the time conductor in ms since epoch. | ||||
|      * @memberof module:openmct.TimeConductor~ | ||||
|      * @memberof module:openmct.TimeAPI~ | ||||
|      */ | ||||
| 
 | ||||
|     /** | ||||
|      * Get or set the start and end time of the time conductor. Basic validation | ||||
|      * of bounds is performed. | ||||
|      * | ||||
|      * @param {module:openmct.TimeConductorBounds~TimeConductorBounds} newBounds | ||||
|      * @param {module:openmct.TimeAPI~TimeConductorBounds} newBounds | ||||
|      * @throws {Error} Validation error | ||||
|      * @fires module:openmct.TimeConductor~bounds | ||||
|      * @returns {module:openmct.TimeConductorBounds~TimeConductorBounds} | ||||
|      * @memberof module:openmct.TimeConductor# | ||||
|      * @fires module:openmct.TimeAPI~bounds | ||||
|      * @returns {module:openmct.TimeAPI~TimeConductorBounds} | ||||
|      * @memberof module:openmct.TimeAPI# | ||||
|      * @method bounds | ||||
|      */ | ||||
|     TimeConductor.prototype.bounds = function (newBounds) { | ||||
|     TimeAPI.prototype.bounds = function (newBounds) { | ||||
|         if (arguments.length > 0) { | ||||
|             var validationResult = this.validateBounds(newBounds); | ||||
|             if (validationResult !== true) { | ||||
| @@ -130,10 +153,12 @@ define(['EventEmitter'], function (EventEmitter) { | ||||
|             /** | ||||
|              * The start time, end time, or both have been updated. | ||||
|              * @event bounds | ||||
|              * @memberof module:openmct.TimeConductor~ | ||||
|              * @property {TimeConductorBounds} bounds | ||||
|              * @memberof module:openmct.TimeAPI~ | ||||
|              * @property {TimeConductorBounds} bounds The newly updated bounds | ||||
|              * @property {boolean} [tick] `true` if the bounds update was due to | ||||
|              * a "tick" event (ie. was an automatic update), false otherwise. | ||||
|              */ | ||||
|             this.emit('bounds', this.boundsVal); | ||||
|             this.emit('bounds', this.boundsVal, false); | ||||
| 
 | ||||
|             // If a bounds change results in a TOI outside of the current
 | ||||
|             // bounds, unset it
 | ||||
| @@ -146,34 +171,40 @@ define(['EventEmitter'], function (EventEmitter) { | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
|      * Get or set the time system of the TimeConductor. Time systems determine | ||||
|      * Get or set the time system of the TimeAPI. Time systems determine | ||||
|      * units, epoch, and other aspects of time representation. When changing | ||||
|      * the time system in use, new valid bounds must also be provided. | ||||
|      * @param {TimeSystem} newTimeSystem | ||||
|      * @param {module:openmct.TimeConductor~TimeConductorBounds} bounds | ||||
|      * @fires module:openmct.TimeConductor~timeSystem | ||||
|      * @param {module:openmct.TimeAPI~TimeConductorBounds} bounds | ||||
|      * @fires module:openmct.TimeAPI~timeSystem | ||||
|      * @returns {TimeSystem} The currently applied time system | ||||
|      * @memberof module:openmct.TimeConductor# | ||||
|      * @memberof module:openmct.TimeAPI# | ||||
|      * @method timeSystem | ||||
|      */ | ||||
|     TimeConductor.prototype.timeSystem = function (newTimeSystem, bounds) { | ||||
|     TimeAPI.prototype.timeSystem = function (newTimeSystem, bounds) { | ||||
|         if (arguments.length >= 2) { | ||||
|             this.system = newTimeSystem; | ||||
|             if (newTimeSystem === 'undefined') { | ||||
|                 throw "Please provide a time system"; | ||||
|             } | ||||
|             if (this.timeSystems.get(newTimeSystem) === undefined){ | ||||
|                 throw "Unknown time system " + newTimeSystem + ". Has it been registered with 'addTimeSystem'?"; | ||||
|             } | ||||
|             this.system = this.timeSystems.get(newTimeSystem); | ||||
|             /** | ||||
|              * The time system used by the time | ||||
|              * conductor has changed. A change in Time System will always be | ||||
|              * followed by a bounds event specifying new query bounds. | ||||
|              * | ||||
|              * @event module:openmct.TimeConductor~timeSystem | ||||
|              * @event module:openmct.TimeAPI~timeSystem | ||||
|              * @property {TimeSystem} The value of the currently applied | ||||
|              * Time System | ||||
|              * */ | ||||
|             this.emit('timeSystem', this.system); | ||||
|             this.emit('timeSystem', this.system.key); | ||||
|             this.bounds(bounds); | ||||
|         } else if (arguments.length === 1) { | ||||
|             throw new Error('Must set bounds when changing time system'); | ||||
|         } | ||||
|         return this.system; | ||||
|         return this.system && this.system.key; | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
| @@ -181,19 +212,19 @@ define(['EventEmitter'], function (EventEmitter) { | ||||
|      * focus of the current view. It can be manipulated by the user from the | ||||
|      * time conductor or from other views.The time of interest can | ||||
|      * effectively be unset by assigning a value of 'undefined'. | ||||
|      * @fires module:openmct.TimeConductor~timeOfInterest | ||||
|      * @fires module:openmct.TimeAPI~timeOfInterest | ||||
|      * @param newTOI | ||||
|      * @returns {number} the current time of interest | ||||
|      * @memberof module:openmct.TimeConductor# | ||||
|      * @memberof module:openmct.TimeAPI# | ||||
|      * @method timeOfInterest | ||||
|      */ | ||||
|     TimeConductor.prototype.timeOfInterest = function (newTOI) { | ||||
|     TimeAPI.prototype.timeOfInterest = function (newTOI) { | ||||
|         if (arguments.length > 0) { | ||||
|             this.toi = newTOI; | ||||
|             /** | ||||
|              * The Time of Interest has moved. | ||||
|              * @event timeOfInterest | ||||
|              * @memberof module:openmct.TimeConductor~ | ||||
|              * @memberof module:openmct.TimeAPI~ | ||||
|              * @property {number} Current time of interest | ||||
|              */ | ||||
|             this.emit('timeOfInterest', this.toi); | ||||
| @@ -201,5 +232,63 @@ define(['EventEmitter'], function (EventEmitter) { | ||||
|         return this.toi; | ||||
|     }; | ||||
| 
 | ||||
|     return TimeConductor; | ||||
|     /** | ||||
|      * Return the follow state of the Conductor. | ||||
|      * @returns {boolean} `true` if conductor is currently following a tick source. | ||||
|      * `false` otherwise. | ||||
|      */ | ||||
|     TimeAPI.prototype.follow = function () { | ||||
|         return this.activeClock !== undefined; | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
|      * Set the active clock. Tick source will be immediately subscribed to | ||||
|      * and ticking will begin. Offsets from 'now' must also be provided. | ||||
|      * @param {string} key the key of the tick source to activate | ||||
|      * @param {ClockOffsets} offsets on each tick these will be used to calculate | ||||
|      * the start and end bounds. This maintains a sliding time window of a fixed | ||||
|      * width that automatically updates. | ||||
|      */ | ||||
|     TimeAPI.prototype.clock = function (key, offsets) { | ||||
|         if (arguments.length === 2) { | ||||
|             if (!this.clocks.has(key)){ | ||||
|                 throw "Unknown clock '" + key + "'. Has it been registered with 'addClock'?"; | ||||
|             } | ||||
|             if (this.activeClock !== undefined) { | ||||
|                 this.activeClock.off("tick", tick); | ||||
|             } else { | ||||
|                 this.emit("follow", true); | ||||
|             } | ||||
|             if (key !== undefined) { | ||||
|                 this.activeClock = this.clocks.get(key); | ||||
|                 this.offsets = offsets; | ||||
|                 this.activeClock.on("tick", tick); | ||||
|             } else { | ||||
|                 this.activeClock = undefined; | ||||
|                 this.emit("follow", false); | ||||
|             } | ||||
|         } else if (arguments.length === 1){ | ||||
|             throw "When setting clock, clock offsets must also be provided" | ||||
|         } | ||||
| 
 | ||||
|         return this.activeClock && this.activeClock.key; | ||||
|     }; | ||||
| 
 | ||||
|     TimeAPI.prototype.clockOffsets = function (offsets) { | ||||
|         if (arguments.length > 0) { | ||||
|             this.offsets = offsets; | ||||
|             this.emit("clockOffsets", offsets); | ||||
|         } | ||||
|         // TODO: Should setting clock offsets trigger a bounds event, or wait until next tick?
 | ||||
|         return this.offsets; | ||||
|     }; | ||||
| 
 | ||||
|     TimeAPI.prototype.stopClock = function () { | ||||
|         if (this.activeClock) { | ||||
|             this.activeClock.off("tick", tick); | ||||
|             this.activeClock = undefined; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     return TimeAPI; | ||||
| }); | ||||
							
								
								
									
										216
									
								
								src/api/time/TimeAPISpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								src/api/time/TimeAPISpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2016, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define(['./TimeAPI'], function (TimeAPI) { | ||||
|     describe("The Time API", function () { | ||||
|         var api, | ||||
|             timeSystemKey, | ||||
|             timeSystem, | ||||
|             bounds, | ||||
|             eventListener, | ||||
|             toi, | ||||
|             follow; | ||||
|  | ||||
|         beforeEach(function () { | ||||
|             api = new TimeAPI(); | ||||
|             timeSystemKey = "timeSystemKey"; | ||||
|             timeSystem = {key: timeSystemKey}; | ||||
|             bounds = {start: 0, end: 0}; | ||||
|             eventListener = jasmine.createSpy("eventListener"); | ||||
|             toi = 111; | ||||
|             follow = true; | ||||
|         }); | ||||
|  | ||||
|         it("Supports setting and querying of time of interest", function () { | ||||
|             expect(api.timeOfInterest()).not.toBe(toi); | ||||
|             api.timeOfInterest(toi); | ||||
|             expect(api.timeOfInterest()).toBe(toi); | ||||
|         }); | ||||
|  | ||||
|         it("Allows setting of valid bounds", function () { | ||||
|             bounds = {start: 0, end: 1}; | ||||
|             expect(api.bounds()).not.toBe(bounds); | ||||
|             expect(api.bounds.bind(api, bounds)).not.toThrow(); | ||||
|             expect(api.bounds()).toEqual(bounds); | ||||
|         }); | ||||
|  | ||||
|         it("Disallows setting of invalid bounds", function () { | ||||
|             bounds = {start: 1, end: 0}; | ||||
|             expect(api.bounds()).not.toEqual(bounds); | ||||
|             expect(api.bounds.bind(api, bounds)).toThrow(); | ||||
|             expect(api.bounds()).not.toEqual(bounds); | ||||
|  | ||||
|             bounds = {start: 1}; | ||||
|             expect(api.bounds()).not.toEqual(bounds); | ||||
|             expect(api.bounds.bind(api, bounds)).toThrow(); | ||||
|             expect(api.bounds()).not.toEqual(bounds); | ||||
|         }); | ||||
|  | ||||
|         it("Allows setting of previously registered time system with bounds", function () { | ||||
|             api.addTimeSystem(timeSystem); | ||||
|             expect(api.timeSystem()).not.toBe(timeSystemKey); | ||||
|             expect(function() { | ||||
|                 api.timeSystem(timeSystemKey, bounds); | ||||
|             }).not.toThrow(); | ||||
|             expect(api.timeSystem()).toBe(timeSystemKey); | ||||
|         }); | ||||
|  | ||||
|         it("Disallows setting of time system without bounds", function () { | ||||
|             api.addTimeSystem(timeSystem); | ||||
|             expect(api.timeSystem()).not.toBe(timeSystemKey); | ||||
|             expect(function () { | ||||
|                 api.timeSystem(timeSystemKey) | ||||
|             }).toThrow(); | ||||
|             expect(api.timeSystem()).not.toBe(timeSystemKey); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when time system changes", function () { | ||||
|             api.addTimeSystem(timeSystem); | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             api.on("timeSystem", eventListener); | ||||
|             api.timeSystem(timeSystemKey, bounds); | ||||
|             expect(eventListener).toHaveBeenCalledWith(timeSystemKey); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when time of interest changes", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             api.on("timeOfInterest", eventListener); | ||||
|             api.timeOfInterest(toi); | ||||
|             expect(eventListener).toHaveBeenCalledWith(toi); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when bounds change", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             api.on("bounds", eventListener); | ||||
|             api.bounds(bounds); | ||||
|             expect(eventListener).toHaveBeenCalledWith(bounds, false); | ||||
|         }); | ||||
|  | ||||
|         it("If bounds are set and TOI lies inside them, do not change TOI", function () { | ||||
|             api.timeOfInterest(6); | ||||
|             api.bounds({start: 1, end: 10}); | ||||
|             expect(api.timeOfInterest()).toEqual(6); | ||||
|         }); | ||||
|  | ||||
|         it("If bounds are set and TOI lies outside them, reset TOI", function () { | ||||
|             api.timeOfInterest(11); | ||||
|             api.bounds({start: 1, end: 10}); | ||||
|             expect(api.timeOfInterest()).toBeUndefined(); | ||||
|         }); | ||||
|  | ||||
|         it("Maintains delta during tick", function () { | ||||
|         }); | ||||
|  | ||||
|  | ||||
|         it("Allows registered time system to be activated", function () { | ||||
|         }); | ||||
|  | ||||
|         it("Allows a registered tick source to be activated", function () { | ||||
|             var mockTickSource = jasmine.createSpyObj("mockTickSource", [ | ||||
|                 "on", | ||||
|                 "off", | ||||
|                 "currentValue" | ||||
|             ]); | ||||
|             mockTickSource.key = 'mockTickSource' | ||||
|         }); | ||||
|  | ||||
|         describe(" when enabling a tick source", function () { | ||||
|             var mockTickSource; | ||||
|             var anotherMockTickSource; | ||||
|             var mockOffsets = { | ||||
|                 start: 0, | ||||
|                 end: 0 | ||||
|             } | ||||
|  | ||||
|             beforeEach(function () { | ||||
|                 mockTickSource = jasmine.createSpyObj("clock", [ | ||||
|                     "on", | ||||
|                     "off" | ||||
|                 ]); | ||||
|                 mockTickSource.key = "mts"; | ||||
|  | ||||
|                 anotherMockTickSource = jasmine.createSpyObj("clock", [ | ||||
|                     "on", | ||||
|                     "off" | ||||
|                 ]); | ||||
|                 anotherMockTickSource.key = "amts"; | ||||
|  | ||||
|                 api.addClock(mockTickSource); | ||||
|                 api.addClock(anotherMockTickSource); | ||||
|             }); | ||||
|  | ||||
|             it("a new tick listener is registered", function () { | ||||
|                 api.clock("mts", mockOffsets); | ||||
|                 expect(mockTickSource.on).toHaveBeenCalledWith("tick", jasmine.any(Function)); | ||||
|             }); | ||||
|  | ||||
|             it("listener of existing tick source is reregistered", function () { | ||||
|                 api.clock("mts", mockOffsets); | ||||
|                 api.clock("amts", mockOffsets); | ||||
|                 expect(mockTickSource.off).toHaveBeenCalledWith("tick", jasmine.any(Function)); | ||||
|             }); | ||||
|  | ||||
|             it("Follow correctly reflects whether the conductor is following a " + | ||||
|                 "tick source", function () { | ||||
|                 expect(api.follow()).toBe(false); | ||||
|                 api.clock("mts", mockOffsets); | ||||
|                 expect(api.follow()).toBe(true); | ||||
|                 api.stopClock(); | ||||
|                 expect(api.follow()).toBe(false); | ||||
|             }); | ||||
|  | ||||
|             it("emits an event when follow mode changes", function () { | ||||
|                 var callback = jasmine.createSpy("followCallback"); | ||||
|                 expect(api.follow()).toBe(false); | ||||
|  | ||||
|                 api.on("follow", callback); | ||||
|             }); | ||||
|  | ||||
|         }); | ||||
|  | ||||
|         it("on tick, observes deltas, and indicates tick in bounds callback", function () { | ||||
|             var mockTickSource = jasmine.createSpyObj("clock", [ | ||||
|                 "on", | ||||
|                 "off" | ||||
|             ]); | ||||
|             var tickCallback; | ||||
|             var boundsCallback = jasmine.createSpy("boundsCallback"); | ||||
|             var clockOffsets = { | ||||
|                 start: -100, | ||||
|                 end: 100 | ||||
|             }; | ||||
|             mockTickSource.key = "mts"; | ||||
|  | ||||
|             api.addClock(mockTickSource); | ||||
|             api.clock("mts", clockOffsets); | ||||
|  | ||||
|             api.on("bounds", boundsCallback); | ||||
|  | ||||
|             tickCallback = mockTickSource.on.mostRecentCall.args[1] | ||||
|             tickCallback(1000); | ||||
|             expect(boundsCallback).toHaveBeenCalledWith({ | ||||
|                 start: 900, | ||||
|                 end: 1100 | ||||
|             }, true); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -68,7 +68,6 @@ define([ | ||||
|     '../platform/features/fixed/bundle', | ||||
|     '../platform/features/conductor/core/bundle', | ||||
|     '../platform/features/conductor/compatibility/bundle', | ||||
|     '../platform/features/conductor/utcTimeSystem/bundle', | ||||
|     '../platform/features/imagery/bundle', | ||||
|     '../platform/features/layout/bundle', | ||||
|     '../platform/features/my-items/bundle', | ||||
|   | ||||
| @@ -22,7 +22,7 @@ | ||||
|  | ||||
| define([ | ||||
|     'lodash', | ||||
|     '../../platform/features/conductor/utcTimeSystem/src/UTCTimeSystem', | ||||
|     './utcTimeSystem/plugin', | ||||
|     '../../example/generator/plugin', | ||||
|     '../../platform/features/autoflow/plugin' | ||||
| ], function ( | ||||
| @@ -48,14 +48,7 @@ define([ | ||||
|         }; | ||||
|     }); | ||||
|  | ||||
|     plugins.UTCTimeSystem = function () { | ||||
|         return function (openmct) { | ||||
|             openmct.legacyExtension("timeSystems", { | ||||
|                 "implementation": UTCTimeSystem, | ||||
|                 "depends": ["$timeout"] | ||||
|             }); | ||||
|         }; | ||||
|     }; | ||||
|     plugins.UTCTimeSystem = UTCTimeSystem; | ||||
|  | ||||
|     /** | ||||
|      * A tabular view showing the latest values of multiple telemetry points at | ||||
| @@ -68,48 +61,25 @@ define([ | ||||
|      */ | ||||
|     plugins.AutoflowView = AutoflowPlugin; | ||||
|  | ||||
|     var conductorInstalled = false; | ||||
|  | ||||
|     plugins.Conductor = function (options) { | ||||
|         if (!options) { | ||||
|             options = {}; | ||||
|     plugins.Conductor = function (config) { | ||||
|         /* | ||||
|         { | ||||
|             // Default 'fixed' configuration shows last 30 mins of data. May also provide specific bounds. | ||||
|             {timeSystems: ['utc'], defaultDeltas: {start: 30 * ONE_MINUTE, end: 0}, zoomOutLimit: ONE_YEAR, zoomInLimit: ONE_MINUTE}, | ||||
|             // Some tick source driven menu options | ||||
|             {clock: 'localClock', timeSystems: ['utc'], defaultDeltas: {start: 15 * ONE_MINUTE, end: 0}, zoomOutLimit: ONE_YEAR, zoomInLimit: ONE_MINUTE}, | ||||
|             {clock: 'latestAvailable', timeSystems: ['utc'], defaultDeltas: {start: 15 * 60 * 1000, end: 0}} | ||||
|         } | ||||
|  | ||||
|         function applyDefaults(openmct, timeConductorViewService) { | ||||
|             var defaults = {}; | ||||
|             var timeSystem = timeConductorViewService.systems.find(function (ts) { | ||||
|                 return ts.metadata.key === options.defaultTimeSystem; | ||||
|             }); | ||||
|             if (timeSystem !== undefined) { | ||||
|                 openmct.conductor.timeSystem(timeSystem, defaults.bounds); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         */ | ||||
|         return function (openmct) { | ||||
|             openmct.legacyExtension('constants', { | ||||
|                 key: 'DEFAULT_TIMECONDUCTOR_MODE', | ||||
|                 value: options.showConductor ? 'fixed' : 'realtime', | ||||
|                 priority: conductorInstalled ? 'mandatory' : 'fallback' | ||||
|                 key: 'CONDUCTOR_CONFIG', | ||||
|                 value: config, | ||||
|                 priority: 'mandatory' | ||||
|             }); | ||||
|             if (options.showConductor !== undefined) { | ||||
|                 openmct.legacyExtension('constants', { | ||||
|                     key: 'SHOW_TIMECONDUCTOR', | ||||
|                     value: options.showConductor, | ||||
|                     priority: conductorInstalled ? 'mandatory' : 'fallback' | ||||
|                 }); | ||||
|             } | ||||
|             if (options.defaultTimeSystem !== undefined || options.defaultTimespan !== undefined) { | ||||
|                 openmct.legacyExtension('runs', { | ||||
|                     implementation: applyDefaults, | ||||
|                     depends: ["openmct", "timeConductorViewService"] | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             if (!conductorInstalled) { | ||||
|                 openmct.legacyRegistry.enable('platform/features/conductor/core'); | ||||
|                 openmct.legacyRegistry.enable('platform/features/conductor/compatibility'); | ||||
|             } | ||||
|             conductorInstalled = true; | ||||
|             openmct.legacyRegistry.enable('platform/features/conductor/core'); | ||||
|             openmct.legacyRegistry.enable('platform/features/conductor/compatibility'); | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|   | ||||
| @@ -20,46 +20,53 @@ | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| define(['./TickSource'], function (TickSource) { | ||||
| define(['EventEmitter'], function (EventEmitter) { | ||||
|     /** | ||||
|      * @implements TickSource | ||||
|      * @constructor | ||||
|      */ | ||||
|     function LocalClock($timeout, period) { | ||||
|         TickSource.call(this); | ||||
|     function LocalClock(period) { | ||||
|         EventEmitter.call(this); | ||||
| 
 | ||||
|         this.metadata = { | ||||
|             key: 'local', | ||||
|             mode: 'realtime', | ||||
|             cssClass: 'icon-clock', | ||||
|             label: 'Real-time', | ||||
|             name: 'Real-time Mode', | ||||
|             description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.' | ||||
|         }; | ||||
|         /* | ||||
|         Metadata fields | ||||
|          */ | ||||
|         this.key = 'local'; | ||||
|         this.mode = 'realtime'; | ||||
|         this.cssClass = 'icon-clock'; | ||||
|         this.label = 'Real-time'; | ||||
|         this.name = 'Real-time Mode'; | ||||
|         this.description = 'Monitor real-time streaming data as it comes in. The ' + | ||||
|             'Time Conductor and displays will automatically advance themselves ' + | ||||
|             'based on a UTC clock.'; | ||||
| 
 | ||||
|         this.period = period; | ||||
|         this.$timeout = $timeout; | ||||
|         this.timeoutHandle = undefined; | ||||
|     } | ||||
| 
 | ||||
|     LocalClock.prototype = Object.create(TickSource.prototype); | ||||
|     LocalClock.prototype = Object.create(EventEmitter.prototype); | ||||
| 
 | ||||
|     /** | ||||
|      * @private | ||||
|      */ | ||||
|     LocalClock.prototype.start = function () { | ||||
|         this.timeoutHandle = this.$timeout(this.tick.bind(this), this.period); | ||||
|         this.timeoutHandle = setTimeout(this.tick.bind(this), this.period); | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
|      * @private | ||||
|      */ | ||||
|     LocalClock.prototype.stop = function () { | ||||
|         if (this.timeoutHandle) { | ||||
|             this.$timeout.cancel(this.timeoutHandle); | ||||
|             clearTimeout(this.timeoutHandle); | ||||
|             this.timeoutHandle = undefined; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     LocalClock.prototype.tick = function () { | ||||
|         var now = Date.now(); | ||||
|         this.listeners.forEach(function (listener) { | ||||
|             listener(now); | ||||
|         }); | ||||
|         this.timeoutHandle = this.$timeout(this.tick.bind(this), this.period); | ||||
|         this.emit("tick", now); | ||||
|         this.timeoutHandle = setTimeout(this.tick.bind(this), this.period); | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
| @@ -69,20 +76,30 @@ define(['./TickSource'], function (TickSource) { | ||||
|      * @param listener | ||||
|      * @returns {function} a function for deregistering the provided listener | ||||
|      */ | ||||
|     LocalClock.prototype.listen = function (listener) { | ||||
|         var listeners = this.listeners; | ||||
|         listeners.push(listener); | ||||
|     LocalClock.prototype.on = function (event, listener) { | ||||
|         var result = this.on.apply(this, arguments); | ||||
| 
 | ||||
|         if (listeners.length === 1) { | ||||
|         if (this.listeners(event).length === 1) { | ||||
|             this.start(); | ||||
|         } | ||||
|         return result; | ||||
|     }; | ||||
| 
 | ||||
|         return function () { | ||||
|             listeners.splice(listeners.indexOf(listener)); | ||||
|             if (listeners.length === 0) { | ||||
|                 this.stop(); | ||||
|             } | ||||
|         }.bind(this); | ||||
|     /** | ||||
|      * Register a listener for the local clock. When it ticks, the local | ||||
|      * clock will provide the current local system time | ||||
|      * | ||||
|      * @param listener | ||||
|      * @returns {function} a function for deregistering the provided listener | ||||
|      */ | ||||
|     LocalClock.prototype.off = function (event, listener) { | ||||
|         var result = this.off.apply(this, arguments); | ||||
| 
 | ||||
|         if (this.listeners(event).length === 0) { | ||||
|             this.stop(); | ||||
|         } | ||||
| 
 | ||||
|         return result; | ||||
|     }; | ||||
| 
 | ||||
|     return LocalClock; | ||||
| @@ -20,38 +20,28 @@ | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| define([ | ||||
|     '../../core/src/timeSystems/TimeSystem', | ||||
|     '../../core/src/timeSystems/LocalClock' | ||||
| ], function (TimeSystem, LocalClock) { | ||||
|     var FIFTEEN_MINUTES = 15 * 60 * 1000, | ||||
|         DEFAULT_PERIOD = 100; | ||||
| define([], function () { | ||||
|     var FIFTEEN_MINUTES = 15 * 60 * 1000; | ||||
| 
 | ||||
|     /** | ||||
|      * This time system supports UTC dates and provides a ticking clock source. | ||||
|      * @implements TimeSystem | ||||
|      * @constructor | ||||
|      */ | ||||
|     function UTCTimeSystem($timeout) { | ||||
|         TimeSystem.call(this); | ||||
|     function UTCTimeSystem() { | ||||
| 
 | ||||
|         /** | ||||
|          * Some metadata, which will be used to identify the time system in | ||||
|          * the UI | ||||
|          * @type {{key: string, name: string, cssClass: string}} | ||||
|          */ | ||||
|         this.metadata = { | ||||
|             'key': 'utc', | ||||
|             'name': 'UTC', | ||||
|             'cssClass': 'icon-clock' | ||||
|         }; | ||||
|         this.key = 'utc'; | ||||
|         this.name = 'UTC'; | ||||
|         this.cssClass = 'icon-clock'; | ||||
| 
 | ||||
|         this.fmts = ['utc']; | ||||
|         this.sources = [new LocalClock($timeout, DEFAULT_PERIOD)]; | ||||
|     } | ||||
| 
 | ||||
|     UTCTimeSystem.prototype = Object.create(TimeSystem.prototype); | ||||
| 
 | ||||
|     UTCTimeSystem.prototype.formats = function () { | ||||
|         return this.fmts; | ||||
|     }; | ||||
| @@ -60,8 +50,8 @@ define([ | ||||
|         return 'duration'; | ||||
|     }; | ||||
| 
 | ||||
|     UTCTimeSystem.prototype.tickSources = function () { | ||||
|         return this.sources; | ||||
|     UTCTimeSystem.prototype.isUTCBased = function () { | ||||
|         return true; | ||||
|     }; | ||||
| 
 | ||||
|     UTCTimeSystem.prototype.defaults = function () { | ||||
| @@ -21,20 +21,16 @@ | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| define([ | ||||
|     "./src/UTCTimeSystem", | ||||
|     "legacyRegistry" | ||||
|     "./UTCTimeSystem", | ||||
|     "./LocalClock" | ||||
| ], function ( | ||||
|     UTCTimeSystem, | ||||
|     legacyRegistry | ||||
|     LocalClock | ||||
| ) { | ||||
|     legacyRegistry.register("platform/features/conductor/utcTimeSystem", { | ||||
|         "extensions": { | ||||
|             "timeSystems": [ | ||||
|                 { | ||||
|                     "implementation": UTCTimeSystem, | ||||
|                     "depends": ["$timeout"] | ||||
|                 } | ||||
|             ] | ||||
|     return function () { | ||||
|         return function (openmct) { | ||||
|             openmct.time.addTimeSystem(new UTCTimeSystem()); | ||||
|             openmct.time.addClock(new LocalClock()); | ||||
|         } | ||||
|     }); | ||||
|     }; | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user