Compare commits

...

7 Commits

37 changed files with 613 additions and 1255 deletions

View File

@ -1,48 +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([
"./src/LocalTimeSystem",
"./src/LocalTimeFormat",
'legacyRegistry'
], function (
LocalTimeSystem,
LocalTimeFormat,
legacyRegistry
) {
legacyRegistry.register("example/localTimeSystem", {
"extensions": {
"formats": [
{
"key": "local-format",
"implementation": LocalTimeFormat
}
],
"timeSystems": [
{
"implementation": LocalTimeSystem,
"depends": ["$timeout"]
}
]
}
});
});

View File

@ -1,43 +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(['../../../platform/features/conductor/core/src/timeSystems/LocalClock'], function (LocalClock) {
/**
* @implements TickSource
* @constructor
*/
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.'
};
}
LADTickSource.prototype = Object.create(LocalClock.prototype);
return LADTickSource;
});

View File

@ -1,112 +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([
'moment'
], function (
moment
) {
var DATE_FORMAT = "YYYY-MM-DD h:mm:ss.SSS a",
DATE_FORMATS = [
DATE_FORMAT,
"YYYY-MM-DD h:mm:ss a",
"YYYY-MM-DD h:mm a",
"YYYY-MM-DD"
];
/**
* @typedef Scale
* @property {number} min the minimum scale value, in ms
* @property {number} max the maximum scale value, in ms
*/
/**
* Formatter for UTC timestamps. Interprets numeric values as
* milliseconds since the start of 1970.
*
* @implements {Format}
* @constructor
* @memberof platform/commonUI/formats
*/
function LocalTimeFormat() {
}
/**
* Returns an appropriate time format based on the provided value and
* the threshold required.
* @private
*/
function getScaledFormat (d) {
var m = moment.utc(d);
/**
* Uses logic from d3 Time-Scales, v3 of the API. See
* https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Scales.md
*
* Licensed
*/
return [
[".SSS", function(m) { return m.milliseconds(); }],
[":ss", function(m) { return m.seconds(); }],
["hh:mma", function(m) { return m.minutes(); }],
["hha", function(m) { return m.hours(); }],
["ddd DD", function(m) {
return m.days() &&
m.date() != 1;
}],
["MMM DD", function(m) { return m.date() != 1; }],
["MMMM", function(m) {
return m.month();
}],
["YYYY", function() { return true; }]
].filter(function (row){
return row[1](m);
})[0][0];
};
/**
*
* @param value
* @param {Scale} [scale] Optionally provides context to the
* format request, allowing for scale-appropriate formatting.
* @returns {string} the formatted date
*/
LocalTimeFormat.prototype.format = function (value, scale) {
if (scale !== undefined){
var scaledFormat = getScaledFormat(value, scale);
if (scaledFormat) {
return moment.utc(value).format(scaledFormat);
}
}
return moment(value).format(DATE_FORMAT);
};
LocalTimeFormat.prototype.parse = function (text) {
return moment(text, DATE_FORMATS).valueOf();
};
LocalTimeFormat.prototype.validate = function (text) {
return moment(text, DATE_FORMATS).isValid();
};
return LocalTimeFormat;
});

View File

@ -1,79 +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([
'../../../platform/features/conductor/core/src/timeSystems/TimeSystem',
'../../../platform/features/conductor/core/src/timeSystems/LocalClock',
'./LADTickSource'
], function (TimeSystem, LocalClock, LADTickSource) {
var THIRTY_MINUTES = 30 * 60 * 1000,
DEFAULT_PERIOD = 1000;
/**
* This time system supports UTC dates and provides a ticking clock source.
* @implements TimeSystem
* @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.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;
};
LocalTimeSystem.prototype.deltaFormat = function () {
return 'duration';
};
LocalTimeSystem.prototype.tickSources = function () {
return this.sources;
};
LocalTimeSystem.prototype.defaults = function (key) {
var now = Math.ceil(Date.now() / 1000) * 1000;
return {
key: 'local-default',
name: 'Local 12 hour time system defaults',
deltas: {start: THIRTY_MINUTES, end: 0},
bounds: {start: now - THIRTY_MINUTES, end: now}
};
};
return LocalTimeSystem;
});

View File

@ -28,7 +28,13 @@
<script src="bower_components/requirejs/require.js"> <script src="bower_components/requirejs/require.js">
</script> </script>
<script> <script>
require(['openmct'], function (openmct) { require([
'openmct',
'src/plugins/conductor/plugin'
], function (
openmct,
ConductorService
) {
[ [
'example/imagery', 'example/imagery',
'example/eventGenerator' 'example/eventGenerator'
@ -40,6 +46,25 @@
openmct.install(openmct.plugins.Espresso()); openmct.install(openmct.plugins.Espresso());
openmct.install(openmct.plugins.Generator()); openmct.install(openmct.plugins.Generator());
openmct.install(openmct.plugins.UTCTimeSystem()); openmct.install(openmct.plugins.UTCTimeSystem());
/*
Will be installed by default...somehow
*/
openmct.install(ConductorService());
var ONE_MINUTE = 60 * 1000;
var ONE_YEAR = 365 * 24 * 60 * 60 * 1000;
// Will also provide a default configuration based on enabled time
// systems and tick sources.
openmct.install(openmct.plugins.Conductor({
menuOptions: [
// Default 'fixed' configuration shows last 30 mins of data. May also provide specific bounds.
{timeSystems: ['utc'], defaultOffsets: {start: 30 * ONE_MINUTE, end: 0}, zoomOutLimit: ONE_YEAR, zoomInLimit: ONE_MINUTE},
{tickSource: 'localClock', timeSystems: ['utc'], defaultOffsets: {start: 15 * ONE_MINUTE, end: 0}, zoomOut: ONE_YEAR, zoomIn: ONE_MINUTE},
{tickSource: 'latestAvailable', timeSystems: ['utc'], defaultOffsets: {start: 15 * 60 * 1000, end: 0}}
]
}));
openmct.start(); openmct.start();
}); });
</script> </script>

View File

@ -42,6 +42,7 @@ define([
"type": "provider", "type": "provider",
"implementation": FormatProvider, "implementation": FormatProvider,
"depends": [ "depends": [
"openmct",
"formats[]" "formats[]"
] ]
} }

View File

