Compare commits

...

22 Commits

Author SHA1 Message Date
Henry
e69fb17b02 Added tests for MeanTelemetryProvider 2017-11-24 15:14:34 -08:00
Henry
72f9a53ba3 Implemention of basic averaging telemetry filter 2017-11-24 14:27:45 -08:00
Deep Tailor
cf15ff5c07 [imagery] fix for issue #1799 (#1814)
* [imagery] fix for issue #1799
if there is no immediately new imagery incoming, forward to latest image in history on un-pause

* add test to check whether image is forwarded to latest image on un-pause
2017-11-22 11:10:53 -08:00
Victor Woeltjen
6bbdfcdfbe [Table] Retain rows in scope (#1813)
* [Table] Push rows in as they are added

...such that sorting does not cause real-time table rows to be lost.
Fixes #1738

* [Table] Test adding rows

* [Table] Fix code style in test

https://github.com/nasa/openmct/pull/1813#pullrequestreview-78277635
2017-11-22 11:05:03 -08:00
Pete Richards
06e93ff520 Merge pull request #1721 from nasa/persistence-issue-1593
[persistence] uncaught in promise error fix for issue #1593
2017-11-21 14:14:35 -08:00
Deep Tailor
550e7a15e6 [persistence] fix for issue #1593
prevent EditorCapability#finish from calling transactionservice#cancel when transactionService was not active - leading to console error everytime user would leave edit mode

Add tests for changes made and also to check for return type in either case (isActive or not)
2017-11-21 12:07:59 -08:00
Andrew Henry
71c54cd541 Merge pull request #1794 from nasa/open599b
[Timeline] Add resource graphs by drag-and-drop
2017-11-17 16:44:59 -08:00
Andrew Henry
e81b8e53dc Merge pull request #1797 from nasa/object-provider-fix
[API] get with keystring, fix transitional race condition
2017-11-17 09:00:00 -08:00
Pete Richards
84e6928f54 Merge pull request #1809 from nasa/file-saver-1808
[Build] Update file-saver dependency
2017-11-14 16:08:08 -08:00
Victor Woeltjen
ba688fe62c [Build] Update file-saver dependency
Fixes #1808
2017-11-14 14:27:43 -08:00
Pete Richards
c533e10352 [API] get with keystring, mark methods not implemented
Update Object API such that get supports calls with either a keystring or an
identifier.

As save and delete are not implemented and  have different calling signatures,
implement them as separate methods so they can be documented separately.
2017-11-01 12:16:06 -07:00
Victor Woeltjen
04f47b3db6 [Timeline] Test MCTResourceGraphDrop's dragleave handler 2017-10-30 12:44:51 -07:00
Victor Woeltjen
717fa5edf4 [Timeline] Test MCTResourceGraphDrop's drop handler 2017-10-30 12:42:18 -07:00
Victor Woeltjen
14f5f048fb [Timeline] Test MCTResourceGraphDrop's dragover handler 2017-10-30 12:40:08 -07:00
Victor Woeltjen
72929500d3 [Timeline] Begin adding spec for MCTResourceGraphDrop
...to follow up on PR #1195, which fixes #599
2017-10-30 12:25:59 -07:00
David Hudson
471adde923 [Swimlanes] Check for valid swimlane
Issue #599. Also switches class toggle from scope based to element
based.
2017-10-30 12:07:52 -07:00
David Hudson
6c5d5f3d00 [Swimlanes] Implement resource graph directive
Issue #599
2017-10-30 12:07:52 -07:00
David Hudson
2262fef29b [Swimlanes] Add resource graph drop directive
Issue #599
2017-10-30 12:07:49 -07:00
Victor Woeltjen
bda30f1475 Merge pull request #1787 from nasa/fixed-position-panels
[Fixed Position] Fixed position displays now show image URLs
2017-10-30 11:31:37 -07:00
Victor Woeltjen
bfec434369 Merge pull request #1793 from nasa/layout-regression-1790
[Layout] Fix regression in selecting object when it's dropped
2017-10-30 09:43:49 -07:00
Pegah Sarram
14df350994 [Layout] Fix regression...
...by clearing the selection only if the selected object is no longer in the compositon and there's no newly dropped object.

Fixes # 1790
2017-10-27 18:18:09 -07:00
Henry
80582f5e8d [Fixed Position] Do not just show range values, be more flexible to other telemetry types. Fixes #1740 2017-10-24 11:44:06 -07:00
25 changed files with 1311 additions and 42 deletions

View File

@@ -17,7 +17,7 @@
"screenfull": "^3.0.0",
"node-uuid": "^1.4.7",
"comma-separated-values": "^3.6.4",
"FileSaver.js": "^0.0.2",
"file-saver": "^1.3.3",
"zepto": "^1.1.6",
"eventemitter3": "^1.2.0",
"lodash": "3.10.1",

View File

@@ -33,7 +33,7 @@ requirejs.config({
"moment": "bower_components/moment/moment",
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
"moment-timezone": "bower_components/moment-timezone/builds/moment-timezone-with-data",
"saveAs": "bower_components/FileSaver.js/FileSaver.min",
"saveAs": "bower_components/file-saver/FileSaver.min",
"screenfull": "bower_components/screenfull/dist/screenfull.min",
"text": "bower_components/text/text",
"uuid": "bower_components/node-uuid/uuid",

View File

@@ -101,10 +101,15 @@ define(
*/
EditorCapability.prototype.finish = function () {
var domainObject = this.domainObject;
return this.transactionService.cancel().then(function () {
domainObject.getCapability("status").set("editing", false);
return domainObject;
});
if (this.transactionService.isActive()) {
return this.transactionService.cancel().then(function () {
domainObject.getCapability("status").set("editing", false);
return domainObject;
});
} else {
return Promise.resolve(domainObject);
}
};
/**

View File

@@ -62,6 +62,7 @@ define(
);
mockTransactionService.commit.andReturn(fastPromise());
mockTransactionService.cancel.andReturn(fastPromise());
mockTransactionService.isActive = jasmine.createSpy('isActive');
mockStatusCapability = jasmine.createSpyObj(
"statusCapability",
@@ -141,6 +142,7 @@ define(
describe("finish", function () {
beforeEach(function () {
mockTransactionService.isActive.andReturn(true);
capability.edit();
capability.finish();
});
@@ -152,6 +154,23 @@ define(
});
});
describe("finish", function () {
beforeEach(function () {
mockTransactionService.isActive.andReturn(false);
capability.edit();
});
it("does not cancel transaction when transaction is not active", function () {
capability.finish();
expect(mockTransactionService.cancel).not.toHaveBeenCalled();
});
it("returns a promise", function () {
expect(capability.finish() instanceof Promise).toBe(true);
});
});
describe("dirty", function () {
var model = {};

View File

@@ -121,6 +121,9 @@ define([
};
UTCTimeFormat.prototype.parse = function (text) {
if (typeof text === 'number') {
return text;
}
return moment.utc(text, DATE_FORMATS).valueOf();
};

View File

@@ -255,6 +255,8 @@ define(
if (this.nextDatum) {
this.updateValues(this.nextDatum);
delete this.nextDatum;
} else {
this.updateValues(this.$scope.imageHistory[this.$scope.imageHistory.length - 1]);
}
this.autoScroll = true;
}

View File

@@ -183,6 +183,17 @@ define(
expect(controller.getImageUrl()).toEqual(newUrl);
});
it("forwards large image view to latest image in history on un-pause", function () {
$scope.imageHistory = [
{ utc: 1434600258122, url: 'some/url1', selected: false},
{ utc: 1434600258123, url: 'some/url2', selected: false}
];
controller.paused(true);
controller.paused(false);
expect(controller.getImageUrl()).toEqual(controller.getImageUrl($scope.imageHistory[1]));
});
it("subscribes to telemetry", function () {
expect(openmct.telemetry.subscribe).toHaveBeenCalledWith(
newDomainObject,
@@ -227,7 +238,7 @@ define(
expect(controller.updateHistory(mockDatum)).toBe(false);
});
describe("user clicks on imagery thumbnail", function () {
describe("when user clicks on imagery thumbnail", function () {
var mockDatum = { utc: 1434600258123, url: 'some/url', selected: false};
it("pauses and adds selected class to imagery thumbnail", function () {
@@ -248,6 +259,7 @@ define(
expect(controller.getTime()).toEqual(controller.timeFormat.format(mockDatum.utc));
});
});
});
it("initially shows an empty string for date/time", function () {

View File

@@ -360,22 +360,47 @@ define(
*/
FixedController.prototype.updateView = function (telemetryObject, datum) {
var metadata = this.openmct.telemetry.getMetadata(telemetryObject);
var rangeMetadata = metadata.valuesForHints(['range'])[0];
var rangeKey = rangeMetadata.source || rangeMetadata.key;
var valueMetadata = metadata.value(rangeKey);
var telemetryKeyToDisplay = this.chooseTelemetryKeyToDisplay(metadata);
var formattedTelemetryValue = this.getFormattedTelemetryValueForKey(telemetryKeyToDisplay, datum, metadata);
var limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject);
var formatter = this.openmct.telemetry.getValueFormatter(valueMetadata);
var value = datum[valueMetadata.key];
var alarm = limitEvaluator && limitEvaluator.evaluate(datum, rangeKey);
var alarm = limitEvaluator && limitEvaluator.evaluate(datum, telemetryKeyToDisplay);
this.setDisplayedValue(
telemetryObject,
formatter.format(value),
formattedTelemetryValue,
alarm && alarm.cssClass
);
this.digest();
};
/**
* @private
*/
FixedController.prototype.getFormattedTelemetryValueForKey = function (telemetryKeyToDisplay, datum, metadata) {
var valueMetadata = metadata.value(telemetryKeyToDisplay);
var formatter = this.openmct.telemetry.getValueFormatter(valueMetadata);
return formatter.format(datum[valueMetadata.key]);
};
/**
* @private
*/
FixedController.prototype.chooseTelemetryKeyToDisplay = function (metadata) {
// If there is a range value, show that preferentially
var telemetryKeyToDisplay = metadata.valuesForHints(['range'])[0];
// If no range is defined, default to the highest priority non time-domain data.
if (telemetryKeyToDisplay === undefined) {
var valuesOrderedByPriority = metadata.values();
telemetryKeyToDisplay = valuesOrderedByPriority.filter(function (valueMetadata) {
return !(valueMetadata.hints.domain);
})[0];
}
return telemetryKeyToDisplay.source;
};
/**
* Request the last historical data point for the given domain objects
* @param {object[]} objects
@@ -388,7 +413,9 @@ define(
objects.forEach(function (object) {
self.openmct.telemetry.request(object, {start: bounds.start, end: bounds.end, size: 1})
.then(function (data) {
self.updateView(object, data[data.length - 1]);
if (data.length > 0) {
self.updateView(object, data[data.length - 1]);
}
});
});
return objects;

View File

@@ -127,9 +127,7 @@ define(
if (self.droppedIdToSelectAfterRefresh) {
self.select(null, self.droppedIdToSelectAfterRefresh);
delete self.droppedIdToSelectAfterRefresh;
}
if (composition.indexOf(self.selectedId) === -1) {
} else if (composition.indexOf(self.selectedId) === -1) {
self.clearSelection();
}
}

View File

@@ -178,7 +178,6 @@ define(
Promise.resolve(mockChildren)
);
mockScope.model = testModel;
mockScope.configuration = testConfiguration;
mockScope.selection = jasmine.createSpyObj(
@@ -194,7 +193,8 @@ define(
mockMetadata = jasmine.createSpyObj('mockMetadata', [
'valuesForHints',
'value'
'value',
'values'
]);
mockMetadata.value.andReturn({
key: 'value'
@@ -653,6 +653,39 @@ define(
});
});
it("selects an range value to display, if available", function () {
mockMetadata.valuesForHints.andReturn([
{
key: 'range',
source: 'range'
}
]);
var key = controller.chooseTelemetryKeyToDisplay(mockMetadata);
expect(key).toEqual('range');
});
it("selects the first non-domain value to display, if no range available", function () {
mockMetadata.valuesForHints.andReturn([]);
mockMetadata.values.andReturn([
{
key: 'domain',
source: 'domain',
hints: {
domain: 1
}
},
{
key: 'image',
source: 'image',
hints: {
image: 1
}
}
]);
var key = controller.chooseTelemetryKeyToDisplay(mockMetadata);
expect(key).toEqual('image');
});
it("reflects limit status", function () {
mockLimitEvaluator.evaluate.andReturn({cssClass: "alarm-a"});
controller.updateView(mockTelemetryObject, [{

View File

@@ -170,6 +170,9 @@ define(
* @param rows
*/
TelemetryTableController.prototype.addRowsToTable = function (rows) {
rows.forEach(function (row) {
this.$scope.rows.push(row);
}, this);
this.$scope.$broadcast('add:rows', rows);
};

View File

@@ -436,5 +436,28 @@ define(
expect(mockScope.$broadcast).toHaveBeenCalledWith("remove:rows", discardedRows);
});
describe('when telemetry is added', function () {
var testRows;
var expectedRows;
beforeEach(function () {
testRows = [{ a: 0 }, { a: 1 }, { a: 2 }];
mockScope.rows = [{ a: -1 }];
expectedRows = mockScope.rows.concat(testRows);
spyOn(controller.telemetry, "on").andCallThrough();
controller.registerChangeListeners();
controller.telemetry.on.calls.forEach(function (call) {
if (call.args[0] === 'added') {
call.args[1](testRows);
}
});
});
it("adds it to rows in scope", function () {
expect(mockScope.rows).toEqual(expectedRows);
});
});
});
});