@ -89,22 +89,21 @@ define([
* @param {Array.<function(new : Format)>} format constructors, * @param {Array.<function(new : Format)>} format constructors,
* from the `formats` extension category. * from the `formats` extension category.
*/ */
function FormatProvider(formats) { function FormatProvider(openmct, formats) {
var formatMap = {}; this.telemetryAPI = openmct.telemetry;
function addToMap(Format) { function addToMap(Format) {
var key = Format.key; var key = Format.key;
if (key && !formatMap[key]) { if (key && !openmct.telemetry.getFormat(key)) {
formatMap[key] = new Format(); openmct.telemetry.addFormat(new Format());
} }
} }
formats.forEach(addToMap); formats.forEach(addToMap);
this.formatMap = formatMap;
} }
FormatProvider.prototype.getFormat = function (key) { FormatProvider.prototype.getFormat = function (key) {
var format = this.formatMap[key]; var format = this.telemetryAPI.getFormat(key);
if (!format) { if (!format) {
throw new Error("FormatProvider: No format found for " + key); throw new Error("FormatProvider: No format found for " + key);
} }

View File

@ -64,7 +64,7 @@ define([
* *
* Licensed * Licensed
*/ */
return [ var format = [
[".SSS", function (m) { [".SSS", function (m) {
return m.milliseconds(); return m.milliseconds();
}], }],
@ -93,62 +93,30 @@ define([
].filter(function (row) { ].filter(function (row) {
return row[1](momentified); return row[1](momentified);
})[0][0]; })[0][0];
if (format !== undefined) {
return moment.utc(value).format(scaledFormat);
}
} }
/** /**
* Returns a description of the current range of the time conductor's * @param {number} value The value to format.
* bounds. * @param {number} [minValue] Contextual information for scaled formatting used in linear scales such as conductor
* @param timeRange * and plot axes. Specifies the smallest number on the scale.
* @returns {*} * @param {number} [maxValue] Contextual information for scaled formatting used in linear scales such as conductor
* and plot axes. Specifies the largest number on the scale
* @param {number} [count] Contextual information for scaled formatting used in linear scales such as conductor
* and plot axes. The number of labels on the scale.
* @returns {string} the formatted date(s). If multiple values were requested, then an array of
* formatted values will be returned. Where a value could not be formatted, `undefined` will be returned at its position
* in the array.
*/ */
UTCTimeFormat.prototype.timeUnits = function (timeRange) { UTCTimeFormat.prototype.format = function (value, minValue, maxValue, count) {
var momentified = moment.duration(timeRange); if (arguments.length > 1) {
return values.map(getScaledFormat);
return [ } else {
["Decades", function (r) { return moment.utc(value).format(DATE_FORMAT) + "Z";
return r.years() > 15;
}],
["Years", function (r) {
return r.years() > 1;
}],
["Months", function (r) {
return r.years() === 1 || r.months() > 1;
}],
["Days", function (r) {
return r.months() === 1 || r.days() > 1;
}],
["Hours", function (r) {
return r.days() === 1 || r.hours() > 1;
}],
["Minutes", function (r) {
return r.hours() === 1 || r.minutes() > 1;
}],
["Seconds", function (r) {
return r.minutes() === 1 || r.seconds() > 1;
}],
["Milliseconds", function (r) {
return true;
}]
].filter(function (row) {
return row[1](momentified);
})[0][0];
};
/**
*
* @param value
* @param {Scale} [scale] Optionally provides context to the
* format request, allowing for scale-appropriate formatting.
* @returns {string} the formatted date
*/
UTCTimeFormat.prototype.format = function (value, scale) {
if (scale !== undefined) {
var scaledFormat = getScaledFormat(value, scale);
if (scaledFormat) {
return moment.utc(value).format(scaledFormat);
}
} }
return moment.utc(value).format(DATE_FORMAT) + "Z";
}; };
UTCTimeFormat.prototype.parse = function (text) { UTCTimeFormat.prototype.parse = function (text) {

View File

@ -21,7 +21,6 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
"./src/ui/TimeConductorViewService",
"./src/ui/TimeConductorController", "./src/ui/TimeConductorController",
"./src/ui/ConductorAxisController", "./src/ui/ConductorAxisController",
"./src/ui/ConductorTOIController", "./src/ui/ConductorTOIController",
@ -34,7 +33,6 @@ define([
"text!./res/templates/time-of-interest.html", "text!./res/templates/time-of-interest.html",
"legacyRegistry" "legacyRegistry"
], function ( ], function (
TimeConductorViewService,
TimeConductorController, TimeConductorController,
ConductorAxisController, ConductorAxisController,
ConductorTOIController, ConductorTOIController,
@ -50,16 +48,6 @@ define([
legacyRegistry.register("platform/features/conductor/core", { legacyRegistry.register("platform/features/conductor/core", {
"extensions": { "extensions": {
"services": [
{
"key": "timeConductorViewService",
"implementation": TimeConductorViewService,
"depends": [
"openmct",
"timeSystems[]"
]
}
],
"controllers": [ "controllers": [
{ {
"key": "TimeConductorController", "key": "TimeConductorController",
@ -69,10 +57,8 @@ define([
"$window", "$window",
"$location", "$location",
"openmct", "openmct",
"timeConductorViewService", "timeConductorService",
"formatService", "formatService"
"DEFAULT_TIMECONDUCTOR_MODE",
"SHOW_TIMECONDUCTOR"
] ]
}, },
{ {
@ -81,7 +67,7 @@ define([
"depends": [ "depends": [
"$scope", "$scope",
"openmct", "openmct",
"timeConductorViewService", "timeConductorService",
"formatService" "formatService"
] ]
}, },

View File

@ -22,19 +22,18 @@
<div class="contents"> <div class="contents">
<div class="pane left menu-items"> <div class="pane left menu-items">
<ul> <ul>
<li ng-repeat="(key, metadata) in ngModel.options" <li ng-repeat="option in ngModel.options"
ng-click="ngModel.selectedKey=key"> ng-click="ngModel.selectedKey=key">
<a ng-mouseover="ngModel.activeMetadata = metadata" <a ng-mouseover="ngModel.activeMetadata = option"
ng-mouseleave="ngModel.activeMetadata = undefined" ng-mouseleave="ngModel.activeMetadata = undefined"
class="menu-item-a {{metadata.cssClass}}"> class="menu-item-a {{ngModel.activeMetadata.cssClass}}">
{{metadata.name}} {{option.name}}
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="pane right menu-item-description"> <div class="pane right menu-item-description">
<div <div class="desc-area ui-symbol icon type-icon {{ngModel.activeMetadata.cssClass}}"></div>
class="desc-area ui-symbol icon type-icon {{ngModel.activeMetadata.cssClass}}"></div>
<div class="desc-area title"> <div class="desc-area title">
{{ngModel.activeMetadata.name}} {{ngModel.activeMetadata.name}}
</div> </div>

View File

@ -19,14 +19,13 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<span ng-controller="ClickAwayController as modeController"> <span ng-controller="ClickAwayController as sourceController">
<div class="s-menu-button" <div class="s-menu-button"
ng-click="modeController.toggle()"> ng-click="sourceController.toggle()">
<span class="title-label">{{ngModel.options[ngModel.selectedKey] <span class="title-label">{{ngModel.sources[ngModel.selectedSource].name}}</span>
.label}}</span>
</div> </div>
<div class="menu super-menu mini mode-selector-menu" <div class="menu super-menu mini mode-selector-menu"
ng-show="modeController.isActive()"> ng-show="sourceController.isActive()">
<mct-include key="'mode-menu'" <mct-include key="'mode-menu'"
ng-model="ngModel"> ng-model="ngModel">
</mct-include> </mct-include>

View File

@ -99,7 +99,7 @@
<div class="l-time-conductor-controls l-row-elem l-flex-row flex-elem"> <div class="l-time-conductor-controls l-row-elem l-flex-row flex-elem">
<mct-include <mct-include
key="'mode-selector'" key="'mode-selector'"
ng-model="modeModel" ng-model="sourceModel"
class="holder flex-elem menus-up mode-selector"> class="holder flex-elem menus-up mode-selector">
</mct-include> </mct-include>
<mct-control <mct-control

View File

@ -1,89 +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(['./TickSource'], function (TickSource) {
/**
* @implements TickSource
* @constructor
*/
function LocalClock($timeout, period) {
TickSource.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.'
};
this.period = period;
this.$timeout = $timeout;
this.timeoutHandle = undefined;
}
LocalClock.prototype = Object.create(TickSource.prototype);
LocalClock.prototype.start = function () {
this.timeoutHandle = this.$timeout(this.tick.bind(this), this.period);
};
LocalClock.prototype.stop = function () {
if (this.timeoutHandle) {
this.$timeout.cancel(this.timeoutHandle);
}
};
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);
};
/**
* 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.listen = function (listener) {
var listeners = this.listeners;
listeners.push(listener);
if (listeners.length === 1) {
this.start();
}
return function () {
listeners.splice(listeners.indexOf(listener));
if (listeners.length === 0) {
this.stop();
}
}.bind(this);
};
return LocalClock;
});

View File

@ -1,50 +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(["./LocalClock"], function (LocalClock) {
describe("The LocalClock class", function () {
var clock,
mockTimeout,
timeoutHandle = {};
beforeEach(function () {
mockTimeout = jasmine.createSpy("timeout");
mockTimeout.andReturn(timeoutHandle);
mockTimeout.cancel = jasmine.createSpy("cancel");
clock = new LocalClock(mockTimeout, 0);
clock.start();
});
it("calls listeners on tick with current time", function () {
var mockListener = jasmine.createSpy("listener");
clock.listen(mockListener);
clock.tick();
expect(mockListener).toHaveBeenCalledWith(jasmine.any(Number));
});
it("stops ticking when stop is called", function () {
clock.stop();
expect(mockTimeout.cancel).toHaveBeenCalledWith(timeoutHandle);
});
});
});

View File

@ -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;
});

View File

@ -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;
});

View File

@ -137,7 +137,7 @@ define(
ConductorAxisController.prototype.changeTimeSystem = function (timeSystem) { ConductorAxisController.prototype.changeTimeSystem = function (timeSystem) {
this.timeSystem = timeSystem; this.timeSystem = timeSystem;
var key = timeSystem.formats()[0]; var key = timeSystem.format;
if (key !== undefined) { if (key !== undefined) {
var format = this.formatService.getFormat(key); var format = this.formatService.getFormat(key);
var bounds = this.conductor.bounds(); var bounds = this.conductor.bounds();
@ -158,10 +158,7 @@ define(
if (tickValue instanceof Date) { if (tickValue instanceof Date) {
tickValue = tickValue.getTime(); tickValue = tickValue.getTime();
} }
return format.format(tickValue, { return format.format(tickValue, bounds.start, bounds.end);
min: bounds.start,
max: bounds.end
});
}); });
this.axisElement.call(this.xAxis); this.axisElement.call(this.xAxis);
} }
@ -210,7 +207,7 @@ define(
* Initiate panning via a click + drag gesture on the time conductor * Initiate panning via a click + drag gesture on the time conductor
* scale. Panning triggers a "pan" event * scale. Panning triggers a "pan" event
* @param {number} delta the offset from the original click event * @param {number} delta the offset from the original click event
* @see TimeConductorViewService# * @see TimeConductorService
* @fires platform.features.conductor.ConductorAxisController~pan * @fires platform.features.conductor.ConductorAxisController~pan
*/ */
ConductorAxisController.prototype.pan = function (delta) { ConductorAxisController.prototype.pan = function (delta) {

View File

@ -32,7 +32,7 @@ define(['./ConductorAxisController'], function (ConductorAxisController) {
controller: [ controller: [
'openmct', 'openmct',
'formatService', 'formatService',
'timeConductorViewService', 'timeConductorService',
'$scope', '$scope',
'$element', '$element',
ConductorAxisController ConductorAxisController

View File

@ -45,10 +45,8 @@ define(
$window, $window,
$location, $location,
openmct, openmct,
conductorViewService, conductorService,
formatService, formatService
DEFAULT_MODE,
SHOW_TIMECONDUCTOR
) { ) {
var self = this; var self = this;
@ -63,20 +61,14 @@ define(
this.$scope = $scope; this.$scope = $scope;
this.$window = $window; this.$window = $window;
this.$location = $location; this.$location = $location;
this.conductorViewService = conductorViewService; this.conductorService = conductorService;
this.conductor = openmct.conductor; this.conductor = openmct.conductor;
this.modes = conductorViewService.availableModes(); this.modes = conductorService.availableModes();
this.validation = new TimeConductorValidation(this.conductor); this.validation = new TimeConductorValidation(this.conductor);
this.formatService = formatService; this.formatService = formatService;
//Check if the default mode defined is actually available
if (this.modes[DEFAULT_MODE] === undefined) {
DEFAULT_MODE = 'fixed';
}
this.DEFAULT_MODE = DEFAULT_MODE;
// Construct the provided time system definitions // Construct the provided time system definitions
this.timeSystems = conductorViewService.systems; this.sourceModel.sources = conductorService.availableTickSources();
this.initializeScope(); this.initializeScope();
var searchParams = JSON.parse(JSON.stringify(this.$location.search())); var searchParams = JSON.parse(JSON.stringify(this.$location.search()));
@ -89,7 +81,7 @@ define(
this.changeTimeSystem(this.conductor.timeSystem()); this.changeTimeSystem(this.conductor.timeSystem());
} }
var deltas = this.conductorViewService.deltas(); var deltas = this.conductorService.deltas();
if (deltas) { if (deltas) {
this.setFormFromDeltas(deltas); this.setFormFromDeltas(deltas);
} }
@ -107,8 +99,6 @@ define(
//Respond to any subsequent conductor changes //Respond to any subsequent conductor changes
this.conductor.on('bounds', this.changeBounds); this.conductor.on('bounds', this.changeBounds);
this.conductor.on('timeSystem', this.changeTimeSystem); this.conductor.on('timeSystem', this.changeTimeSystem);
this.$scope.showTimeConductor = SHOW_TIMECONDUCTOR;
} }
/** /**
@ -138,14 +128,14 @@ define(
//Represents the various modes, and the currently selected mode //Represents the various modes, and the currently selected mode
//in the view //in the view
this.$scope.modeModel = { this.$scope.modeModel = {
options: this.conductorViewService.availableModes() options: this.conductorService.availableModes()
}; };
// Watch scope for selection of mode or time system by user // Watch scope for selection of mode or time system by user
this.$scope.$watch('modeModel.selectedKey', this.setMode); this.$scope.$watch('modeModel.selectedKey', this.setMode);
this.conductorViewService.on('pan', this.onPan); this.conductorService.on('pan', this.onPan);
this.conductorViewService.on('pan-stop', this.onPanStop); this.conductorService.on('pan-stop', this.onPanStop);
this.$scope.$on('$destroy', this.destroy); this.$scope.$on('$destroy', this.destroy);
}; };
@ -158,7 +148,7 @@ define(
} }
if (searchParams[SEARCH.TIME_SYSTEM] && if (searchParams[SEARCH.TIME_SYSTEM] &&
searchParams[SEARCH.TIME_SYSTEM] !== this.conductor.timeSystem().metadata.key) { searchParams[SEARCH.TIME_SYSTEM] !== this.conductor.timeSystem().key) {
//Will select the specified time system on the conductor //Will select the specified time system on the conductor
this.selectTimeSystemByKey(searchParams[SEARCH.TIME_SYSTEM]); this.selectTimeSystemByKey(searchParams[SEARCH.TIME_SYSTEM]);
} }
@ -198,8 +188,8 @@ define(
this.conductor.off('bounds', this.changeBounds); this.conductor.off('bounds', this.changeBounds);
this.conductor.off('timeSystem', this.changeTimeSystem); this.conductor.off('timeSystem', this.changeTimeSystem);
this.conductorViewService.off('pan', this.onPan); this.conductorService.off('pan', this.onPan);
this.conductorViewService.off('pan-stop', this.onPanStop); this.conductorService.off('pan-stop', this.onPanStop);
}; };
/** /**
@ -211,7 +201,7 @@ define(
//If a zoom or pan is currently in progress, do not override form values. //If a zoom or pan is currently in progress, do not override form values.
if (!this.zooming && !this.panning) { if (!this.zooming && !this.panning) {
this.setFormFromBounds(bounds); this.setFormFromBounds(bounds);
if (this.conductorViewService.mode() === 'fixed') { if (this.conductorService.mode() === 'fixed') {
//Set bounds in URL on change //Set bounds in URL on change
this.setParam(SEARCH.START_BOUND, bounds.start); this.setParam(SEARCH.START_BOUND, bounds.start);
this.setParam(SEARCH.END_BOUND, bounds.end); this.setParam(SEARCH.END_BOUND, bounds.end);
@ -244,21 +234,6 @@ define(
} }
}; };
/**
* On mode change, populate form based on time systems available
* from the selected mode.
* @param mode
*/
TimeConductorController.prototype.setFormFromMode = function (mode) {
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;
});
};
/** /**
* When the deltas change, update the values in the UI * When the deltas change, update the values in the UI
* @private * @private
@ -308,7 +283,7 @@ define(
}; };
if (this.validation.validateStartDelta(deltas.start) && this.validation.validateEndDelta(deltas.end)) { if (this.validation.validateStartDelta(deltas.start) && this.validation.validateEndDelta(deltas.end)) {
//Sychronize deltas between form and mode //Sychronize deltas between form and mode
this.conductorViewService.deltas(deltas); this.conductorService.deltas(deltas);
//Set Deltas in URL on change //Set Deltas in URL on change
this.setParam(SEARCH.START_DELTA, deltas.start); this.setParam(SEARCH.START_DELTA, deltas.start);
@ -316,39 +291,6 @@ define(
} }
}; };
/**
* Change the selected Time Conductor mode. This will call destroy
* and initialization functions on the relevant modes, setting
* default values for bound and deltas in the form.
*
* @private
* @param newModeKey
* @param oldModeKey
*/
TimeConductorController.prototype.setMode = function (newModeKey, oldModeKey) {
//Set mode in URL on change
this.setParam(SEARCH.MODE, newModeKey);
if (newModeKey !== oldModeKey) {
this.conductorViewService.mode(newModeKey);
this.setFormFromMode(newModeKey);
if (newModeKey === "fixed") {
this.setParam(SEARCH.START_DELTA, undefined);
this.setParam(SEARCH.END_DELTA, undefined);
} else {
this.setParam(SEARCH.START_BOUND, undefined);
this.setParam(SEARCH.END_BOUND, undefined);
var deltas = this.conductorViewService.deltas();
if (deltas) {
this.setParam(SEARCH.START_DELTA, deltas.start);
this.setParam(SEARCH.END_DELTA, deltas.end);
}
}
}
};
/** /**
* Respond to time system selection from UI * Respond to time system selection from UI
* *
@ -432,7 +374,7 @@ define(
var zoomDefaults = this.conductor.timeSystem().defaults().zoom; var zoomDefaults = this.conductor.timeSystem().defaults().zoom;
var timeSpan = Math.pow((1 - sliderValue), 4) * (zoomDefaults.min - zoomDefaults.max); var timeSpan = Math.pow((1 - sliderValue), 4) * (zoomDefaults.min - zoomDefaults.max);
var zoom = this.conductorViewService.zoom(timeSpan); var zoom = this.conductorService.zoom(timeSpan);
this.$scope.boundsModel.start = zoom.bounds.start; this.$scope.boundsModel.start = zoom.bounds.start;
this.$scope.boundsModel.end = zoom.bounds.end; this.$scope.boundsModel.end = zoom.bounds.end;
@ -457,7 +399,7 @@ define(
this.setDeltas(this.$scope.boundsModel); this.setDeltas(this.$scope.boundsModel);
this.zooming = false; this.zooming = false;
this.conductorViewService.emit('zoom-stop'); this.conductorService.emit('zoom-stop');
}; };
/** /**

View File

@ -153,25 +153,6 @@ define(
} }
}; };
/**
* @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
});
};
/** /**
* Get or set the current value for the deltas used by this time system. * Get or set the current value for the deltas used by this time system.
* On change, the new deltas will be used to calculate and set the * On change, the new deltas will be used to calculate and set the

View File

@ -1,229 +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(
[
'EventEmitter',
'./TimeConductorMode'
],
function (EventEmitter, TimeConductorMode) {
/**
* A class representing the state of the time conductor view. This
* exposes details of the UI that are not represented on the
* TimeConductor API itself such as modes and deltas.
*
* @memberof platform.features.conductor
* @param conductor
* @param timeSystems
* @constructor
*/
function TimeConductorViewService(openmct, timeSystems) {
EventEmitter.call(this);
this.systems = timeSystems.map(function (timeSystemConstructor) {
return timeSystemConstructor();
});
this.conductor = openmct.conductor;
this.currentMode = undefined;
/**
* @typedef {object} ModeMetadata
* @property {string} key A unique identifying key for this mode
* @property {string} cssClass The css class for the glyph
* representing this mode
* @property {string} label A short label for this mode
* @property {string} name A longer name for the mode
* @property {string} description A description of the mode
*/
this.availModes = {
'fixed': {
key: 'fixed',
cssClass: 'icon-calendar',
label: 'Fixed',
name: 'Fixed Timespan Mode',
description: 'Query and explore data that falls between two fixed datetimes.'
}
};
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;
}
//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;
}
}
TimeConductorViewService.prototype = Object.create(EventEmitter.prototype);
/**
* Getter/Setter for the Time Conductor Mode. Modes determine the
* behavior of the time conductor, especially with regards to the
* bounds and how they change with time.
*
* In fixed mode, the bounds do not change with time, but can be
* modified by the used
*
* In realtime mode, the bounds change with time. Bounds are not
* directly modifiable by the user, however deltas can be.
*
* In Latest Available Data (LAD) mode, the bounds are updated when
* data is received. As with realtime mode the
*
* @param {string} newModeKey One of 'fixed', 'realtime', or 'LAD'
* @returns {string} the current mode, one of 'fixed', 'realtime',
* or 'LAD'.
*
*/
TimeConductorViewService.prototype.mode = function (newModeKey) {
function contains(timeSystems, ts) {
return timeSystems.filter(function (t) {
return t.metadata.key === ts.metadata.key;
}).length > 0;
}
if (arguments.length === 1) {
var timeSystem = this.conductor.timeSystem();
var modes = this.availableModes();
var modeMetaData = modes[newModeKey];
if (this.currentMode) {
this.currentMode.destroy();
}
this.currentMode = new TimeConductorMode(modeMetaData, this.conductor, this.systems);
// 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);
}
}
return this.currentMode ? this.currentMode.metadata().key : undefined;
};
/**
* @typedef {object} TimeConductorDeltas
* @property {number} start Used to set the start bound of the
* TimeConductor on tick. A positive value that will be subtracted
* from the value provided by a tick source to determine the start
* bound.
* @property {number} end Used to set the end bound of the
* TimeConductor on tick. A positive value that will be added
* from the value provided by a tick source to determine the start
* bound.
*/
/**
* Deltas define the offset from the latest time value provided by
* the current tick source. Deltas are only valid in realtime or LAD
* modes.
*
* Realtime mode:
* - start: A time in ms before now which will be used to
* determine the 'start' bound on tick
* - end: A time in ms after now which will be used to determine
* the 'end' bound on tick
*
* LAD mode:
* - start: A time in ms before the timestamp of the last data
* received which will be used to determine the 'start' bound on
* tick
* - end: A time in ms after the timestamp of the last data received
* which will be used to determine the 'end' bound on tick
* @returns {TimeConductorDeltas} current value of the deltas
*/
TimeConductorViewService.prototype.deltas = function () {
//Deltas stored on mode. Use .apply to preserve arguments
return this.currentMode.deltas.apply(this.currentMode, arguments);
};
/**
* Availability of modes depends on the time systems and tick
* sources available. For example, Latest Available Data mode will
* not be available if there are no time systems and tick sources
* that support LAD mode.
* @returns {ModeMetadata[]}
*/
TimeConductorViewService.prototype.availableModes = function () {
return this.availModes;
};
/**
* Availability of time systems depends on the currently selected
* mode. Time systems and tick sources are mode dependent
*/
TimeConductorViewService.prototype.availableTimeSystems = function () {
return this.currentMode.availableTimeSystems();
};
/**
* An event to indicate that zooming is taking place
* @event platform.features.conductor.TimeConductorViewService~zoom
* @property {ZoomLevel} zoom the new zoom level.
*/
/**
* Zoom to given time span. Will fire a zoom event with new zoom
* bounds. Zoom bounds emitted in this way are considered ephemeral
* and should be overridden by any time conductor bounds events. Does
* not set bounds globally.
* @param {number} zoom A time duration in ms
* @fires platform.features.conductor.TimeConductorViewService~zoom
* @see module:openmct.TimeConductor#bounds
*/
TimeConductorViewService.prototype.zoom = function (timeSpan) {
var zoom = this.currentMode.calculateZoom(timeSpan);
this.emit("zoom", zoom);
return zoom;
};
return TimeConductorViewService;
}
);

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
define(['./TimeConductorViewService'], function (TimeConductorViewService) { define(['./TimeConductorService'], function (TimeConductorService) {
describe("The Time Conductor view service", function () { describe("The Time Conductor view service", function () {
var mockTimeConductor; var mockTimeConductor;
var basicTimeSystem; var basicTimeSystem;

View File

@ -1,40 +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([
"./src/UTCTimeSystem",
"legacyRegistry"
], function (
UTCTimeSystem,
legacyRegistry
) {
legacyRegistry.register("platform/features/conductor/utcTimeSystem", {
"extensions": {
"timeSystems": [
{
"implementation": UTCTimeSystem,
"depends": ["$timeout"]
}
]
}
});
});

View File

@ -1,90 +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([
'../../core/src/timeSystems/TimeSystem',
'../../core/src/timeSystems/LocalClock'
], function (TimeSystem, LocalClock) {
var FIFTEEN_MINUTES = 15 * 60 * 1000,
DEFAULT_PERIOD = 100;
/**
* This time system supports UTC dates and provides a ticking clock source.
* @implements TimeSystem
* @constructor
*/
function UTCTimeSystem($timeout) {
TimeSystem.call(this);
/**
* 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.fmts = ['utc'];
this.sources = [new LocalClock($timeout, DEFAULT_PERIOD)];
this.defaultValues = undefined;
}
UTCTimeSystem.prototype = Object.create(TimeSystem.prototype);
UTCTimeSystem.prototype.formats = function () {
return this.fmts;
};
UTCTimeSystem.prototype.deltaFormat = function () {
return 'duration';
};
UTCTimeSystem.prototype.tickSources = function () {
return this.sources;
};
UTCTimeSystem.prototype.defaults = function (defaults) {
if (arguments.length > 0) {
this.defaultValues = defaults;
}
if (this.defaultValues === undefined) {
var now = Math.ceil(Date.now() / 1000) * 1000;
var ONE_MINUTE = 60 * 1 * 1000;
var FIFTY_YEARS = 50 * 365 * 24 * 60 * 60 * 1000;
this.defaultValues = {
key: 'utc-default',
name: 'UTC time system defaults',
deltas: {start: FIFTEEN_MINUTES, end: 0},
bounds: {start: now - FIFTEEN_MINUTES, end: now},
zoom: {min: FIFTY_YEARS, max: ONE_MINUTE}
};
}
return this.defaultValues;
};
return UTCTimeSystem;
});

View File

@ -1,46 +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(['./UTCTimeSystem'], function (UTCTimeSystem) {
describe("The UTCTimeSystem class", function () {
var timeSystem,
mockTimeout;
beforeEach(function () {
mockTimeout = jasmine.createSpy("timeout");
timeSystem = new UTCTimeSystem(mockTimeout);
});
it("defines at least one format", function () {
expect(timeSystem.formats().length).toBeGreaterThan(0);
});
it("defines a tick source", function () {
var tickSources = timeSystem.tickSources();
expect(tickSources.length).toBeGreaterThan(0);
});
it("defines some defaults", function () {
expect(timeSystem.defaults()).toBeDefined();
});
});
});

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
'./TimeConductor', './conductor/TimeConductor',
'./objects/ObjectAPI', './objects/ObjectAPI',
'./composition/CompositionAPI', './composition/CompositionAPI',
'./types/TypeRegistry', './types/TypeRegistry',

View File

@ -50,10 +50,21 @@ define(['EventEmitter'], function (EventEmitter) {
//Default to fixed mode //Default to fixed mode
this.followMode = false; this.followMode = false;
this.timeSystems = {};
this.tickSources = {};
} }
TimeConductor.prototype = Object.create(EventEmitter.prototype); TimeConductor.prototype = Object.create(EventEmitter.prototype);
TimeConductor.prototype.addTimeSystem = function (timeSystem) {
this.timeSystems[timeSystem.key] = timeSystem;
};
TimeConductor.prototype.addTickSource = function (tickSource) {
this.tickSources[tickSource.key] = tickSource;
};
/** /**
* Validate the given bounds. This can be used for pre-validation of * Validate the given bounds. This can be used for pre-validation of
* bounds, for example by views validating user inputs. * bounds, for example by views validating user inputs.
@ -75,32 +86,6 @@ define(['EventEmitter'], function (EventEmitter) {
return true; 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 * @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} start The start time displayed by the time conductor in ms since epoch. Epoch determined by current time system

View File

@ -121,7 +121,7 @@ define([
* @memberof module:openmct.TelemetryAPI~ * @memberof module:openmct.TelemetryAPI~
*/ */
var cachedFormatService;
/** /**
* An interface for retrieving telemetry data associated with a domain * An interface for retrieving telemetry data associated with a domain
@ -138,6 +138,7 @@ define([
this.metadataCache = new WeakMap(); this.metadataCache = new WeakMap();
this.formatMapCache = new WeakMap(); this.formatMapCache = new WeakMap();
this.valueFormatterCache = new WeakMap(); this.valueFormatterCache = new WeakMap();
this.formatMap = {};
} }
/** /**
@ -281,6 +282,13 @@ define([
return _.sortByAll(options, sortKeys); return _.sortByAll(options, sortKeys);
}; };
function getFormatService() {
if (cachedFormatService === undefined) {
cachedFormatService = this.MCT.$injector.get('formatService');
}
return cachedFormatService;
}
/** /**
* Get a value formatter for a given valueMetadata. * Get a value formatter for a given valueMetadata.
* *
@ -288,12 +296,10 @@ define([
*/ */
TelemetryAPI.prototype.getValueFormatter = function (valueMetadata) { TelemetryAPI.prototype.getValueFormatter = function (valueMetadata) {
if (!this.valueFormatterCache.has(valueMetadata)) { if (!this.valueFormatterCache.has(valueMetadata)) {
if (!this.formatService) { var formatService = getFormatService.call(this);
this.formatService = this.MCT.$injector.get('formatService');
}
this.valueFormatterCache.set( this.valueFormatterCache.set(
valueMetadata, valueMetadata,
new TelemetryValueFormatter(valueMetadata, this.formatService) new TelemetryValueFormatter(valueMetadata, formatService)
); );
} }
return this.valueFormatterCache.get(valueMetadata); return this.valueFormatterCache.get(valueMetadata);
@ -334,5 +340,17 @@ define([
return this.legacyProvider.limitEvaluator.apply(this.legacyProvider, arguments); return this.legacyProvider.limitEvaluator.apply(this.legacyProvider, arguments);
}; };
TelemetryAPI.prototype.getFormat = function (formatKey) {
return this.formatMap[formatKey];
};
/**
* Register a new formatter
* @param {Format} formatter
*/
TelemetryAPI.prototype.addFormat = function (format) {
this.formatMap[format.key] = format;
};
return TelemetryAPI; return TelemetryAPI;
}); });

View File

@ -45,7 +45,6 @@ define([
'../example/scratchpad/bundle', '../example/scratchpad/bundle',
'../example/taxonomy/bundle', '../example/taxonomy/bundle',
'../example/worker/bundle', '../example/worker/bundle',
'../example/localTimeSystem/bundle',
'../platform/commonUI/about/bundle', '../platform/commonUI/about/bundle',
'../platform/commonUI/browse/bundle', '../platform/commonUI/browse/bundle',
@ -68,7 +67,6 @@ define([
'../platform/features/fixed/bundle', '../platform/features/fixed/bundle',
'../platform/features/conductor/core/bundle', '../platform/features/conductor/core/bundle',
'../platform/features/conductor/compatibility/bundle', '../platform/features/conductor/compatibility/bundle',
'../platform/features/conductor/utcTimeSystem/bundle',
'../platform/features/imagery/bundle', '../platform/features/imagery/bundle',
'../platform/features/layout/bundle', '../platform/features/layout/bundle',
'../platform/features/my-items/bundle', '../platform/features/my-items/bundle',

View File

@ -0,0 +1,170 @@
/*****************************************************************************
* 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(
[
'EventEmitter'
],
function (EventEmitter) {
/**
* A class representing the state of the time conductor view. This
* exposes details of the UI that are not represented on the
* TimeConductor API itself such as modes and deltas.
*
* @memberof platform.features.conductor
* @param conductor
* @param timeSystems
* @constructor
*/
function TimeConductorService(openmct) {
EventEmitter.call(this);
this.conductor = openmct.conductor;
}
TimeConductorService.prototype = Object.create(EventEmitter.prototype);
/**
* @private
* @param {number} time some value that is valid in the current TimeSystem
*/
TimeConductorService.prototype.tick = function (time) {
var deltas = this.deltas();
var startTime = time;
var endTime = time;
if (deltas) {
startTime = time - deltas.start;
endTime = time + deltas.end;
}
var newBounds = {
start: startTime,
end: endTime
};
this.conductor.boundsVal = newBounds;
this.conductor.emit('bounds', true);
// If a bounds change results in a TOI outside of the current
// bounds, unset it
if (this.conductor.toi < newBounds.start || this.conductor.toi > newBounds.end) {
this.conductor.timeOfInterest(undefined);
}
};
TimeConductorService.prototype.menuOptions = function (options) {
this.options = options;
};
TimeConductorService.prototype.activeTickSource = function (key) {
if (arguments.length > 0) {
if (this.activeTickSource !== undefined) {
this.activeTickSource.off('tick', this.tick);
}
var newTickSource = this.conductor.tickSource[key];
if (newTickSource) {
this.activeTickSource.on('tick', this.tick);
this.activeTickSource = newTickSource;
}
}
return this.activeTickSource;
};
/**
* @typedef {object} TimeConductorDeltas
* @property {number} start Used to set the start bound of the
* TimeConductor on tick. A positive value that will be subtracted
* from the value provided by a tick source to determine the start
* bound.
* @property {number} end Used to set the end bound of the
* TimeConductor on tick. A positive value that will be added
* from the value provided by a tick source to determine the start
* bound.
*/
/**
* Deltas define the offset from the latest time value provided by
* the current tick source. Deltas are only valid in realtime or LAD
* modes.
*
* Realtime mode:
* - start: A time in ms before now which will be used to
* determine the 'start' bound on tick
* - end: A time in ms after now which will be used to determine
* the 'end' bound on tick
*
* LAD mode:
* - start: A time in ms before the timestamp of the last data
* received which will be used to determine the 'start' bound on
* tick
* - end: A time in ms after the timestamp of the last data received
* which will be used to determine the 'end' bound on tick
* @returns {TimeConductorDeltas} current value of the deltas
*/
TimeConductorService.prototype.deltas = function () {
// Get / Set deltas
};
/**
* Availability of modes depends on the time systems and tick
* sources available. For example, Latest Available Data mode will
* not be available if there are no time systems and tick sources
* that support LAD mode.
* @returns {ModeMetadata[]}
*/
TimeConductorService.prototype.availableTickSources = function () {
var conductor = this.conductor;
//Return all tick sources
return _.uniq(this.options.map(function (option) {
return option.tickSource && conductor.tickSources(option.tickSource);
}.bind(this)));
};
TimeConductorService.prototype.availableTimeSystems = function () {
return Object.values(this.conductor.timeSystems);
};
/**
* An event to indicate that zooming is taking place
* @event platform.features.conductor.TimeConductorService~zoom
* @property {ZoomLevel} zoom the new zoom level.
*/
/**
* Zoom to given time span. Will fire a zoom event with new zoom
* bounds. Zoom bounds emitted in this way are considered ephemeral
* and should be overridden by any time conductor bounds events. Does
* not set bounds globally.
* @param {number} zoom A time duration in ms
* @fires platform.features.conductor.TimeConductorService~zoom
* @see module:openmct.TimeConductor#bounds
*/
TimeConductorService.prototype.zoom = function (timeSpan) {
var zoom = this.currentMode.calculateZoom(timeSpan);
this.emit("zoom", zoom);
return zoom;
};
return TimeConductorService;
}
);

View File

@ -0,0 +1,15 @@
define([
'./TimeConductorService'
], function (TimeConductorService) {
return function ConductorAPIPlugin() {
return function install(openmct) {
openmct.legacyExtension("services", {
"key": "timeConductorService",
"implementation": TimeConductorService,
"depends": [
"openmct"
]
});
}
}
});

View File

@ -22,7 +22,7 @@
define([ define([
'lodash', 'lodash',
'../../platform/features/conductor/utcTimeSystem/src/UTCTimeSystem', './utcTimeSystem/plugin',
'../../example/generator/plugin' '../../example/generator/plugin'
], function ( ], function (
_, _,
@ -46,65 +46,20 @@ define([
}; };
}); });
plugins.UTCTimeSystem = function () { plugins.UTCTimeSystem = UTCTimeSystem;
return function (openmct) {
openmct.legacyExtension("timeSystems", {
"implementation": UTCTimeSystem,
"depends": ["$timeout"]
});
};
};
var conductorInstalled = false;
plugins.Conductor = function (options) { plugins.Conductor = function (options) {
if (!options) { if (!options) {
options = {}; options = {};
} }
function applyDefaults(openmct, timeConductorViewService) {
var defaults = {};
var timeSystem = timeConductorViewService.systems.find(function (ts) {
return ts.metadata.key === options.defaultTimeSystem;
});
if (timeSystem !== undefined) {
defaults = timeSystem.defaults();
if (options.defaultTimespan !== undefined) {
defaults.deltas.start = options.defaultTimespan;
defaults.bounds.start = defaults.bounds.end - options.defaultTimespan;
timeSystem.defaults(defaults);
}
openmct.conductor.timeSystem(timeSystem, defaults.bounds);
}
}
return function (openmct) { return function (openmct) {
openmct.legacyExtension('constants', { openmct.legacyExtension('runs', {
key: 'DEFAULT_TIMECONDUCTOR_MODE', implementation: function applyDefaults(timeConductorService) {
value: options.showConductor ? 'fixed' : 'realtime', timeConductorService.menuOptions(options.menuOptions);
priority: conductorInstalled ? 'mandatory' : 'fallback' },
depends: ["timeConductorService"]
}); });
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;
}; };
}; };

View File

@ -0,0 +1,65 @@
/*****************************************************************************
* 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([], function () {
function LocalClock(tickPeriod) {
//Metadata
this.key = 'localClock';
this.name = 'A local time source';
this.cssClass = 'icon-clock';
//Members
this.listeners = {};
this.tickPeriod = tickPeriod;
this.tick = this.tick.bind(this);
}
LocalClock.prototype.tick = function () {
this.listeners['tick'].forEach(Date.now());
this.timeout = setTimeout(this.tick, this.tickPeriod);
};
LocalClock.prototype.on = function (event, listener) {
this.listeners[event] = this.listeners[event] || [];
this.listeners[event].push(listener);
if (timeout === undefined) {
setTimeout(this.tick, this.tickPeriod);
}
};
LocalClock.prototype.off = function (event, listener) {
if (this.listeners[event]) {
this.listeners[event] = this.listeners[event].filter(function (l) {
return l === listener;
});
var isEmpty = Object.keys(this.listeners).all(function (key){
return this.listeners[key] === undefined || this.listeners[key].length === 0
});
if (isEmpty) {
clearTimeout(this.timeout);
}
}
};
return LocalClock;
});

View File

@ -0,0 +1,131 @@
/*****************************************************************************
* 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([
'moment'
], function (
moment
) {
var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss.SSS",
DATE_FORMATS = [
DATE_FORMAT,
"YYYY-MM-DD HH:mm:ss",
"YYYY-MM-DD HH:mm",
"YYYY-MM-DD"
];
/**
* @typedef Scale
* @property {number} min the minimum scale value, in ms
* @property {number} max the maximum scale value, in ms
*/
/**
* Formatter for UTC timestamps. Interprets numeric values as
* milliseconds since the start of 1970.
*
* @implements {Format}
* @constructor
* @memberof platform/commonUI/formats
*/
function UTCTimeFormat() {
}
/**
* Returns an appropriate time format based on the provided value and
* the threshold required.
* @private
*/
function getScaledFormat(d) {
var momentified = moment.utc(d);
/**
* Uses logic from d3 Time-Scales, v3 of the API. See
* https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Scales.md
*
* Licensed
*/
var format = [
[".SSS", function (m) {
return m.milliseconds();
}],
[":ss", function (m) {
return m.seconds();
}],
["HH:mm", function (m) {
return m.minutes();
}],
["HH", function (m) {
return m.hours();
}],
["ddd DD", function (m) {
return m.days() &&
m.date() !== 1;
}],
["MMM DD", function (m) {
return m.date() !== 1;
}],
["MMMM", function (m) {
return m.month();
}],
["YYYY", function () {
return true;
}]
].filter(function (row) {
return row[1](momentified);
})[0][0];
if (format !== undefined) {
return moment.utc(value).format(scaledFormat);
}
}
/**
* @param {number} value The value to format.
* @param {number} [minValue] Contextual information for scaled formatting used in linear scales such as conductor
* and plot axes. Specifies the smallest number on the scale.
* @param {number} [maxValue] Contextual information for scaled formatting used in linear scales such as conductor
* and plot axes. Specifies the largest number on the scale
* @param {number} [count] Contextual information for scaled formatting used in linear scales such as conductor
* and plot axes. The number of labels on the scale.
* @returns {string} the formatted date(s). If multiple values were requested, then an array of
* formatted values will be returned. Where a value could not be formatted, `undefined` will be returned at its position
* in the array.
*/
UTCTimeFormat.prototype.format = function (value, minValue, maxValue, count) {
if (arguments.length > 1) {
return values.map(getScaledFormat);
} else {
return moment.utc(value).format(DATE_FORMAT) + "Z";
}
};
UTCTimeFormat.prototype.parse = function (text) {
return moment.utc(text, DATE_FORMATS).valueOf();
};
UTCTimeFormat.prototype.validate = function (text) {
return moment.utc(text, DATE_FORMATS).isValid();
};
return UTCTimeFormat;
});

View File

@ -0,0 +1,83 @@
/*****************************************************************************
* 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([
"./UTCTimeFormat",
"moment"
], function (
UTCTimeFormat,
moment
) {
describe("The UTCTimeFormat class", function () {
var format;
var scale;
beforeEach(function () {
format = new UTCTimeFormat();
scale = {min: 0, max: 0};
});
it("Provides an appropriately scaled time format based on the input" +
" time", function () {
var TWO_HUNDRED_MS = 200;
var THREE_SECONDS = 3000;
var FIVE_MINUTES = 5 * 60 * 1000;
var ONE_HOUR_TWENTY_MINS = (1 * 60 * 60 * 1000) + (20 * 60 * 1000);
var TEN_HOURS = (10 * 60 * 60 * 1000);
var JUNE_THIRD = moment.utc("2016-06-03", "YYYY-MM-DD");
var APRIL = moment.utc("2016-04", "YYYY-MM");
var TWENTY_SIXTEEN = moment.utc("2016", "YYYY");
expect(format.format(TWO_HUNDRED_MS, scale)).toBe(".200");
expect(format.format(THREE_SECONDS, scale)).toBe(":03");
expect(format.format(FIVE_MINUTES, scale)).toBe("00:05");
expect(format.format(ONE_HOUR_TWENTY_MINS, scale)).toBe("01:20");
expect(format.format(TEN_HOURS, scale)).toBe("10");
expect(format.format(JUNE_THIRD, scale)).toBe("Fri 03");
expect(format.format(APRIL, scale)).toBe("April");
expect(format.format(TWENTY_SIXTEEN, scale)).toBe("2016");
});
it("Returns appropriate time units for a given time span", function () {
var ONE_DAY = 1000 * 60 * 60 * 24;
var FIVE_DAYS = 5 * ONE_DAY;
var FIVE_MONTHS = 60 * ONE_DAY;
var ONE_YEAR = 365 * ONE_DAY;
var SEVEN_YEARS = 7 * ONE_YEAR;
var TWO_DECADES = 20 * ONE_YEAR;
//A span of one day should show a zoom label of "Hours"
expect(format.timeUnits(ONE_DAY)).toEqual("Hours");
//Multiple days should display "Days"
expect(format.timeUnits(FIVE_DAYS)).toEqual("Days");
expect(format.timeUnits(FIVE_MONTHS)).toEqual("Days");
//A span of one year should show a zoom level of "Months".
// Multiple years will show "Years"
expect(format.timeUnits(ONE_YEAR)).toEqual("Months");
expect(format.timeUnits(SEVEN_YEARS)).toEqual("Years");
expect(format.timeUnits(TWO_DECADES)).toEqual("Decades");
});
});
});

View File

@ -0,0 +1,21 @@
define([
'./UTCTimeFormat',
'./LocalClock'
], function (
UtcTimeFormat,
LocalClock
) {
return function UtcTimeSystemPlugin(options) {
return function install(openmct) {
openmct.telemetry.addFormat(new UtcTimeFormat());
openmct.conductor.addTimeSystem({
key: 'utc',
name: 'UTC',
timeFormat: 'utc',
durationFormat: 'duration',
utcBased: true
});
openmct.conductor.addTickSource(new LocalClock());
}
}
});