View File

@@ -38,6 +38,7 @@ define([
"./src/capabilities/CostCapability",
"./src/directives/MCTSwimlaneDrop",
"./src/directives/MCTSwimlaneDrag",
"./src/directives/MCTResourceGraphDrop",
"./src/services/ObjectLoader",
"./src/chart/MCTTimelineChart",
"text!./res/templates/values.html",
@@ -69,6 +70,7 @@ define([
CostCapability,
MCTSwimlaneDrop,
MCTSwimlaneDrag,
MCTResourceGraphDrop,
ObjectLoader,
MCTTimelineChart,
valuesTemplate,
@@ -577,6 +579,13 @@ define([
"$interval",
"$log"
]
},
{
"key": "mctResourceGraphDrop",
"implementation": MCTResourceGraphDrop,
"depends": [
"dndService"
]
}
],
"services": [

View File

@@ -38,6 +38,10 @@
.l-timeline-pane {
@include absPosDefault();
&.drop-over {
background-color: lighten($colorEditAreaBg, 5%);
}
.l-width-control {
position: relative;
}

View File

@@ -77,7 +77,8 @@
<mct-splitter></mct-splitter>
<!-- BOTTOM PANE RESOURCE LEGEND -->
<div class="split-pane-component abs l-timeline-pane t-pane-h l-pane-btm s-timeline-resource-legend l-timeline-resource-legend">
<div mct-resource-graph-drop
class="split-pane-component abs l-timeline-pane t-pane-h l-pane-btm s-timeline-resource-legend l-timeline-resource-legend">
<div class="l-title s-title">{{ngModel.title}}Resource Graph Legend</div>
<div class="l-legend-items legend">
<mct-include key="'timeline-legend-item'"

View File

@@ -0,0 +1,81 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-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(
['./SwimlaneDragConstants'],
function (SwimlaneDragConstants) {
/**
* Defines the `mct-resource-graph-drop` directive. When a drop occurs
* on an element with this attribute, the swimlane targeted by the drop
* will receive the dropped domain object (at which point it can handle
* the drop, typically by toggling the swimlane graph.)
* @param {DndService} dndService drag-and-drop service
*/
function MCTResourceGraphDrop(dndService) {
function link(scope, element, attrs) {
// Handle dragover
element.on('dragover', function (e) {
var swimlane = dndService.getData(
SwimlaneDragConstants.TIMELINE_SWIMLANE_DRAG_TYPE
);
if (typeof swimlane !== "undefined" && !swimlane.graph()) {
element.addClass('drop-over');
scope.$apply();
e.preventDefault();
}
});
// Handle drops
element.on('drop', function (e) {
var swimlane = dndService.getData(
SwimlaneDragConstants.TIMELINE_SWIMLANE_DRAG_TYPE
);
element.removeClass('drop-over');
// Only toggle if the graph isn't already set
if (typeof swimlane !== "undefined" && !swimlane.graph()) {
swimlane.toggleGraph();
e.preventDefault();
}
});
// Clear highlights when drag leaves this swimlane
element.on('dragleave', function (e) {
element.removeClass('drop-over');
scope.$apply();
e.preventDefault();
});
}
return {
// Applies to attributes
restrict: "A",
// Link using above function
link: link
};
}
return MCTResourceGraphDrop;
}
);

View File

@@ -0,0 +1,159 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-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(
['../../src/directives/MCTResourceGraphDrop', '../../src/directives/SwimlaneDragConstants'],
function (MCTResourceGraphDrop, SwimlaneDragConstants) {
describe("The mct-resource-graph-drop directive", function () {
var mockDndService,
mockScope,
mockElement,
testAttrs,
mockSwimlane,
testEvent,
handlers,
directive;
beforeEach(function () {
handlers = {};
mockDndService = jasmine.createSpyObj(
'dndService',
['setData', 'getData', 'removeData']
);
mockScope = jasmine.createSpyObj('$scope', ['$eval', '$apply']);
mockElement = jasmine.createSpyObj('element', ['on', 'addClass', 'removeClass']);
testAttrs = { mctSwimlaneDrop: "mockSwimlane" };
mockSwimlane = jasmine.createSpyObj(
"swimlane",
['graph', 'toggleGraph']
);
testEvent = {
dataTransfer: { getData: jasmine.createSpy() },
preventDefault: jasmine.createSpy(),
stopPropagation: jasmine.createSpy()
};
testEvent.dataTransfer.getData.andReturn('abc');
mockDndService.getData.andCallFake(function (key) {
return key === SwimlaneDragConstants.TIMELINE_SWIMLANE_DRAG_TYPE ?
mockSwimlane : undefined;
});
mockSwimlane.graph.andReturn(false);
directive = new MCTResourceGraphDrop(mockDndService);
directive.link(mockScope, mockElement, testAttrs);
mockElement.on.calls.forEach(function (call) {
handlers[call.args[0]] = call.args[1];
});
});
it("is available as an attribute", function () {
expect(directive.restrict).toEqual("A");
});
[false, true].forEach(function (graphing) {
describe("when swimlane graph is " + (graphing ? "" : "not ") + "enabled", function () {
beforeEach(function () {
mockSwimlane.graph.andReturn(graphing);
});
describe("on dragover", function () {
var prefix = !graphing ? "does" : "does not";
beforeEach(function () {
handlers.dragover(testEvent);
});
it(prefix + " add a drop-over class", function () {
var expectAddClass = expect(mockElement.addClass);
(!graphing ? expectAddClass : expectAddClass.not)
.toHaveBeenCalledWith('drop-over');
});
it(prefix + " call $apply on scope", function () {
var expectApply = expect(mockScope.$apply);
(!graphing ? expectApply : expectApply.not)
.toHaveBeenCalled();
});
it(prefix + " prevent default", function () {
var expectPreventDefault = expect(testEvent.preventDefault);
(!graphing ? expectPreventDefault : expectPreventDefault.not)
.toHaveBeenCalled();
});
});
describe("on drop", function () {
var prefix = !graphing ? "does" : "does not";
beforeEach(function () {
handlers.drop(testEvent);
});
it("removes any drop-over class", function () {
expect(mockElement.removeClass)
.toHaveBeenCalledWith('drop-over');
});
it(prefix + " toggle the swimlane's resource graph", function () {
var expectToggle = expect(mockSwimlane.toggleGraph);
(!graphing ? expectToggle : expectToggle.not)
.toHaveBeenCalled();
});
it(prefix + " prevent default", function () {
var expectPreventDefault = expect(testEvent.preventDefault);
(!graphing ? expectPreventDefault : expectPreventDefault.not)
.toHaveBeenCalled();
});
});
describe("on dragleave", function () {
beforeEach(function () {
handlers.dragleave(testEvent);
});
it("removes any drop-over class", function () {
expect(mockElement.removeClass)
.toHaveBeenCalledWith('drop-over');
});
it("calls $apply on scope", function () {
expect(mockScope.$apply).toHaveBeenCalled();
});
it("calls preventDefault on events", function () {
expect(testEvent.preventDefault).toHaveBeenCalled();
});
});
});
});
});
}
);

View File

@@ -50,11 +50,18 @@ define([
this.rootProvider = new RootObjectProvider(this.rootRegistry);
}
/**
* Set fallback provider, this is an internal API for legacy reasons.
* @private
*/
ObjectAPI.prototype.supersecretSetFallbackProvider = function (p) {
this.fallbackProvider = p;
};
// Retrieve the provider for a given key.
/**
* Retrieve the provider for a given identifier.
* @private
*/
ObjectAPI.prototype.getProvider = function (identifier) {
if (identifier.key === 'ROOT') {
return this.rootProvider;
@@ -135,27 +142,28 @@ define([
* @returns {Promise} a promise which will resolve when the domain object
* has been saved, or be rejected if it cannot be saved
*/
ObjectAPI.prototype.get = function (identifier) {
identifier = utils.parseKeyString(identifier);
var provider = this.getProvider(identifier);
[
'save',
'delete',
'get'
].forEach(function (method) {
ObjectAPI.prototype[method] = function () {
var identifier = arguments[0],
provider = this.getProvider(identifier);
if (!provider) {
throw new Error('No Provider Matched');
}
if (!provider) {
throw new Error('No Provider Matched');
}
if (!provider.get) {
throw new Error('Provider does not support get!');
}
if (!provider[method]) {
throw new Error('Provider does not support [' + method + '].');
}
return provider.get(identifier);
};
return provider[method].apply(provider, arguments);
};
});
ObjectAPI.prototype.delete = function () {
throw new Error('Delete not implemented');
};
ObjectAPI.prototype.save = function () {
throw new Error('Save not implemented');
};
/**
* Add a root-level object.

View File

@@ -27,7 +27,8 @@ define([
'../../platform/features/autoflow/plugin',
'./timeConductor/plugin',
'../../example/imagery/plugin',
'../../platform/import-export/bundle'
'../../platform/import-export/bundle',
'./telemetryMean/plugin'
], function (
_,
UTCTimeSystem,
@@ -35,7 +36,8 @@ define([
AutoflowPlugin,
TimeConductorPlugin,
ExampleImagery,
ImportExport
ImportExport,
TelemetryMean
) {
var bundleMap = {
CouchDB: 'platform/persistence/couch',
@@ -120,6 +122,7 @@ define([
};
plugins.ExampleImagery = ExampleImagery;
plugins.TelemetryMean = TelemetryMean;
return plugins;
});

View File

@@ -0,0 +1,76 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, 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(['./src/MeanTelemetryProvider'], function (MeanTelemetryProvider) {
var DEFAULT_SAMPLES = 10;
function plugin() {
return function install(openmct) {
openmct.types.addType('telemetry-mean', {
name: 'Telemetry Mean',
description: 'Provides telemetry values that represent the mean of the last N values of a telemetry stream',
creatable: true,
cssClass: 'icon-telemetry',
initialize: function (domainObject) {
domainObject.samples = DEFAULT_SAMPLES;
domainObject.telemetry = {};
domainObject.telemetry.values =
openmct.time.getAllTimeSystems().map(function (timeSystem, index) {
return {
key: timeSystem.key,
name: timeSystem.name,
hints: {
domain: index + 1
}
};
});
domainObject.telemetry.values.push({
key: "value",
name: "Value",
hints: {
range: 1
}
});
},
form: [
{
"key": "telemetryPoint",
"name": "Telemetry Point",
"control": "textfield",
"required": true,
"cssClass": "l-input-lg"
},
{
"key": "samples",
"name": "Samples to Average",
"control": "textfield",
"required": true,
"cssClass": "l-input-sm"
}
]
});
openmct.telemetry.addProvider(new MeanTelemetryProvider(openmct));
};
}
return plugin;
});

View File

@@ -0,0 +1,125 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, 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.
*****************************************************************************/
/*jshint latedef: nofunc */
/*global console */
define([
'../../../api/objects/object-utils',
'./TelemetryAverager'
], function (objectUtils, TelemetryAverager) {
function MeanTelemetryProvider(openmct) {
this.openmct = openmct;
this.telemetryAPI = openmct.telemetry;
this.timeAPI = openmct.time;
this.objectAPI = openmct.objects;
this.perObjectProviders = {};
}
MeanTelemetryProvider.prototype.canProvideTelemetry = function (domainObject) {
return domainObject.type === 'telemetry-mean';
};
MeanTelemetryProvider.prototype.supportsRequest =
MeanTelemetryProvider.prototype.supportsSubscribe =
MeanTelemetryProvider.prototype.canProvideTelemetry;
MeanTelemetryProvider.prototype.subscribe = function (domainObject, callback) {
var wrappedUnsubscribe;
var unsubscribeCalled = false;
var objectId = objectUtils.parseKeyString(domainObject.telemetryPoint);
var samples = domainObject.samples;
this.objectAPI.get(objectId)
.then(function (linkedDomainObject) {
if (!unsubscribeCalled) {
wrappedUnsubscribe = this.subscribeToAverage(linkedDomainObject, samples, callback);
}
}.bind(this))
.catch(logError);
return function unsubscribe() {
unsubscribeCalled = true;
if (wrappedUnsubscribe !== undefined) {
wrappedUnsubscribe();
}
};
};
MeanTelemetryProvider.prototype.subscribeToAverage = function (domainObject, samples, callback) {
var telemetryAverager = new TelemetryAverager(this.telemetryAPI, this.timeAPI, domainObject, samples);
return this.telemetryAPI.subscribe(domainObject, function (telemetryDatum) {
var avgData = telemetryAverager.createAverageDatum(telemetryDatum);
if (telemetryAverager.sampleCount() === samples) {
callback(avgData);
}
}.bind(this));
};
MeanTelemetryProvider.prototype.request = function (domainObject, request) {
var objectId = objectUtils.parseKeyString(domainObject.telemetryPoint);
var samples = domainObject.samples;
return this.objectAPI.get(objectId).then(function (linkedDomainObject) {
return this.requestAverageTelemetry(linkedDomainObject, request, samples);
}.bind(this));
};
/**
* @private
*/
MeanTelemetryProvider.prototype.requestAverageTelemetry = function (domainObject, request, samples) {
var averageData = [];
var telemetryAverager = new TelemetryAverager(this.telemetryAPI, this.timeAPI, domainObject, samples);
return this.telemetryAPI.request(domainObject, request).then(function (telemetryData) {
telemetryData.forEach(function (datum) {
var avgDatum = telemetryAverager.createAverageDatum(datum);
if (telemetryAverager.sampleCount() === samples) {
averageData.push(avgDatum);
}
}.bind(this));
return averageData;
}.bind(this));
};
/**
* @private
*/
MeanTelemetryProvider.prototype.getLinkedObject = function (domainObject) {
var objectId = objectUtils.parseKeyString(domainObject.telemetryPoint);
return this.objectAPI.get(objectId);
};
function logError(error) {
if (error.stack) {
console.error(error.stack);
} else {
console.error(error);
}
}
return MeanTelemetryProvider;
});

View File

@@ -0,0 +1,460 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*jshint latedef: nofunc */
define([
"./MeanTelemetryProvider",
"./MockTelemetryApi"
], function (
MeanTelemetryProvider,
MockTelemetryApi
) {
var RANGE_KEY = 'value';
describe("The Mean Telemetry Provider", function () {
var mockApi;
var meanTelemetryProvider;
var outstandingPromises = 0;
var mockDomainObject;
var associatedObject;
beforeEach(function () {
createMockApi();
setTimeSystemTo('utc');
createMockObjects();
meanTelemetryProvider = new MeanTelemetryProvider(mockApi);
});
it("supports telemetry-mean objects only", function () {
var mockTelemetryMeanObject = mockObjectWithType('telemetry-mean');
var mockOtherObject = mockObjectWithType('other');
expect(meanTelemetryProvider.canProvideTelemetry(mockTelemetryMeanObject)).toBe(true);
expect(meanTelemetryProvider.canProvideTelemetry(mockOtherObject)).toBe(false);
});
describe("the subscribe function", function () {
var subscriptionCallback;
beforeEach(function () {
subscriptionCallback = jasmine.createSpy('subscriptionCallback');
});
it("subscribes to telemetry for the associated object", function () {
meanTelemetryProvider.subscribe(mockDomainObject);
expectObjectWasSubscribedTo(associatedObject);
});
it("returns a function that unsubscribes from the associated object", function () {
var unsubscribe = meanTelemetryProvider.subscribe(mockDomainObject);
waitsFor(allPromisesToBeResolved);
runs(unsubscribe);
expectUnsubscribeFrom(associatedObject);
});
it("returns an average only when the sample size is reached", function () {
var inputTelemetry = [
{'utc': 1, 'defaultRange': 123.1231},
{'utc': 2, 'defaultRange': 321.3223},
{'utc': 3, 'defaultRange': 111.4446},
{'utc': 4, 'defaultRange': 555.2313}
];
setSampleSize(5);
meanTelemetryProvider.subscribe(mockDomainObject, subscriptionCallback);
feedInputTelemetry(inputTelemetry);
expectNoAverageForTelemetry(inputTelemetry);
});
it("correctly averages a sample of five values", function () {
var inputTelemetry = [
{'utc': 1, 'defaultRange': 123.1231},
{'utc': 2, 'defaultRange': 321.3223},
{'utc': 3, 'defaultRange': 111.4446},
{'utc': 4, 'defaultRange': 555.2313},
{'utc': 5, 'defaultRange': 1.1231}
];
var expectedAverages = [{
'utc': 5, 'value': 222.44888
}];
setSampleSize(5);
meanTelemetryProvider.subscribe(mockDomainObject, subscriptionCallback);
feedInputTelemetry(inputTelemetry);
expectAveragesForTelemetry(expectedAverages, inputTelemetry);
});
it("correctly averages a sample of ten values", function () {
var inputTelemetry = [
{'utc': 1, 'defaultRange': 123.1231},
{'utc': 2, 'defaultRange': 321.3223},
{'utc': 3, 'defaultRange': 111.4446},
{'utc': 4, 'defaultRange': 555.2313},
{'utc': 5, 'defaultRange': 1.1231},
{'utc': 6, 'defaultRange': 2323.12},
{'utc': 7, 'defaultRange': 532.12},
{'utc': 8, 'defaultRange': 453.543},
{'utc': 9, 'defaultRange': 89.2111},
{'utc': 10, 'defaultRange': 0.543}
];
var expectedAverages = [{
'utc': 10, 'value': 451.07815
}];
setSampleSize(10);
meanTelemetryProvider.subscribe(mockDomainObject, subscriptionCallback);
feedInputTelemetry(inputTelemetry);
expectAveragesForTelemetry(expectedAverages, inputTelemetry);
});
it("only averages values within its sample window", function () {
var inputTelemetry = [
{'utc': 1, 'defaultRange': 123.1231},
{'utc': 2, 'defaultRange': 321.3223},
{'utc': 3, 'defaultRange': 111.4446},
{'utc': 4, 'defaultRange': 555.2313},
{'utc': 5, 'defaultRange': 1.1231},
{'utc': 6, 'defaultRange': 2323.12},
{'utc': 7, 'defaultRange': 532.12},
{'utc': 8, 'defaultRange': 453.543},
{'utc': 9, 'defaultRange': 89.2111},
{'utc': 10, 'defaultRange': 0.543}
];
var expectedAverages = [
{'utc': 5, 'value': 222.44888},
{'utc': 6, 'value': 662.4482599999999},
{'utc': 7, 'value': 704.6078},
{'utc': 8, 'value': 773.02748},
{'utc': 9, 'value': 679.8234399999999},
{'utc': 10, 'value': 679.70742}
];
setSampleSize(5);
meanTelemetryProvider.subscribe(mockDomainObject, subscriptionCallback);
feedInputTelemetry(inputTelemetry);
expectAveragesForTelemetry(expectedAverages, inputTelemetry);
});
describe("given telemetry input with range values", function () {
var inputTelemetry;
beforeEach(function () {
inputTelemetry = [{
'utc': 1,
'rangeKey': 5678,
'otherKey': 9999
}];
setSampleSize(1);
});
it("uses the 'rangeKey' input range, when it is the default, to calculate the average", function () {
var averageTelemetryForRangeKey = [{
'utc': 1,
'value': 5678
}];
meanTelemetryProvider.subscribe(mockDomainObject, subscriptionCallback);
mockApi.telemetry.setDefaultRangeTo('rangeKey');
feedInputTelemetry(inputTelemetry);
expectAveragesForTelemetry(averageTelemetryForRangeKey, inputTelemetry);
});
it("uses the 'otherKey' input range, when it is the default, to calculate the average", function () {
var averageTelemetryForOtherKey = [{
'utc': 1,
'value': 9999
}];
meanTelemetryProvider.subscribe(mockDomainObject, subscriptionCallback);
mockApi.telemetry.setDefaultRangeTo('otherKey');
feedInputTelemetry(inputTelemetry);
expectAveragesForTelemetry(averageTelemetryForOtherKey, inputTelemetry);
});
});
describe("given telemetry input with range values", function () {
var inputTelemetry;
beforeEach(function () {
inputTelemetry = [{
'utc': 1,
'rangeKey': 5678,
'otherKey': 9999
}];
setSampleSize(1);
});
it("uses the 'rangeKey' input range, when it is the default, to calculate the average", function () {
var averageTelemetryForRangeKey = [{
'utc': 1,
'value': 5678
}];
meanTelemetryProvider.subscribe(mockDomainObject, subscriptionCallback);
mockApi.telemetry.setDefaultRangeTo('rangeKey');
feedInputTelemetry(inputTelemetry);
expectAveragesForTelemetry(averageTelemetryForRangeKey, inputTelemetry);
});
it("uses the 'otherKey' input range, when it is the default, to calculate the average", function () {
var averageTelemetryForOtherKey = [{
'utc': 1,
'value': 9999
}];
meanTelemetryProvider.subscribe(mockDomainObject, subscriptionCallback);
mockApi.telemetry.setDefaultRangeTo('otherKey');
feedInputTelemetry(inputTelemetry);
expectAveragesForTelemetry(averageTelemetryForOtherKey, inputTelemetry);
});
});
function feedInputTelemetry(inputTelemetry) {
waitsFor(allPromisesToBeResolved);
runs(function () {
inputTelemetry.forEach(mockApi.telemetry.mockReceiveTelemetry);
});
}
function expectNoAverageForTelemetry(inputTelemetry) {
waitsFor(allPromisesToBeResolved);
runs(function () {
expect(subscriptionCallback).not.toHaveBeenCalled();
});
}
function expectAveragesForTelemetry(expectedAverages) {
waitsFor(allPromisesToBeResolved);
runs(function () {
expectedAverages.forEach(function (averageDatum) {
expect(subscriptionCallback).toHaveBeenCalledWith(averageDatum);
});
});
}
function expectObjectWasSubscribedTo(object) {
waitsFor(allPromisesToBeResolved);
runs(function () {
expect(mockApi.telemetry.subscribe).toHaveBeenCalledWith(object, jasmine.any(Function));
});
}
function expectUnsubscribeFrom() {
waitsFor(allPromisesToBeResolved);
runs(function () {
expect(mockApi.telemetry.unsubscribe).toHaveBeenCalled();
});
}
});
describe("the request function", function () {
it("requests telemetry for the associated object", function () {
meanTelemetryProvider.request(mockDomainObject);
expectTelemetryToBeRequestedFor(associatedObject);
});
it("returns an average only when the sample size is reached", function () {
var inputTelemetry = [
{'utc': 1, 'defaultRange': 123.1231},
{'utc': 2, 'defaultRange': 321.3223},
{'utc': 3, 'defaultRange': 111.4446},
{'utc': 4, 'defaultRange': 555.2313}
];
var promiseForAverage;
setSampleSize(5);
whenTelemetryRequestedReturn(inputTelemetry);
promiseForAverage = meanTelemetryProvider.request(mockDomainObject);
expectEmptyResponse(promiseForAverage);
});
it("correctly averages a sample of five values", function () {
var inputTelemetry = [
{'utc': 1, 'defaultRange': 123.1231},
{'utc': 2, 'defaultRange': 321.3223},
{'utc': 3, 'defaultRange': 111.4446},
{'utc': 4, 'defaultRange': 555.2313},
{'utc': 5, 'defaultRange': 1.1231}
];
var promiseForAverage;
setSampleSize(5);
whenTelemetryRequestedReturn(inputTelemetry);
promiseForAverage = meanTelemetryProvider.request(mockDomainObject);
expectAverageToBe(222.44888, promiseForAverage);
});
it("correctly averages a sample of ten values", function () {
var inputTelemetry = [
{'utc': 1, 'defaultRange': 123.1231},
{'utc': 2, 'defaultRange': 321.3223},
{'utc': 3, 'defaultRange': 111.4446},
{'utc': 4, 'defaultRange': 555.2313},
{'utc': 5, 'defaultRange': 1.1231},
{'utc': 6, 'defaultRange': 2323.12},
{'utc': 7, 'defaultRange': 532.12},
{'utc': 8, 'defaultRange': 453.543},
{'utc': 9, 'defaultRange': 89.2111},
{'utc': 10, 'defaultRange': 0.543}
];
var promiseForAverage;
setSampleSize(10);
whenTelemetryRequestedReturn(inputTelemetry);
promiseForAverage = meanTelemetryProvider.request(mockDomainObject);
expectAverageToBe(451.07815, promiseForAverage);
});
it("only averages values within its sample window", function () {
var inputTelemetry = [
{'utc': 1, 'defaultRange': 123.1231},
{'utc': 2, 'defaultRange': 321.3223},
{'utc': 3, 'defaultRange': 111.4446},
{'utc': 4, 'defaultRange': 555.2313},
{'utc': 5, 'defaultRange': 1.1231},
{'utc': 6, 'defaultRange': 2323.12},
{'utc': 7, 'defaultRange': 532.12},
{'utc': 8, 'defaultRange': 453.543},
{'utc': 9, 'defaultRange': 89.2111},
{'utc': 10, 'defaultRange': 0.543}
];
var promiseForAverage;
setSampleSize(5);
whenTelemetryRequestedReturn(inputTelemetry);
promiseForAverage = meanTelemetryProvider.request(mockDomainObject);
expectAverageToBe(679.70742, promiseForAverage);
});
function expectAverageToBe(expectedValue, promiseForAverage) {
var averageData;
promiseForAverage.then(function (data) {
averageData = data;
});
waitsFor(function () {
return averageData !== undefined;
}, 'data to return from request', 1);
runs(function () {
var averageDatum = averageData[averageData.length - 1];
expect(averageDatum[RANGE_KEY]).toBe(expectedValue);
});
}
function expectEmptyResponse(promiseForAverage) {
var averageData;
promiseForAverage.then(function (data) {
averageData = data;
});
waitsFor(function () {
return averageData !== undefined;
}, 'data to return from request', 1);
runs(function () {
expect(averageData.length).toBe(0);
});
}
function whenTelemetryRequestedReturn(telemetry) {
mockApi.telemetry.request.andReturn(resolvePromiseWith(telemetry));
}
function expectTelemetryToBeRequestedFor(object) {
waitsFor(allPromisesToBeResolved);
runs(function () {
expect(mockApi.telemetry.request).toHaveBeenCalledWith(object, undefined);
});
}
});
function createMockObjects() {
mockDomainObject = {
telemetryPoint: 'someTelemetryPoint'
};
associatedObject = {};
mockApi.objects.get.andReturn(resolvePromiseWith(associatedObject));
}
function setSampleSize(sampleSize) {
mockDomainObject.samples = sampleSize;
}
function createMockApi() {
mockApi = {
telemetry: new MockTelemetryApi(),
objects: createMockObjectApi(),
time: createMockTimeApi()
};
}
function createMockObjectApi() {
return jasmine.createSpyObj('ObjectAPI', [
'get'
]);
}
function mockObjectWithType(type) {
return {
type: type
};
}
function resolvePromiseWith(value) {
outstandingPromises++;
return Promise.resolve(value).then(function () {
outstandingPromises--;
return value;
});
}
function allPromisesToBeResolved() {
return outstandingPromises === 0;
}
function createMockTimeApi() {
return jasmine.createSpyObj("timeApi", ['timeSystem']);
}
function setTimeSystemTo(timeSystemKey) {
mockApi.time.timeSystem.andReturn({
key: timeSystemKey
});
}
});
});

View File

@@ -0,0 +1,106 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, 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.
*****************************************************************************/
/*global jasmine, spyOn */
define([], function () {
function MockTelemetryApi() {
this.createSpy('subscribe');
this.createSpy('getMetadata');
this.metadata = this.createMockMetadata();
this.setDefaultRangeTo('defaultRange');
this.unsubscribe = jasmine.createSpy('unsubscribe');
this.mockReceiveTelemetry = this.mockReceiveTelemetry.bind(this);
}
MockTelemetryApi.prototype.subscribe = function () {
return this.unsubscribe;
};
MockTelemetryApi.prototype.getMetadata = function (object) {
return this.metadata;
};
MockTelemetryApi.prototype.request = jasmine.createSpy('request');
MockTelemetryApi.prototype.getValueFormatter = function (valueMetadata) {
var mockValueFormatter = jasmine.createSpyObj("valueFormatter", [
"parse"
]);
mockValueFormatter.parse.andCallFake(function (value) {
return value[valueMetadata.key];
});
return mockValueFormatter;
};
MockTelemetryApi.prototype.mockReceiveTelemetry = function (newTelemetryDatum) {
var subscriptionCallback = this.subscribe.mostRecentCall.args[1];
subscriptionCallback(newTelemetryDatum);
};
/**
* @private
*/
MockTelemetryApi.prototype.onRequestReturn = function (telemetryData) {
this.requestTelemetry = telemetryData;
};
/**
* @private
*/
MockTelemetryApi.prototype.setDefaultRangeTo = function (rangeKey) {
var mockMetadataValue = {
key: rangeKey
};
this.metadata.valuesForHints.andReturn([mockMetadataValue]);
};
/**
* @private
*/
MockTelemetryApi.prototype.createMockMetadata = function () {
var mockMetadata = jasmine.createSpyObj("metadata", [
'value',
'valuesForHints'
]);
mockMetadata.value.andCallFake(function (key) {
return {
key: key
};
});
return mockMetadata;
};
/**
* @private
*/
MockTelemetryApi.prototype.createSpy = function (functionName) {
this[functionName] = this[functionName].bind(this);
spyOn(this, functionName);
this[functionName].andCallThrough();
};
return MockTelemetryApi;
});

View File

@@ -0,0 +1,112 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, 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 TelemetryAverager(telemetryAPI, timeAPI, domainObject, samples) {
this.telemetryAPI = telemetryAPI;
this.timeAPI = timeAPI;
this.domainObject = domainObject;
this.samples = samples;
this.averagingWindow = [];
this.rangeKey = undefined;
this.rangeFormatter = undefined;
this.setRangeKeyAndFormatter();
// Defined dynamically based on current time system
this.domainKey = undefined;
this.domainFormatter = undefined;
}
TelemetryAverager.prototype.createAverageDatum = function (telemetryDatum) {
this.setDomainKeyAndFormatter();
var timeValue = this.domainFormatter.parse(telemetryDatum);
var rangeValue = this.rangeFormatter.parse(telemetryDatum);
this.averagingWindow.push(rangeValue);
if (this.averagingWindow.length > this.samples) {
this.averagingWindow.shift();
}
var averageValue = this.calculateMean();
var meanDatum = {};
meanDatum[this.domainKey] = timeValue;
meanDatum.value = averageValue;
return meanDatum;
};
/**
* @private
*/
TelemetryAverager.prototype.calculateMean = function () {
var sum = 0;
var i = 0;
for (; i < this.averagingWindow.length; i++) {
sum += this.averagingWindow[i];
}
return sum / this.averagingWindow.length;
};
/**
* @private
*/
TelemetryAverager.prototype.setDomainKeyAndFormatter = function () {
var domainKey = this.timeAPI.timeSystem().key;
if (domainKey !== this.domainKey) {
this.domainKey = domainKey;
this.domainFormatter = this.getFormatter(domainKey);
}
};
/**
* @private
*/
TelemetryAverager.prototype.setRangeKeyAndFormatter = function () {
var metadatas = this.telemetryAPI.getMetadata(this.domainObject);
var rangeValues = metadatas.valuesForHints(['range']);
this.rangeKey = rangeValues[0].key;
this.rangeFormatter = this.getFormatter(this.rangeKey);
};
/**
* @private
*/
TelemetryAverager.prototype.getFormatter = function (key) {
var objectMetadata = this.telemetryAPI.getMetadata(this.domainObject);
var valueMetadata = objectMetadata.value(key);
return this.telemetryAPI.getValueFormatter(valueMetadata);
};
TelemetryAverager.prototype.sampleCount = function () {
return this.averagingWindow.length;
};
return TelemetryAverager;
});

View File

@@ -59,7 +59,7 @@ requirejs.config({
"moment": "bower_components/moment/moment",
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
"moment-timezone": "bower_components/moment-timezone/builds/moment-timezone-with-data",
"saveAs": "bower_components/FileSaver.js/FileSaver.min",
"saveAs": "bower_components/file-saver/FileSaver.min",
"screenfull": "bower_components/screenfull/dist/screenfull.min",
"text": "bower_components/text/text",
"uuid": "bower_components/node-uuid/uuid",