mirror of
https://github.com/nasa/openmct.git
synced 2025-05-28 21:24:20 +00:00
Support for Bar Graphs (#4221)
* Adds new types for Bar Graphs (#4168) * Adds new spectral test data Co-authored-by: Scott Bell <scott@traclabs.com> Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com> Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov> Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
parent
eabdf6cd04
commit
c4b9be18f1
@ -28,6 +28,15 @@ define([
|
|||||||
domain: 2
|
domain: 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "cos",
|
||||||
|
name: "Cosine",
|
||||||
|
unit: "deg",
|
||||||
|
formatString: '%0.2f',
|
||||||
|
hints: {
|
||||||
|
domain: 3
|
||||||
|
}
|
||||||
|
},
|
||||||
// Need to enable "LocalTimeSystem" plugin to make use of this
|
// Need to enable "LocalTimeSystem" plugin to make use of this
|
||||||
// {
|
// {
|
||||||
// key: "local",
|
// key: "local",
|
||||||
@ -109,6 +118,100 @@ define([
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
'example.spectral-generator': {
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
key: "name",
|
||||||
|
name: "Name",
|
||||||
|
format: "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "utc",
|
||||||
|
name: "Time",
|
||||||
|
format: "utc",
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "wavelength",
|
||||||
|
name: "Wavelength",
|
||||||
|
unit: "Hz",
|
||||||
|
formatString: '%0.2f',
|
||||||
|
hints: {
|
||||||
|
domain: 2,
|
||||||
|
spectralAttribute: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "cos",
|
||||||
|
name: "Cosine",
|
||||||
|
unit: "deg",
|
||||||
|
formatString: '%0.2f',
|
||||||
|
hints: {
|
||||||
|
range: 2,
|
||||||
|
spectralAttribute: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'example.spectral-aggregate-generator': {
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
key: "name",
|
||||||
|
name: "Name",
|
||||||
|
format: "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "utc",
|
||||||
|
name: "Time",
|
||||||
|
format: "utc",
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ch1",
|
||||||
|
name: "Channel 1",
|
||||||
|
format: "string",
|
||||||
|
hints: {
|
||||||
|
range: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ch2",
|
||||||
|
name: "Channel 2",
|
||||||
|
format: "string",
|
||||||
|
hints: {
|
||||||
|
range: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ch3",
|
||||||
|
name: "Channel 3",
|
||||||
|
format: "string",
|
||||||
|
hints: {
|
||||||
|
range: 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ch4",
|
||||||
|
name: "Channel 4",
|
||||||
|
format: "string",
|
||||||
|
hints: {
|
||||||
|
range: 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ch5",
|
||||||
|
name: "Channel 5",
|
||||||
|
format: "string",
|
||||||
|
hints: {
|
||||||
|
range: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
86
example/generator/SpectralAggregateGeneratorProvider.js
Normal file
86
example/generator/SpectralAggregateGeneratorProvider.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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 SpectralAggregateGeneratorProvider() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function pointForTimestamp(timestamp, count, name) {
|
||||||
|
return {
|
||||||
|
name: name,
|
||||||
|
utc: String(Math.floor(timestamp / count) * count),
|
||||||
|
ch1: String(Math.floor(timestamp / count) % 1),
|
||||||
|
ch2: String(Math.floor(timestamp / count) % 2),
|
||||||
|
ch3: String(Math.floor(timestamp / count) % 3),
|
||||||
|
ch4: String(Math.floor(timestamp / count) % 4),
|
||||||
|
ch5: String(Math.floor(timestamp / count) % 5)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
SpectralAggregateGeneratorProvider.prototype.supportsSubscribe = function (domainObject) {
|
||||||
|
return domainObject.type === 'example.spectral-aggregate-generator';
|
||||||
|
};
|
||||||
|
|
||||||
|
SpectralAggregateGeneratorProvider.prototype.subscribe = function (domainObject, callback) {
|
||||||
|
var count = 5000;
|
||||||
|
|
||||||
|
var interval = setInterval(function () {
|
||||||
|
var now = Date.now();
|
||||||
|
var datum = pointForTimestamp(now, count, domainObject.name);
|
||||||
|
callback(datum);
|
||||||
|
}, count);
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
clearInterval(interval);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
SpectralAggregateGeneratorProvider.prototype.supportsRequest = function (domainObject, options) {
|
||||||
|
return domainObject.type === 'example.spectral-aggregate-generator';
|
||||||
|
};
|
||||||
|
|
||||||
|
SpectralAggregateGeneratorProvider.prototype.request = function (domainObject, options) {
|
||||||
|
var start = options.start;
|
||||||
|
var end = Math.min(Date.now(), options.end); // no future values
|
||||||
|
var count = 5000;
|
||||||
|
if (options.strategy === 'latest' || options.size === 1) {
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = [];
|
||||||
|
while (start <= end && data.length < 5000) {
|
||||||
|
data.push(pointForTimestamp(start, count, domainObject.name));
|
||||||
|
start += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
return SpectralAggregateGeneratorProvider;
|
||||||
|
|
||||||
|
});
|
102
example/generator/SpectralGeneratorProvider.js
Normal file
102
example/generator/SpectralGeneratorProvider.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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([
|
||||||
|
'./WorkerInterface'
|
||||||
|
], function (
|
||||||
|
WorkerInterface
|
||||||
|
) {
|
||||||
|
|
||||||
|
var REQUEST_DEFAULTS = {
|
||||||
|
amplitude: 1,
|
||||||
|
wavelength: 1,
|
||||||
|
period: 10,
|
||||||
|
offset: 0,
|
||||||
|
dataRateInHz: 1,
|
||||||
|
randomness: 0,
|
||||||
|
phase: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
function SpectralGeneratorProvider() {
|
||||||
|
this.workerInterface = new WorkerInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
SpectralGeneratorProvider.prototype.canProvideTelemetry = function (domainObject) {
|
||||||
|
return domainObject.type === 'example.spectral-generator';
|
||||||
|
};
|
||||||
|
|
||||||
|
SpectralGeneratorProvider.prototype.supportsRequest =
|
||||||
|
SpectralGeneratorProvider.prototype.supportsSubscribe =
|
||||||
|
SpectralGeneratorProvider.prototype.canProvideTelemetry;
|
||||||
|
|
||||||
|
SpectralGeneratorProvider.prototype.makeWorkerRequest = function (domainObject, request = {}) {
|
||||||
|
var props = [
|
||||||
|
'amplitude',
|
||||||
|
'wavelength',
|
||||||
|
'period',
|
||||||
|
'offset',
|
||||||
|
'dataRateInHz',
|
||||||
|
'phase',
|
||||||
|
'randomness'
|
||||||
|
];
|
||||||
|
|
||||||
|
var workerRequest = {};
|
||||||
|
|
||||||
|
props.forEach(function (prop) {
|
||||||
|
if (domainObject.telemetry && Object.prototype.hasOwnProperty.call(domainObject.telemetry, prop)) {
|
||||||
|
workerRequest[prop] = domainObject.telemetry[prop];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request && Object.prototype.hasOwnProperty.call(request, prop)) {
|
||||||
|
workerRequest[prop] = request[prop];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(workerRequest, prop)) {
|
||||||
|
workerRequest[prop] = REQUEST_DEFAULTS[prop];
|
||||||
|
}
|
||||||
|
|
||||||
|
workerRequest[prop] = Number(workerRequest[prop]);
|
||||||
|
});
|
||||||
|
|
||||||
|
workerRequest.name = domainObject.name;
|
||||||
|
|
||||||
|
return workerRequest;
|
||||||
|
};
|
||||||
|
|
||||||
|
SpectralGeneratorProvider.prototype.request = function (domainObject, request) {
|
||||||
|
var workerRequest = this.makeWorkerRequest(domainObject, request);
|
||||||
|
workerRequest.start = request.start;
|
||||||
|
workerRequest.end = request.end;
|
||||||
|
workerRequest.spectra = true;
|
||||||
|
|
||||||
|
return this.workerInterface.request(workerRequest);
|
||||||
|
};
|
||||||
|
|
||||||
|
SpectralGeneratorProvider.prototype.subscribe = function (domainObject, callback) {
|
||||||
|
var workerRequest = this.makeWorkerRequest(domainObject, {});
|
||||||
|
workerRequest.spectra = true;
|
||||||
|
|
||||||
|
return this.workerInterface.subscribe(workerRequest, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
return SpectralGeneratorProvider;
|
||||||
|
});
|
@ -54,23 +54,38 @@
|
|||||||
var start = Date.now();
|
var start = Date.now();
|
||||||
var step = 1000 / data.dataRateInHz;
|
var step = 1000 / data.dataRateInHz;
|
||||||
var nextStep = start - (start % step) + step;
|
var nextStep = start - (start % step) + step;
|
||||||
|
let work;
|
||||||
|
if (data.spectra) {
|
||||||
|
work = function (now) {
|
||||||
|
while (nextStep < now) {
|
||||||
|
const messageCopy = Object.create(message);
|
||||||
|
message.data.start = nextStep - (60 * 1000);
|
||||||
|
message.data.end = nextStep;
|
||||||
|
onRequest(messageCopy);
|
||||||
|
nextStep += step;
|
||||||
|
}
|
||||||
|
|
||||||
function work(now) {
|
return nextStep;
|
||||||
while (nextStep < now) {
|
};
|
||||||
self.postMessage({
|
} else {
|
||||||
id: message.id,
|
work = function (now) {
|
||||||
data: {
|
while (nextStep < now) {
|
||||||
name: data.name,
|
self.postMessage({
|
||||||
utc: nextStep,
|
id: message.id,
|
||||||
yesterday: nextStep - 60 * 60 * 24 * 1000,
|
data: {
|
||||||
sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness),
|
name: data.name,
|
||||||
cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness)
|
utc: nextStep,
|
||||||
}
|
yesterday: nextStep - 60 * 60 * 24 * 1000,
|
||||||
});
|
sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness),
|
||||||
nextStep += step;
|
wavelength: wavelength(start, nextStep),
|
||||||
}
|
cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nextStep += step;
|
||||||
|
}
|
||||||
|
|
||||||
return nextStep;
|
return nextStep;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
subscriptions[message.id] = work;
|
subscriptions[message.id] = work;
|
||||||
@ -111,13 +126,21 @@
|
|||||||
utc: nextStep,
|
utc: nextStep,
|
||||||
yesterday: nextStep - 60 * 60 * 24 * 1000,
|
yesterday: nextStep - 60 * 60 * 24 * 1000,
|
||||||
sin: sin(nextStep, period, amplitude, offset, phase, randomness),
|
sin: sin(nextStep, period, amplitude, offset, phase, randomness),
|
||||||
|
wavelength: wavelength(start, nextStep),
|
||||||
cos: cos(nextStep, period, amplitude, offset, phase, randomness)
|
cos: cos(nextStep, period, amplitude, offset, phase, randomness)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
id: message.id,
|
id: message.id,
|
||||||
data: data
|
data: request.spectra ? {
|
||||||
|
wavelength: data.map((item) => {
|
||||||
|
return item.wavelength;
|
||||||
|
}),
|
||||||
|
cos: data.map((item) => {
|
||||||
|
return item.cos;
|
||||||
|
})
|
||||||
|
} : data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +154,10 @@
|
|||||||
* Math.sin(phase + (timestamp / period / 1000 * Math.PI * 2)) + (amplitude * Math.random() * randomness) + offset;
|
* Math.sin(phase + (timestamp / period / 1000 * Math.PI * 2)) + (amplitude * Math.random() * randomness) + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wavelength(start, nextStep) {
|
||||||
|
return (nextStep - start) / 10;
|
||||||
|
}
|
||||||
|
|
||||||
function sendError(error, message) {
|
function sendError(error, message) {
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
error: error.name + ': ' + error.message,
|
error: error.name + ': ' + error.message,
|
||||||
|
@ -24,11 +24,15 @@ define([
|
|||||||
"./GeneratorProvider",
|
"./GeneratorProvider",
|
||||||
"./SinewaveLimitProvider",
|
"./SinewaveLimitProvider",
|
||||||
"./StateGeneratorProvider",
|
"./StateGeneratorProvider",
|
||||||
|
"./SpectralGeneratorProvider",
|
||||||
|
"./SpectralAggregateGeneratorProvider",
|
||||||
"./GeneratorMetadataProvider"
|
"./GeneratorMetadataProvider"
|
||||||
], function (
|
], function (
|
||||||
GeneratorProvider,
|
GeneratorProvider,
|
||||||
SinewaveLimitProvider,
|
SinewaveLimitProvider,
|
||||||
StateGeneratorProvider,
|
StateGeneratorProvider,
|
||||||
|
SpectralGeneratorProvider,
|
||||||
|
SpectralAggregateGeneratorProvider,
|
||||||
GeneratorMetadataProvider
|
GeneratorMetadataProvider
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -61,6 +65,37 @@ define([
|
|||||||
|
|
||||||
openmct.telemetry.addProvider(new StateGeneratorProvider());
|
openmct.telemetry.addProvider(new StateGeneratorProvider());
|
||||||
|
|
||||||
|
openmct.types.addType("example.spectral-generator", {
|
||||||
|
name: "Spectral Generator",
|
||||||
|
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
|
||||||
|
cssClass: "icon-generator-telemetry",
|
||||||
|
creatable: true,
|
||||||
|
initialize: function (object) {
|
||||||
|
object.telemetry = {
|
||||||
|
period: 10,
|
||||||
|
amplitude: 1,
|
||||||
|
wavelength: 1,
|
||||||
|
frequency: 1,
|
||||||
|
offset: 0,
|
||||||
|
dataRateInHz: 1,
|
||||||
|
phase: 0,
|
||||||
|
randomness: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
openmct.telemetry.addProvider(new SpectralGeneratorProvider());
|
||||||
|
|
||||||
|
openmct.types.addType("example.spectral-aggregate-generator", {
|
||||||
|
name: "Spectral Aggregate Generator",
|
||||||
|
description: "For development use. Generates example streaming telemetry data using a simple state algorithm.",
|
||||||
|
cssClass: "icon-generator-telemetry",
|
||||||
|
creatable: true,
|
||||||
|
initialize: function (object) {
|
||||||
|
object.telemetry = {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
openmct.telemetry.addProvider(new SpectralAggregateGeneratorProvider());
|
||||||
|
|
||||||
openmct.types.addType("generator", {
|
openmct.types.addType("generator", {
|
||||||
name: "Sine Wave Generator",
|
name: "Sine Wave Generator",
|
||||||
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
|
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
|
||||||
|
14
package.json
14
package.json
@ -2,7 +2,6 @@
|
|||||||
"name": "openmct",
|
"name": "openmct",
|
||||||
"version": "1.7.8-SNAPSHOT",
|
"version": "1.7.8-SNAPSHOT",
|
||||||
"description": "The Open MCT core platform",
|
"description": "The Open MCT core platform",
|
||||||
"dependencies": {},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"angular": ">=1.8.0",
|
"angular": ">=1.8.0",
|
||||||
"angular-route": "1.4.14",
|
"angular-route": "1.4.14",
|
||||||
@ -12,16 +11,9 @@
|
|||||||
"copy-webpack-plugin": "^4.5.2",
|
"copy-webpack-plugin": "^4.5.2",
|
||||||
"cross-env": "^6.0.3",
|
"cross-env": "^6.0.3",
|
||||||
"css-loader": "^1.0.0",
|
"css-loader": "^1.0.0",
|
||||||
"d3-array": "1.2.x",
|
|
||||||
"d3-axis": "1.0.x",
|
"d3-axis": "1.0.x",
|
||||||
"d3-collection": "1.0.x",
|
|
||||||
"d3-color": "1.0.x",
|
|
||||||
"d3-format": "1.2.x",
|
|
||||||
"d3-interpolate": "1.1.x",
|
|
||||||
"d3-scale": "1.0.x",
|
"d3-scale": "1.0.x",
|
||||||
"d3-selection": "1.3.x",
|
"d3-selection": "1.3.x",
|
||||||
"d3-time": "1.0.x",
|
|
||||||
"d3-time-format": "2.1.x",
|
|
||||||
"eslint": "7.0.0",
|
"eslint": "7.0.0",
|
||||||
"eslint-plugin-vue": "^7.5.0",
|
"eslint-plugin-vue": "^7.5.0",
|
||||||
"eslint-plugin-you-dont-need-lodash-underscore": "^6.10.0",
|
"eslint-plugin-you-dont-need-lodash-underscore": "^6.10.0",
|
||||||
@ -41,13 +33,13 @@
|
|||||||
"jsdoc": "^3.3.2",
|
"jsdoc": "^3.3.2",
|
||||||
"karma": "6.3.4",
|
"karma": "6.3.4",
|
||||||
"karma-chrome-launcher": "3.1.0",
|
"karma-chrome-launcher": "3.1.0",
|
||||||
"karma-firefox-launcher": "2.1.1",
|
|
||||||
"karma-cli": "2.0.0",
|
"karma-cli": "2.0.0",
|
||||||
"karma-coverage": "2.0.3",
|
"karma-coverage": "2.0.3",
|
||||||
"karma-coverage-istanbul-reporter": "3.0.3",
|
"karma-coverage-istanbul-reporter": "3.0.3",
|
||||||
"karma-junit-reporter": "2.0.1",
|
"karma-firefox-launcher": "2.1.1",
|
||||||
"karma-html-reporter": "0.2.7",
|
"karma-html-reporter": "0.2.7",
|
||||||
"karma-jasmine": "4.0.1",
|
"karma-jasmine": "4.0.1",
|
||||||
|
"karma-junit-reporter": "2.0.1",
|
||||||
"karma-sourcemap-loader": "0.3.8",
|
"karma-sourcemap-loader": "0.3.8",
|
||||||
"karma-webpack": "4.0.2",
|
"karma-webpack": "4.0.2",
|
||||||
"location-bar": "^3.0.1",
|
"location-bar": "^3.0.1",
|
||||||
@ -62,6 +54,8 @@
|
|||||||
"node-bourbon": "^4.2.3",
|
"node-bourbon": "^4.2.3",
|
||||||
"node-sass": "^4.14.1",
|
"node-sass": "^4.14.1",
|
||||||
"painterro": "^1.2.56",
|
"painterro": "^1.2.56",
|
||||||
|
"plotly.js-basic-dist": "^2.5.0",
|
||||||
|
"plotly.js-gl2d-dist": "^2.5.0",
|
||||||
"printj": "^1.2.1",
|
"printj": "^1.2.1",
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
"request": "^2.69.0",
|
"request": "^2.69.0",
|
||||||
|
170
src/plugins/plot/ColorSwatch.vue
Normal file
170
src/plugins/plot/ColorSwatch.vue
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2020, 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.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="u-contents">
|
||||||
|
<ul v-if="canEdit"
|
||||||
|
class="l-inspector-part"
|
||||||
|
>
|
||||||
|
<h2 v-if="heading"
|
||||||
|
:title="heading"
|
||||||
|
>{{ heading }}</h2>
|
||||||
|
<li class="grid-row">
|
||||||
|
<div class="grid-cell label"
|
||||||
|
:title="editTitle"
|
||||||
|
>{{ shortLabel }}</div>
|
||||||
|
<div class="grid-cell value">
|
||||||
|
<div class="c-click-swatch c-click-swatch--menu"
|
||||||
|
@click="toggleSwatch()"
|
||||||
|
>
|
||||||
|
<span class="c-color-swatch"
|
||||||
|
:style="{ background: currentColor }"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="c-palette c-palette--color">
|
||||||
|
<div v-show="swatchActive"
|
||||||
|
class="c-palette__items"
|
||||||
|
>
|
||||||
|
<div v-for="group in colorPaletteGroups"
|
||||||
|
:key="group.id"
|
||||||
|
class="u-contents"
|
||||||
|
>
|
||||||
|
<div v-for="color in group"
|
||||||
|
:key="color.id"
|
||||||
|
class="c-palette__item"
|
||||||
|
:class="{ 'selected': currentColor === color.hexString }"
|
||||||
|
:style="{ background: color.hexString }"
|
||||||
|
@click="setColor(color)"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul v-else
|
||||||
|
class="l-inspector-part"
|
||||||
|
>
|
||||||
|
<h2 v-if="heading"
|
||||||
|
:title="heading"
|
||||||
|
>{{ heading }}</h2>
|
||||||
|
<li class="grid-row">
|
||||||
|
<div class="grid-cell label"
|
||||||
|
:title="viewTitle"
|
||||||
|
>{{ shortLabel }}</div>
|
||||||
|
<div class="grid-cell value">
|
||||||
|
<span class="c-color-swatch"
|
||||||
|
:style="{
|
||||||
|
'background': currentColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ColorPalette from './lib/ColorPalette';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['openmct', 'domainObject'],
|
||||||
|
props: {
|
||||||
|
currentColor: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
editTitle: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return 'Set the color.';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
viewTitle: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return 'The current color.';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shortLabel: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return 'Color';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
heading: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
swatchActive: false,
|
||||||
|
colorPaletteGroups: [],
|
||||||
|
isEditing: this.openmct.editor.isEditing()
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
canEdit() {
|
||||||
|
return this.isEditing && !this.domainObject.locked;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.colorPalette = new ColorPalette();
|
||||||
|
this.openmct.editor.on('isEditing', this.setEditState);
|
||||||
|
this.initialize();
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.openmct.editor.off('isEditing', this.setEditState);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initialize() {
|
||||||
|
const colorPaletteGroups = this.colorPalette.groups();
|
||||||
|
colorPaletteGroups.forEach((group, index) => {
|
||||||
|
let groupId = [];
|
||||||
|
group.forEach(color => {
|
||||||
|
color.hexString = color.asHexString();
|
||||||
|
color.id = `${color.hexString}-${index}`;
|
||||||
|
groupId.push(color.id);
|
||||||
|
});
|
||||||
|
group.id = groupId.join('-');
|
||||||
|
});
|
||||||
|
this.colorPaletteGroups = colorPaletteGroups;
|
||||||
|
},
|
||||||
|
setEditState(isEditing) {
|
||||||
|
this.isEditing = isEditing;
|
||||||
|
},
|
||||||
|
setColor(chosenColor) {
|
||||||
|
this.$emit('colorSet', chosenColor);
|
||||||
|
},
|
||||||
|
toggleSwatch() {
|
||||||
|
this.swatchActive = !this.swatchActive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -156,7 +156,7 @@
|
|||||||
import eventHelpers from './lib/eventHelpers';
|
import eventHelpers from './lib/eventHelpers';
|
||||||
import LinearScale from "./LinearScale";
|
import LinearScale from "./LinearScale";
|
||||||
import PlotConfigurationModel from './configuration/PlotConfigurationModel';
|
import PlotConfigurationModel from './configuration/PlotConfigurationModel';
|
||||||
import configStore from './configuration/configStore';
|
import configStore from './configuration/ConfigStore';
|
||||||
|
|
||||||
import PlotLegend from "./legend/PlotLegend.vue";
|
import PlotLegend from "./legend/PlotLegend.vue";
|
||||||
import MctTicks from "./MctTicks.vue";
|
import MctTicks from "./MctTicks.vue";
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import eventHelpers from "./lib/eventHelpers";
|
import eventHelpers from "./lib/eventHelpers";
|
||||||
import { ticks, getFormattedTicks } from "./tickUtils";
|
import { ticks, getFormattedTicks } from "./tickUtils";
|
||||||
import configStore from "./configuration/configStore";
|
import configStore from "./configuration/ConfigStore";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'domainObject'],
|
inject: ['openmct', 'domainObject'],
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import MctTicks from "../MctTicks.vue";
|
import MctTicks from "../MctTicks.vue";
|
||||||
import eventHelpers from '../lib/eventHelpers';
|
import eventHelpers from '../lib/eventHelpers';
|
||||||
import configStore from "../configuration/configStore";
|
import configStore from "../configuration/ConfigStore";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MctTicks from "../MctTicks.vue";
|
import MctTicks from "../MctTicks.vue";
|
||||||
import configStore from "../configuration/configStore";
|
import configStore from "../configuration/ConfigStore";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
57
src/plugins/plot/barGraph/BarGraphCompositionPolicy.js
Normal file
57
src/plugins/plot/barGraph/BarGraphCompositionPolicy.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import { BAR_GRAPH_KEY } from './BarGraphConstants';
|
||||||
|
|
||||||
|
export default function BarGraphCompositionPolicy(openmct) {
|
||||||
|
function hasAggregateDomainAndRange(metadata) {
|
||||||
|
const rangeValues = metadata.valuesForHints(['range']);
|
||||||
|
|
||||||
|
return rangeValues.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasBarGraphTelemetry(domainObject) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(domainObject, 'telemetry')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let metadata = openmct.telemetry.getMetadata(domainObject);
|
||||||
|
|
||||||
|
return metadata.values().length > 0 && hasAggregateDomainAndRange(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasNoChildren(parentObject) {
|
||||||
|
return parentObject.composition && parentObject.composition.length < 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
allow: function (parent, child) {
|
||||||
|
if ((parent.type === BAR_GRAPH_KEY)
|
||||||
|
&& ((child.type !== 'telemetry.plot.overlay') && (hasBarGraphTelemetry(child) === false))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
346
src/plugins/plot/barGraph/BarGraphCompositionPolicySpec.js
Normal file
346
src/plugins/plot/barGraph/BarGraphCompositionPolicySpec.js
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import BarGraphCompositionPolicy from "./BarGraphCompositionPolicy";
|
||||||
|
import { createOpenMct } from "utils/testing";
|
||||||
|
|
||||||
|
describe("The bar graph composition policy", () => {
|
||||||
|
let openmct;
|
||||||
|
const mockMetaDataWithNoRangeHints = {
|
||||||
|
"period": 10,
|
||||||
|
"amplitude": 1,
|
||||||
|
"offset": 0,
|
||||||
|
"dataRateInHz": 1,
|
||||||
|
"phase": 0,
|
||||||
|
"randomness": 0,
|
||||||
|
valuesForHints: () => {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
"key": "name",
|
||||||
|
"name": "Name",
|
||||||
|
"format": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "utc",
|
||||||
|
"name": "Time",
|
||||||
|
"format": "utc",
|
||||||
|
"hints": {
|
||||||
|
"domain": 1,
|
||||||
|
"priority": 1
|
||||||
|
},
|
||||||
|
"source": "utc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
const mockMetaDataWithRangeHints = {
|
||||||
|
"period": 10,
|
||||||
|
"amplitude": 1,
|
||||||
|
"offset": 0,
|
||||||
|
"dataRateInHz": 1,
|
||||||
|
"phase": 0,
|
||||||
|
"randomness": 0,
|
||||||
|
"wavelength": 0,
|
||||||
|
valuesForHints: () => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"key": "sin",
|
||||||
|
"name": "Sine",
|
||||||
|
"unit": "Hz",
|
||||||
|
"formatString": "%0.2f",
|
||||||
|
"hints": {
|
||||||
|
"range": 1,
|
||||||
|
"priority": 4
|
||||||
|
},
|
||||||
|
"source": "sin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "cos",
|
||||||
|
"name": "Cosine",
|
||||||
|
"unit": "deg",
|
||||||
|
"formatString": "%0.2f",
|
||||||
|
"hints": {
|
||||||
|
"range": 2,
|
||||||
|
"priority": 5
|
||||||
|
},
|
||||||
|
"source": "cos"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
},
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
"key": "name",
|
||||||
|
"name": "Name",
|
||||||
|
"format": "string",
|
||||||
|
"source": "name",
|
||||||
|
"hints": {
|
||||||
|
"priority": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "utc",
|
||||||
|
"name": "Time",
|
||||||
|
"format": "utc",
|
||||||
|
"hints": {
|
||||||
|
"domain": 1,
|
||||||
|
"priority": 1
|
||||||
|
},
|
||||||
|
"source": "utc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "yesterday",
|
||||||
|
"name": "Yesterday",
|
||||||
|
"format": "utc",
|
||||||
|
"hints": {
|
||||||
|
"domain": 2,
|
||||||
|
"priority": 2
|
||||||
|
},
|
||||||
|
"source": "yesterday"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "sin",
|
||||||
|
"name": "Sine",
|
||||||
|
"unit": "Hz",
|
||||||
|
"formatString": "%0.2f",
|
||||||
|
"hints": {
|
||||||
|
"range": 1,
|
||||||
|
"spectralAttribute": true
|
||||||
|
},
|
||||||
|
"source": "sin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "cos",
|
||||||
|
"name": "Cosine",
|
||||||
|
"unit": "deg",
|
||||||
|
"formatString": "%0.2f",
|
||||||
|
"hints": {
|
||||||
|
"range": 2,
|
||||||
|
"priority": 5
|
||||||
|
},
|
||||||
|
"source": "cos"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
openmct = createOpenMct();
|
||||||
|
const mockTypeDef = {
|
||||||
|
telemetry: mockMetaDataWithRangeHints
|
||||||
|
};
|
||||||
|
const mockTypeService = {
|
||||||
|
getType: () => {
|
||||||
|
return {
|
||||||
|
typeDef: mockTypeDef
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
openmct.$injector = {
|
||||||
|
get: () => {
|
||||||
|
return mockTypeService;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
openmct.telemetry.isTelemetryObject = function (domainObject) {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exists", () => {
|
||||||
|
expect(BarGraphCompositionPolicy(openmct).allow).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
xit("allow composition for telemetry that provides/supports bar graph meta data", () => {
|
||||||
|
const parent = {
|
||||||
|
"composition": [],
|
||||||
|
"configuration": {},
|
||||||
|
"name": "Some Bar Graph",
|
||||||
|
"type": "telemetry.plot.bar-graph",
|
||||||
|
"location": "mine",
|
||||||
|
"modified": 1631005183584,
|
||||||
|
"persisted": 1631005183502,
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const child = {
|
||||||
|
"telemetry": {
|
||||||
|
"period": 10,
|
||||||
|
"amplitude": 1,
|
||||||
|
"offset": 0,
|
||||||
|
"dataRateInHz": 1,
|
||||||
|
"phase": 0,
|
||||||
|
"randomness": 0
|
||||||
|
},
|
||||||
|
"name": "Unnamed Sine Wave Generator",
|
||||||
|
"type": "generator",
|
||||||
|
"location": "mine",
|
||||||
|
"modified": 1630399715531,
|
||||||
|
"persisted": 1630399715531,
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(BarGraphCompositionPolicy(openmct).allow(parent, child)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows composition for telemetry that contain at least one range", () => {
|
||||||
|
const mockTypeDef = {
|
||||||
|
telemetry: mockMetaDataWithRangeHints
|
||||||
|
};
|
||||||
|
const mockTypeService = {
|
||||||
|
getType: () => {
|
||||||
|
return {
|
||||||
|
typeDef: mockTypeDef
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
openmct.$injector = {
|
||||||
|
get: () => {
|
||||||
|
return mockTypeService;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const parent = {
|
||||||
|
"composition": [],
|
||||||
|
"configuration": {},
|
||||||
|
"name": "Some Bar Graph",
|
||||||
|
"type": "telemetry.plot.bar-graph",
|
||||||
|
"location": "mine",
|
||||||
|
"modified": 1631005183584,
|
||||||
|
"persisted": 1631005183502,
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const child = {
|
||||||
|
"telemetry": {
|
||||||
|
"period": 10,
|
||||||
|
"amplitude": 1,
|
||||||
|
"offset": 0,
|
||||||
|
"dataRateInHz": 1,
|
||||||
|
"phase": 0,
|
||||||
|
"randomness": 0
|
||||||
|
},
|
||||||
|
"name": "Unnamed Sine Wave Generator",
|
||||||
|
"type": "generator",
|
||||||
|
"location": "mine",
|
||||||
|
"modified": 1630399715531,
|
||||||
|
"persisted": 1630399715531,
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(BarGraphCompositionPolicy(openmct).allow(parent, child)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("disallows composition for telemetry that don't contain any range hints", () => {
|
||||||
|
const mockTypeDef = {
|
||||||
|
telemetry: mockMetaDataWithNoRangeHints
|
||||||
|
};
|
||||||
|
const mockTypeService = {
|
||||||
|
getType: () => {
|
||||||
|
return {
|
||||||
|
typeDef: mockTypeDef
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
openmct.$injector = {
|
||||||
|
get: () => {
|
||||||
|
return mockTypeService;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const parent = {
|
||||||
|
"composition": [],
|
||||||
|
"configuration": {},
|
||||||
|
"name": "Some Bar Graph",
|
||||||
|
"type": "telemetry.plot.bar-graph",
|
||||||
|
"location": "mine",
|
||||||
|
"modified": 1631005183584,
|
||||||
|
"persisted": 1631005183502,
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const child = {
|
||||||
|
"telemetry": {
|
||||||
|
"period": 10,
|
||||||
|
"amplitude": 1,
|
||||||
|
"offset": 0,
|
||||||
|
"dataRateInHz": 1,
|
||||||
|
"phase": 0,
|
||||||
|
"randomness": 0
|
||||||
|
},
|
||||||
|
"name": "Unnamed Sine Wave Generator",
|
||||||
|
"type": "generator",
|
||||||
|
"location": "mine",
|
||||||
|
"modified": 1630399715531,
|
||||||
|
"persisted": 1630399715531,
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(BarGraphCompositionPolicy(openmct).allow(parent, child)).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passthrough for composition for non bar graph plots", () => {
|
||||||
|
const parent = {
|
||||||
|
"composition": [],
|
||||||
|
"configuration": {},
|
||||||
|
"name": "Some Stacked Plot",
|
||||||
|
"type": "telemetry.plot.stacked",
|
||||||
|
"location": "mine",
|
||||||
|
"modified": 1631005183584,
|
||||||
|
"persisted": 1631005183502,
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const child = {
|
||||||
|
"telemetry": {
|
||||||
|
"period": 10,
|
||||||
|
"amplitude": 1,
|
||||||
|
"offset": 0,
|
||||||
|
"dataRateInHz": 1,
|
||||||
|
"phase": 0,
|
||||||
|
"randomness": 0
|
||||||
|
},
|
||||||
|
"name": "Unnamed Sine Wave Generator",
|
||||||
|
"type": "generator",
|
||||||
|
"location": "mine",
|
||||||
|
"modified": 1630399715531,
|
||||||
|
"persisted": 1630399715531,
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(BarGraphCompositionPolicy(openmct).allow(parent, child)).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
5
src/plugins/plot/barGraph/BarGraphConstants.js
Normal file
5
src/plugins/plot/barGraph/BarGraphConstants.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const BAR_GRAPH_VIEW = 'bar-graph.view';
|
||||||
|
export const BAR_GRAPH_KEY = 'telemetry.plot.bar-graph';
|
||||||
|
export const BAR_GRAPH_INSPECTOR_KEY = 'telemetry.plot.bar-graph.inspector';
|
||||||
|
export const SUBSCRIBE = 'subscribe';
|
||||||
|
export const UNSUBSCRIBE = 'unsubscribe';
|
293
src/plugins/plot/barGraph/BarGraphPlot.vue
Normal file
293
src/plugins/plot/barGraph/BarGraphPlot.vue
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="plotWrapper"
|
||||||
|
class="has-local-controls"
|
||||||
|
:class="{ 's-unsynced' : isZoomed }"
|
||||||
|
>
|
||||||
|
<div v-if="isZoomed"
|
||||||
|
class="l-state-indicators"
|
||||||
|
>
|
||||||
|
<span class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle"
|
||||||
|
title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data."
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
<div ref="plot"
|
||||||
|
class="c-bar-chart"
|
||||||
|
></div>
|
||||||
|
<div v-if="false"
|
||||||
|
ref="localControl"
|
||||||
|
class="gl-plot__local-controls h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover"
|
||||||
|
>
|
||||||
|
<button v-if="data.length"
|
||||||
|
class="c-button icon-reset"
|
||||||
|
:disabled="!isZoomed"
|
||||||
|
title="Reset pan/zoom"
|
||||||
|
@click="reset()"
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Plotly from 'plotly.js-basic-dist';
|
||||||
|
import { SUBSCRIBE, UNSUBSCRIBE } from './BarGraphConstants';
|
||||||
|
|
||||||
|
const MULTI_AXES_X_PADDING_PERCENT = {
|
||||||
|
LEFT: 8,
|
||||||
|
RIGHT: 94
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['openmct', 'domainObject'],
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plotAxisTitle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isZoomed: false,
|
||||||
|
primaryYAxisRange: {
|
||||||
|
min: '',
|
||||||
|
max: ''
|
||||||
|
},
|
||||||
|
xAxisRange: {
|
||||||
|
min: '',
|
||||||
|
max: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
data: {
|
||||||
|
immediate: false,
|
||||||
|
handler: 'updateData'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Plotly.newPlot(this.$refs.plot, Array.from(this.data), this.getLayout(), {
|
||||||
|
responsive: true,
|
||||||
|
displayModeBar: false
|
||||||
|
});
|
||||||
|
this.registerListeners();
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.$refs.plot.removeAllListeners();
|
||||||
|
|
||||||
|
if (this.plotResizeObserver) {
|
||||||
|
this.plotResizeObserver.unobserve(this.$refs.plotWrapper);
|
||||||
|
clearTimeout(this.resizeTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.removeBarColorListener) {
|
||||||
|
this.removeBarColorListener();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getAxisMinMax(axis) {
|
||||||
|
const min = axis.autoSize
|
||||||
|
? ''
|
||||||
|
: axis.min;
|
||||||
|
const max = axis.autoSize
|
||||||
|
? ''
|
||||||
|
: axis.max;
|
||||||
|
|
||||||
|
return {
|
||||||
|
min,
|
||||||
|
max
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getLayout() {
|
||||||
|
const yAxesMeta = this.getYAxisMeta();
|
||||||
|
const primaryYaxis = this.getYaxisLayout(yAxesMeta['1']);
|
||||||
|
const xAxisDomain = this.getXAxisDomain(yAxesMeta);
|
||||||
|
|
||||||
|
return {
|
||||||
|
autosize: true,
|
||||||
|
showlegend: false,
|
||||||
|
textposition: 'auto',
|
||||||
|
font: {
|
||||||
|
family: 'Helvetica Neue, Helvetica, Arial, sans-serif',
|
||||||
|
size: '12px',
|
||||||
|
color: '#666'
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
domain: xAxisDomain,
|
||||||
|
range: [this.xAxisRange.min, this.xAxisRange.max],
|
||||||
|
title: this.plotAxisTitle.xAxisTitle,
|
||||||
|
automargin: true,
|
||||||
|
fixedrange: true
|
||||||
|
},
|
||||||
|
yaxis: primaryYaxis,
|
||||||
|
margin: {
|
||||||
|
l: 5,
|
||||||
|
r: 5,
|
||||||
|
t: 5,
|
||||||
|
b: 0
|
||||||
|
},
|
||||||
|
paper_bgcolor: 'transparent',
|
||||||
|
plot_bgcolor: 'transparent'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getYAxisMeta() {
|
||||||
|
const yAxisMeta = {};
|
||||||
|
|
||||||
|
this.data.forEach(d => {
|
||||||
|
const yAxisMetadata = d.yAxisMetadata;
|
||||||
|
const range = '1';
|
||||||
|
const side = 'left';
|
||||||
|
const name = '';
|
||||||
|
const unit = yAxisMetadata.units;
|
||||||
|
|
||||||
|
yAxisMeta[range] = {
|
||||||
|
range,
|
||||||
|
side,
|
||||||
|
name,
|
||||||
|
unit
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return yAxisMeta;
|
||||||
|
},
|
||||||
|
getXAxisDomain(yAxisMeta) {
|
||||||
|
let leftPaddingPerc = 0;
|
||||||
|
let rightPaddingPerc = 100;
|
||||||
|
let rightSide = yAxisMeta && Object.values(yAxisMeta).filter((axisMeta => axisMeta.side === 'right'));
|
||||||
|
let leftSide = yAxisMeta && Object.values(yAxisMeta).filter((axisMeta => axisMeta.side === 'left'));
|
||||||
|
if (yAxisMeta && rightSide.length > 1) {
|
||||||
|
rightPaddingPerc = MULTI_AXES_X_PADDING_PERCENT.RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yAxisMeta && leftSide.length > 1) {
|
||||||
|
leftPaddingPerc = MULTI_AXES_X_PADDING_PERCENT.LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [leftPaddingPerc / 100, rightPaddingPerc / 100];
|
||||||
|
},
|
||||||
|
getYaxisLayout(yAxisMeta) {
|
||||||
|
if (!yAxisMeta) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, range, side = 'left', unit } = yAxisMeta;
|
||||||
|
const title = `${name} ${unit ? '(' + unit + ')' : ''}`;
|
||||||
|
const yaxis = {
|
||||||
|
automargin: true,
|
||||||
|
fixedrange: true,
|
||||||
|
title
|
||||||
|
};
|
||||||
|
|
||||||
|
let yAxistype = this.primaryYAxisRange;
|
||||||
|
if (range === '1') {
|
||||||
|
yaxis.range = [yAxistype.min, yAxistype.max];
|
||||||
|
|
||||||
|
return yaxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
yaxis.range = [yAxistype.min, yAxistype.max];
|
||||||
|
yaxis.anchor = side.toLowerCase() === 'left'
|
||||||
|
? 'free'
|
||||||
|
: 'x';
|
||||||
|
yaxis.showline = side.toLowerCase() === 'left';
|
||||||
|
yaxis.side = side.toLowerCase();
|
||||||
|
yaxis.overlaying = 'y';
|
||||||
|
yaxis.position = 0.01;
|
||||||
|
|
||||||
|
return yaxis;
|
||||||
|
},
|
||||||
|
registerListeners() {
|
||||||
|
this.$refs.plot.on('plotly_relayout', this.zoom);
|
||||||
|
|
||||||
|
this.removeBarColorListener = this.openmct.objects.observe(
|
||||||
|
this.domainObject,
|
||||||
|
'configuration.barStyles',
|
||||||
|
this.barColorChanged
|
||||||
|
);
|
||||||
|
this.resizeTimer = false;
|
||||||
|
if (window.ResizeObserver) {
|
||||||
|
this.plotResizeObserver = new ResizeObserver(() => {
|
||||||
|
// debounce and trigger window resize so that plotly can resize the plot
|
||||||
|
clearTimeout(this.resizeTimer);
|
||||||
|
this.resizeTimer = setTimeout(() => {
|
||||||
|
window.dispatchEvent(new Event('resize'));
|
||||||
|
}, 250);
|
||||||
|
});
|
||||||
|
this.plotResizeObserver.observe(this.$refs.plotWrapper);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reset() {
|
||||||
|
this.updatePlot();
|
||||||
|
|
||||||
|
this.isZoomed = false;
|
||||||
|
this.$emit(SUBSCRIBE);
|
||||||
|
},
|
||||||
|
barColorChanged() {
|
||||||
|
const colors = [];
|
||||||
|
const indices = [];
|
||||||
|
this.data.forEach((item, index) => {
|
||||||
|
const key = item.key;
|
||||||
|
const color = this.domainObject.configuration.barStyles[key] && this.domainObject.configuration.barStyles[key].color;
|
||||||
|
indices.push(index);
|
||||||
|
if (color) {
|
||||||
|
colors.push();
|
||||||
|
} else {
|
||||||
|
colors.push(item.marker.color);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const plotUpdate = {
|
||||||
|
'marker.color': colors
|
||||||
|
};
|
||||||
|
Plotly.restyle(this.$refs.plot, plotUpdate, indices);
|
||||||
|
},
|
||||||
|
updateData() {
|
||||||
|
this.updatePlot();
|
||||||
|
},
|
||||||
|
updateLocalControlPosition() {
|
||||||
|
const localControl = this.$refs.localControl;
|
||||||
|
localControl.style.display = 'none';
|
||||||
|
|
||||||
|
const plot = this.$refs.plot;
|
||||||
|
const bgLayer = this.$el.querySelector('.bglayer');
|
||||||
|
|
||||||
|
const plotBoundingRect = plot.getBoundingClientRect();
|
||||||
|
const bgLayerBoundingRect = bgLayer.getBoundingClientRect();
|
||||||
|
|
||||||
|
const top = bgLayerBoundingRect.top - plotBoundingRect.top + 5;
|
||||||
|
const left = bgLayerBoundingRect.left - plotBoundingRect.left + 5;
|
||||||
|
|
||||||
|
localControl.style.top = `${top}px`;
|
||||||
|
localControl.style.left = `${left}px`;
|
||||||
|
localControl.style.display = 'block';
|
||||||
|
},
|
||||||
|
updatePlot() {
|
||||||
|
if (!this.$refs || !this.$refs.plot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Plotly.react(this.$refs.plot, Array.from(this.data), this.getLayout());
|
||||||
|
},
|
||||||
|
zoom(eventData) {
|
||||||
|
const autorange = eventData['xaxis.autorange'];
|
||||||
|
const { autosize } = eventData;
|
||||||
|
|
||||||
|
if (autosize || autorange) {
|
||||||
|
this.isZoomed = false;
|
||||||
|
this.reset();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isZoomed = true;
|
||||||
|
this.$emit(UNSUBSCRIBE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
286
src/plugins/plot/barGraph/BarGraphView.vue
Normal file
286
src/plugins/plot/barGraph/BarGraphView.vue
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2021, 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<BarGraph ref="barGraph"
|
||||||
|
class="c-plot c-bar-chart-view"
|
||||||
|
:data="trace"
|
||||||
|
:plot-axis-title="plotAxisTitle"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as SPECTRAL_AGGREGATE from './BarGraphConstants';
|
||||||
|
import ColorPalette from '../lib/ColorPalette';
|
||||||
|
import BarGraph from './BarGraphPlot.vue';
|
||||||
|
import Color from "@/plugins/plot/lib/Color";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
BarGraph
|
||||||
|
},
|
||||||
|
inject: ['openmct', 'domainObject'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
composition: {},
|
||||||
|
currentDomainObject: this.domainObject,
|
||||||
|
subscriptions: [],
|
||||||
|
telemetryObjects: {},
|
||||||
|
trace: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
activeClock() {
|
||||||
|
return this.openmct.time.activeClock;
|
||||||
|
},
|
||||||
|
plotAxisTitle() {
|
||||||
|
const { xAxisMetadata = {}, yAxisMetadata = {} } = this.trace[0] || {};
|
||||||
|
const xAxisUnit = xAxisMetadata.units ? `(${xAxisMetadata.units})` : '';
|
||||||
|
const yAxisUnit = yAxisMetadata.units ? `(${yAxisMetadata.units})` : '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
xAxisTitle: `${xAxisMetadata.name || ''} ${xAxisUnit}`,
|
||||||
|
yAxisTitle: `${yAxisMetadata.name || ''} ${yAxisUnit}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.colorPalette = new ColorPalette();
|
||||||
|
this.loadComposition();
|
||||||
|
|
||||||
|
this.openmct.time.on('bounds', this.refreshData);
|
||||||
|
this.openmct.time.on('clock', this.clockChanged);
|
||||||
|
|
||||||
|
this.$refs.barGraph.$on(SPECTRAL_AGGREGATE.SUBSCRIBE, this.subscribeToAll);
|
||||||
|
this.$refs.barGraph.$on(SPECTRAL_AGGREGATE.UNSUBSCRIBE, this.removeAllSubscriptions);
|
||||||
|
|
||||||
|
this.unobserve = this.openmct.objects.observe(this.currentDomainObject, '*', this.updateDomainObject);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.$refs.barGraph.$off();
|
||||||
|
this.openmct.time.off('bounds', this.refreshData);
|
||||||
|
this.openmct.time.off('clock', this.clockChanged);
|
||||||
|
|
||||||
|
this.removeAllSubscriptions();
|
||||||
|
this.unobserve();
|
||||||
|
|
||||||
|
if (!this.composition) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.composition.off('add', this.addTelemetryObject);
|
||||||
|
this.composition.off('remove', this.removeTelemetryObject);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addTelemetryObject(telemetryObject) {
|
||||||
|
const key = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||||
|
|
||||||
|
if (!this.domainObject.configuration.barStyles) {
|
||||||
|
this.domainObject.configuration.barStyles = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// check to see if we've set a bar color
|
||||||
|
if (!this.domainObject.configuration.barStyles[key] || !this.domainObject.configuration.barStyles[key].color) {
|
||||||
|
const color = this.colorPalette.getNextColor().asHexString();
|
||||||
|
this.domainObject.configuration.barStyles[key] = {
|
||||||
|
name: telemetryObject.name,
|
||||||
|
color
|
||||||
|
};
|
||||||
|
this.openmct.objects.mutate(
|
||||||
|
this.domainObject,
|
||||||
|
`configuration.barStyles[${this.key}]`,
|
||||||
|
this.domainObject.configuration.barStyles[key]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let color = this.domainObject.configuration.barStyles[key].color;
|
||||||
|
if (!(color instanceof Color)) {
|
||||||
|
color = Color.fromHexString(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.colorPalette.remove(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.telemetryObjects[key] = telemetryObject;
|
||||||
|
|
||||||
|
this.requestDataFor(telemetryObject);
|
||||||
|
this.subscribeToObject(telemetryObject);
|
||||||
|
},
|
||||||
|
addTrace(trace, key) {
|
||||||
|
if (!this.trace.length) {
|
||||||
|
this.trace = this.trace.concat([trace]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isInTrace = false;
|
||||||
|
const newTrace = this.trace.map((currentTrace, index) => {
|
||||||
|
if (currentTrace.key !== key) {
|
||||||
|
return currentTrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
isInTrace = true;
|
||||||
|
|
||||||
|
return trace;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.trace = isInTrace ? newTrace : newTrace.concat([trace]);
|
||||||
|
},
|
||||||
|
clockChanged() {
|
||||||
|
this.removeAllSubscriptions();
|
||||||
|
this.subscribeToAll();
|
||||||
|
},
|
||||||
|
getAxisMetadata(telemetryObject) {
|
||||||
|
const metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||||
|
const yAxisMetadata = metadata.valuesForHints(['range'])[0];
|
||||||
|
//Exclude 'name' and 'time' based metadata specifically, from the x-Axis values by using range hints only
|
||||||
|
const xAxisMetadata = metadata.valuesForHints(['range']);
|
||||||
|
|
||||||
|
return {
|
||||||
|
xAxisMetadata,
|
||||||
|
yAxisMetadata
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getOptions(telemetryObject) {
|
||||||
|
const { start, end } = this.openmct.time.bounds();
|
||||||
|
|
||||||
|
return {
|
||||||
|
end,
|
||||||
|
start,
|
||||||
|
startTime: null,
|
||||||
|
spectra: true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
loadComposition() {
|
||||||
|
this.composition = this.openmct.composition.get(this.currentDomainObject);
|
||||||
|
|
||||||
|
if (!this.composition) {
|
||||||
|
this.addTelemetryObject(this.currentDomainObject);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.composition.on('add', this.addTelemetryObject);
|
||||||
|
this.composition.on('remove', this.removeTelemetryObject);
|
||||||
|
this.composition.load();
|
||||||
|
},
|
||||||
|
refreshData(bounds, isTick) {
|
||||||
|
if (!isTick) {
|
||||||
|
const telemetryObjects = Object.values(this.telemetryObjects);
|
||||||
|
telemetryObjects.forEach(this.requestDataFor);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeAllSubscriptions() {
|
||||||
|
this.subscriptions.forEach(subscription => subscription.unsubscribe());
|
||||||
|
this.subscriptions = [];
|
||||||
|
},
|
||||||
|
removeSubscription(key) {
|
||||||
|
const found = this.subscriptions.findIndex(subscription => subscription.key === key);
|
||||||
|
if (found > -1) {
|
||||||
|
this.subscriptions[found].unsubscribe();
|
||||||
|
this.subscriptions.splice(found, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeTelemetryObject(identifier) {
|
||||||
|
const key = this.openmct.objects.makeKeyString(identifier);
|
||||||
|
delete this.telemetryObjects[key];
|
||||||
|
if (this.domainObject.configuration.barStyles[key]) {
|
||||||
|
delete this.domainObject.configuration.barStyles[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeSubscription(key);
|
||||||
|
|
||||||
|
this.trace = this.trace.filter(t => t.key !== key);
|
||||||
|
},
|
||||||
|
processData(telemetryObject, data, axisMetadata) {
|
||||||
|
const key = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||||
|
|
||||||
|
if (data.message) {
|
||||||
|
this.openmct.notifications.alert(data.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
let xValues = [];
|
||||||
|
let yValues = [];
|
||||||
|
|
||||||
|
//populate X and Y values for plotly
|
||||||
|
axisMetadata.xAxisMetadata.forEach((metadata) => {
|
||||||
|
xValues.push(metadata.name);
|
||||||
|
if (data[metadata.key]) {
|
||||||
|
//TODO: Format the data?
|
||||||
|
yValues.push(data[metadata.key]);
|
||||||
|
} else {
|
||||||
|
yValues.push('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const trace = {
|
||||||
|
key,
|
||||||
|
name: telemetryObject.name,
|
||||||
|
x: xValues,
|
||||||
|
y: yValues,
|
||||||
|
text: yValues.map(String),
|
||||||
|
xAxisMetadata: axisMetadata.xAxisMetadata,
|
||||||
|
yAxisMetadata: axisMetadata.yAxisMetadata,
|
||||||
|
type: 'bar',
|
||||||
|
marker: {
|
||||||
|
color: this.domainObject.configuration.barStyles[key].color
|
||||||
|
},
|
||||||
|
hoverinfo: 'skip'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addTrace(trace, key);
|
||||||
|
},
|
||||||
|
requestDataFor(telemetryObject) {
|
||||||
|
const axisMetadata = this.getAxisMetadata(telemetryObject);
|
||||||
|
this.openmct.telemetry.request(telemetryObject, this.getOptions(telemetryObject))
|
||||||
|
.then(data => {
|
||||||
|
data.forEach((datum) => {
|
||||||
|
this.processData(telemetryObject, datum, axisMetadata);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
subscribeToObject(telemetryObject) {
|
||||||
|
const key = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||||
|
|
||||||
|
this.removeSubscription(key);
|
||||||
|
|
||||||
|
const options = this.getOptions(telemetryObject);
|
||||||
|
const axisMetadata = this.getAxisMetadata(telemetryObject);
|
||||||
|
const unsubscribe = this.openmct.telemetry.subscribe(telemetryObject,
|
||||||
|
data => this.processData(telemetryObject, data, axisMetadata)
|
||||||
|
, options);
|
||||||
|
|
||||||
|
this.subscriptions.push({
|
||||||
|
key,
|
||||||
|
unsubscribe
|
||||||
|
});
|
||||||
|
},
|
||||||
|
subscribeToAll() {
|
||||||
|
const telemetryObjects = Object.values(this.telemetryObjects);
|
||||||
|
telemetryObjects.forEach(this.subscribeToObject);
|
||||||
|
},
|
||||||
|
updateDomainObject(newDomainObject) {
|
||||||
|
this.currentDomainObject = newDomainObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
76
src/plugins/plot/barGraph/BarGraphViewProvider.js
Normal file
76
src/plugins/plot/barGraph/BarGraphViewProvider.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import BarGraphView from './BarGraphView.vue';
|
||||||
|
import { BAR_GRAPH_KEY, BAR_GRAPH_VIEW } from './BarGraphConstants';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default function BarGraphViewProvider(openmct) {
|
||||||
|
function isCompactView(objectPath) {
|
||||||
|
return objectPath.find(object => object.type === 'time-strip');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: BAR_GRAPH_VIEW,
|
||||||
|
name: 'Spectral Aggregate Plot',
|
||||||
|
cssClass: 'icon-telemetry',
|
||||||
|
canView(domainObject, objectPath) {
|
||||||
|
return domainObject && domainObject.type === BAR_GRAPH_KEY;
|
||||||
|
},
|
||||||
|
|
||||||
|
canEdit(domainObject, objectPath) {
|
||||||
|
return domainObject && domainObject.type === BAR_GRAPH_KEY;
|
||||||
|
},
|
||||||
|
|
||||||
|
view: function (domainObject, objectPath) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (element) {
|
||||||
|
let isCompact = isCompactView(objectPath);
|
||||||
|
component = new Vue({
|
||||||
|
el: element,
|
||||||
|
components: {
|
||||||
|
BarGraphView
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
domainObject
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
options: {
|
||||||
|
compact: isCompact
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: '<bar-graph-view :options="options"></bar-graph-view>'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
import { BAR_GRAPH_INSPECTOR_KEY, BAR_GRAPH_KEY } from '../BarGraphConstants';
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Options from "./Options.vue";
|
||||||
|
|
||||||
|
export default function BarGraphInspectorViewProvider(openmct) {
|
||||||
|
return {
|
||||||
|
key: BAR_GRAPH_INSPECTOR_KEY,
|
||||||
|
name: 'Bar Graph Inspector View',
|
||||||
|
canView: function (selection) {
|
||||||
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let object = selection[0][0].context.item;
|
||||||
|
|
||||||
|
return object
|
||||||
|
&& object.type === BAR_GRAPH_KEY;
|
||||||
|
},
|
||||||
|
view: function (selection) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (element) {
|
||||||
|
component = new Vue({
|
||||||
|
el: element,
|
||||||
|
components: {
|
||||||
|
Options
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
domainObject: selection[0][0].context.item
|
||||||
|
},
|
||||||
|
template: '<options></options>'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
if (component) {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
priority: function () {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
107
src/plugins/plot/barGraph/inspector/BarGraphOptions.vue
Normal file
107
src/plugins/plot/barGraph/inspector/BarGraphOptions.vue
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2020, 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.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<ul>
|
||||||
|
<li class="c-tree__item menus-to-left">
|
||||||
|
<span class="c-disclosure-triangle is-enabled flex-elem"
|
||||||
|
:class="expandedCssClass"
|
||||||
|
@click="expanded = !expanded"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<div>
|
||||||
|
<div class="c-object-label__name">{{ name }}</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<ColorSwatch v-if="expanded"
|
||||||
|
:current-color="currentColor"
|
||||||
|
title="Manually set the color for this bar graph."
|
||||||
|
edit-title="Manually set the color for this bar graph"
|
||||||
|
view-title="The color for this bar graph."
|
||||||
|
short-label="Color"
|
||||||
|
class="grid-properties"
|
||||||
|
@colorSet="setColor"
|
||||||
|
/>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ColorSwatch from '../../ColorSwatch.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ColorSwatch
|
||||||
|
},
|
||||||
|
inject: ['openmct', 'domainObject'],
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentColor: undefined,
|
||||||
|
name: '',
|
||||||
|
expanded: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
expandedCssClass() {
|
||||||
|
return this.expanded ? 'c-disclosure-triangle--expanded' : '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
item: {
|
||||||
|
handler() {
|
||||||
|
this.initColor();
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.key = this.openmct.objects.makeKeyString(this.item);
|
||||||
|
this.initColor();
|
||||||
|
this.unObserve = this.openmct.objects.observe(this.domainObject, `this.domainObject.configuration.barStyles[${this.key}]`, this.initColor);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.unObserve) {
|
||||||
|
this.unObserve();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initColor() {
|
||||||
|
if (this.domainObject.configuration.barStyles && this.domainObject.configuration.barStyles[this.key]) {
|
||||||
|
this.currentColor = this.domainObject.configuration.barStyles[this.key].color;
|
||||||
|
this.name = this.domainObject.configuration.barStyles[this.key].name;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setColor(chosenColor) {
|
||||||
|
this.currentColor = chosenColor.asHexString();
|
||||||
|
this.openmct.objects.mutate(
|
||||||
|
this.domainObject,
|
||||||
|
`configuration.barStyles[${this.key}].color`,
|
||||||
|
this.currentColor
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
63
src/plugins/plot/barGraph/inspector/Options.vue
Normal file
63
src/plugins/plot/barGraph/inspector/Options.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2020, 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.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ul class="c-tree">
|
||||||
|
<li v-for="series in domainObject.composition"
|
||||||
|
:key="series.key"
|
||||||
|
>
|
||||||
|
<bar-graph-options :item="series" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import BarGraphOptions from "./BarGraphOptions.vue";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
BarGraphOptions
|
||||||
|
},
|
||||||
|
inject: ['openmct', 'domainObject'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isEditing: this.openmct.editor.isEditing()
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
canEdit() {
|
||||||
|
return this.isEditing && !this.domainObject.locked;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.openmct.editor.on('isEditing', this.setEditState);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.openmct.editor.off('isEditing', this.setEditState);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setEditState(isEditing) {
|
||||||
|
this.isEditing = isEditing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -38,7 +38,7 @@ import MCTChartLineStepAfter from './MCTChartLineStepAfter';
|
|||||||
import MCTChartPointSet from './MCTChartPointSet';
|
import MCTChartPointSet from './MCTChartPointSet';
|
||||||
import MCTChartAlarmPointSet from './MCTChartAlarmPointSet';
|
import MCTChartAlarmPointSet from './MCTChartAlarmPointSet';
|
||||||
import MCTChartAlarmLineSet from "./MCTChartAlarmLineSet";
|
import MCTChartAlarmLineSet from "./MCTChartAlarmLineSet";
|
||||||
import configStore from "../configuration/configStore";
|
import configStore from "../configuration/ConfigStore";
|
||||||
import PlotConfigurationModel from "../configuration/PlotConfigurationModel";
|
import PlotConfigurationModel from "../configuration/PlotConfigurationModel";
|
||||||
import LimitLine from "./LimitLine.vue";
|
import LimitLine from "./LimitLine.vue";
|
||||||
import LimitLabel from "./LimitLabel.vue";
|
import LimitLabel from "./LimitLabel.vue";
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import Model from "./Model";
|
import Model from "./Model";
|
||||||
import { MARKER_SHAPES } from '../draw/MarkerShapes';
|
import { MARKER_SHAPES } from '../draw/MarkerShapes';
|
||||||
import configStore from "../configuration/configStore";
|
import configStore from "../configuration/ConfigStore";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plot series handle interpreting telemetry metadata for a single telemetry
|
* Plot series handle interpreting telemetry metadata for a single telemetry
|
||||||
|
@ -115,7 +115,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PlotOptionsItem from "./PlotOptionsItem.vue";
|
import PlotOptionsItem from "./PlotOptionsItem.vue";
|
||||||
import configStore from "../configuration/configStore";
|
import configStore from "../configuration/ConfigStore";
|
||||||
import eventHelpers from "../lib/eventHelpers";
|
import eventHelpers from "../lib/eventHelpers";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -49,7 +49,7 @@ import SeriesForm from "./forms/SeriesForm.vue";
|
|||||||
import YAxisForm from "./forms/YAxisForm.vue";
|
import YAxisForm from "./forms/YAxisForm.vue";
|
||||||
import LegendForm from "./forms/LegendForm.vue";
|
import LegendForm from "./forms/LegendForm.vue";
|
||||||
import eventHelpers from "../lib/eventHelpers";
|
import eventHelpers from "../lib/eventHelpers";
|
||||||
import configStore from "../configuration/configStore";
|
import configStore from "../configuration/ConfigStore";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -68,26 +68,23 @@
|
|||||||
{{ limitLines ? "Enabled" : "Disabled" }}
|
{{ limitLines ? "Enabled" : "Disabled" }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="grid-row">
|
<ColorSwatch :current-color="seriesHexColor"
|
||||||
<div class="grid-cell label"
|
edit-title="Manually set the plot line and marker color for this series."
|
||||||
title="The plot line and marker color for this series."
|
view-title="The plot line and marker color for this series."
|
||||||
>Color</div>
|
short-label="Color"
|
||||||
<div class="grid-cell value">
|
/>
|
||||||
<span class="c-color-swatch"
|
|
||||||
:style="{
|
|
||||||
'background': seriesHexColor
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import ColorSwatch from "@/plugins/plot/ColorSwatch.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
ColorSwatch
|
||||||
|
},
|
||||||
inject: ['openmct', 'domainObject', 'path'],
|
inject: ['openmct', 'domainObject', 'path'],
|
||||||
props: {
|
props: {
|
||||||
series: {
|
series: {
|
||||||
|
@ -117,49 +117,27 @@
|
|||||||
<li v-show="interpolate !== 'none' || markers"
|
<li v-show="interpolate !== 'none' || markers"
|
||||||
class="grid-row"
|
class="grid-row"
|
||||||
>
|
>
|
||||||
<div class="grid-cell label"
|
<ColorSwatch :current-color="currentColor"
|
||||||
title="Manually set the plot line and marker color for this series."
|
edit-title="Manually set the plot line and marker color for this series."
|
||||||
>Color</div>
|
view-title="The plot line and marker color for this series."
|
||||||
<div class="grid-cell value">
|
short-label="Color"
|
||||||
<div class="c-click-swatch c-click-swatch--menu"
|
@colorSet="setColor"
|
||||||
@click="toggleSwatch()"
|
/>
|
||||||
>
|
|
||||||
<span class="c-color-swatch"
|
|
||||||
:style="{ background: seriesColorAsHex }"
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="c-palette c-palette--color">
|
|
||||||
<div v-show="swatchActive"
|
|
||||||
class="c-palette__items"
|
|
||||||
>
|
|
||||||
<div v-for="(group, index) in colorPalette"
|
|
||||||
:key="index"
|
|
||||||
class="u-contents"
|
|
||||||
>
|
|
||||||
<div v-for="(color, colorIndex) in group"
|
|
||||||
:key="colorIndex"
|
|
||||||
class="c-palette__item"
|
|
||||||
:class="{ 'selected': series.get('color').equalTo(color) }"
|
|
||||||
:style="{ background: color.asHexString() }"
|
|
||||||
@click="setColor(color)"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import ColorSwatch from '../../ColorSwatch.vue';
|
||||||
import { MARKER_SHAPES } from "../../draw/MarkerShapes";
|
import { MARKER_SHAPES } from "../../draw/MarkerShapes";
|
||||||
import { objectPath, validate, coerce } from "./formUtil";
|
import { objectPath, validate, coerce } from "./formUtil";
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
ColorSwatch
|
||||||
|
},
|
||||||
inject: ['openmct', 'domainObject', 'path'],
|
inject: ['openmct', 'domainObject', 'path'],
|
||||||
props: {
|
props: {
|
||||||
series: {
|
series: {
|
||||||
@ -209,7 +187,7 @@ export default {
|
|||||||
expandedCssClass() {
|
expandedCssClass() {
|
||||||
return this.expanded ? 'c-disclosure-triangle--expanded' : '';
|
return this.expanded ? 'c-disclosure-triangle--expanded' : '';
|
||||||
},
|
},
|
||||||
seriesColorAsHex() {
|
currentColor() {
|
||||||
return this.series.get('color').asHexString();
|
return this.series.get('color').asHexString();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -89,13 +89,4 @@ ColorPalette.prototype.getNextColor = function () {
|
|||||||
return this.availableColors.shift();
|
return this.availableColors.shift();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} index the index of the color to return. An index
|
|
||||||
* value larger than the size of the index will wrap around.
|
|
||||||
* @returns {Color}
|
|
||||||
*/
|
|
||||||
ColorPalette.prototype.getColor = function (index) {
|
|
||||||
return this.colors[index % this.colors.length];
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ColorPalette;
|
export default ColorPalette;
|
||||||
|
@ -19,13 +19,18 @@
|
|||||||
* 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.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
import { BAR_GRAPH_KEY } from './barGraph/BarGraphConstants';
|
||||||
import PlotViewProvider from './PlotViewProvider';
|
import PlotViewProvider from './PlotViewProvider';
|
||||||
|
import SpectralPlotViewProvider from './spectralPlot/SpectralPlotViewProvider';
|
||||||
|
import BarGraphViewProvider from './barGraph/BarGraphViewProvider';
|
||||||
import OverlayPlotViewProvider from './overlayPlot/OverlayPlotViewProvider';
|
import OverlayPlotViewProvider from './overlayPlot/OverlayPlotViewProvider';
|
||||||
import StackedPlotViewProvider from './stackedPlot/StackedPlotViewProvider';
|
import StackedPlotViewProvider from './stackedPlot/StackedPlotViewProvider';
|
||||||
import PlotsInspectorViewProvider from './inspector/PlotsInspectorViewProvider';
|
import PlotsInspectorViewProvider from './inspector/PlotsInspectorViewProvider';
|
||||||
|
import BarGraphInspectorViewProvider from './barGraph/inspector/BarGraphInspectorViewProvider';
|
||||||
import OverlayPlotCompositionPolicy from './overlayPlot/OverlayPlotCompositionPolicy';
|
import OverlayPlotCompositionPolicy from './overlayPlot/OverlayPlotCompositionPolicy';
|
||||||
import StackedPlotCompositionPolicy from './stackedPlot/StackedPlotCompositionPolicy';
|
import StackedPlotCompositionPolicy from './stackedPlot/StackedPlotCompositionPolicy';
|
||||||
|
import SpectralPlotCompositionPolicy from './spectralPlot/SpectralPlotCompositionPolicy';
|
||||||
|
import BarGraphCompositionPolicy from './barGraph/BarGraphCompositionPolicy';
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return function install(openmct) {
|
return function install(openmct) {
|
||||||
@ -59,13 +64,48 @@ export default function () {
|
|||||||
},
|
},
|
||||||
priority: 890
|
priority: 890
|
||||||
});
|
});
|
||||||
|
openmct.types.addType('telemetry.plot.spectral', {
|
||||||
|
key: "telemetry.plot.spectral",
|
||||||
|
name: "Spectral Plot",
|
||||||
|
cssClass: "icon-plot-stacked",
|
||||||
|
description: "View Spectra on Y Axes with non-time domain on the X axis. Can be added to Display Layouts.",
|
||||||
|
//Temporarily disabling spectral plots
|
||||||
|
creatable: false,
|
||||||
|
initialize: function (domainObject) {
|
||||||
|
domainObject.composition = [];
|
||||||
|
domainObject.configuration = {};
|
||||||
|
},
|
||||||
|
priority: 890
|
||||||
|
});
|
||||||
|
|
||||||
|
openmct.types.addType(BAR_GRAPH_KEY, {
|
||||||
|
key: BAR_GRAPH_KEY,
|
||||||
|
name: "Bar Graph",
|
||||||
|
cssClass: "icon-bar-chart",
|
||||||
|
description: "View data as a bar graph. Can be added to Display Layouts.",
|
||||||
|
creatable: true,
|
||||||
|
initialize: function (domainObject) {
|
||||||
|
domainObject.composition = [];
|
||||||
|
domainObject.configuration = {
|
||||||
|
plotType: 'bar'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
priority: 891
|
||||||
|
});
|
||||||
|
|
||||||
openmct.objectViews.addProvider(new StackedPlotViewProvider(openmct));
|
openmct.objectViews.addProvider(new StackedPlotViewProvider(openmct));
|
||||||
openmct.objectViews.addProvider(new OverlayPlotViewProvider(openmct));
|
openmct.objectViews.addProvider(new OverlayPlotViewProvider(openmct));
|
||||||
openmct.objectViews.addProvider(new PlotViewProvider(openmct));
|
openmct.objectViews.addProvider(new PlotViewProvider(openmct));
|
||||||
|
openmct.objectViews.addProvider(new SpectralPlotViewProvider(openmct));
|
||||||
|
openmct.objectViews.addProvider(new BarGraphViewProvider(openmct));
|
||||||
|
|
||||||
openmct.inspectorViews.addProvider(new PlotsInspectorViewProvider(openmct));
|
openmct.inspectorViews.addProvider(new PlotsInspectorViewProvider(openmct));
|
||||||
|
openmct.inspectorViews.addProvider(new BarGraphInspectorViewProvider(openmct));
|
||||||
|
|
||||||
openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow);
|
openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow);
|
||||||
openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow);
|
openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow);
|
||||||
|
openmct.composition.addPolicy(new SpectralPlotCompositionPolicy(openmct).allow);
|
||||||
|
openmct.composition.addPolicy(new BarGraphCompositionPolicy(openmct).allow);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,10 +24,12 @@ import {createMouseEvent, createOpenMct, resetApplicationState, spyOnBuiltins} f
|
|||||||
import PlotVuePlugin from "./plugin";
|
import PlotVuePlugin from "./plugin";
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import StackedPlot from "./stackedPlot/StackedPlot.vue";
|
import StackedPlot from "./stackedPlot/StackedPlot.vue";
|
||||||
import configStore from "./configuration/configStore";
|
// import SpectralPlot from "./spectralPlot/SpectralPlot.vue";
|
||||||
|
import configStore from "./configuration/ConfigStore";
|
||||||
import EventEmitter from "EventEmitter";
|
import EventEmitter from "EventEmitter";
|
||||||
import PlotOptions from "./inspector/PlotOptions.vue";
|
import PlotOptions from "./inspector/PlotOptions.vue";
|
||||||
import PlotConfigurationModel from "./configuration/PlotConfigurationModel";
|
import PlotConfigurationModel from "./configuration/PlotConfigurationModel";
|
||||||
|
import { BAR_GRAPH_VIEW, BAR_GRAPH_KEY } from './barGraph/BarGraphConstants';
|
||||||
|
|
||||||
describe("the plugin", function () {
|
describe("the plugin", function () {
|
||||||
let element;
|
let element;
|
||||||
@ -312,6 +314,38 @@ describe("the plugin", function () {
|
|||||||
let plotView = applicableViews.find((viewProvider) => viewProvider.key === "plot-stacked");
|
let plotView = applicableViews.find((viewProvider) => viewProvider.key === "plot-stacked");
|
||||||
expect(plotView).toBeDefined();
|
expect(plotView).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("provides a spectral plot view for objects with telemetry", () => {
|
||||||
|
const testTelemetryObject = {
|
||||||
|
id: "test-object",
|
||||||
|
type: "telemetry.plot.spectral",
|
||||||
|
telemetry: {
|
||||||
|
values: [{
|
||||||
|
key: "a-very-fine-key"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath);
|
||||||
|
let plotView = applicableViews.find((viewProvider) => viewProvider.key === "plot-spectral");
|
||||||
|
expect(plotView).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("provides a spectral aggregate plot view for objects with telemetry", () => {
|
||||||
|
const testTelemetryObject = {
|
||||||
|
id: "test-object",
|
||||||
|
type: BAR_GRAPH_KEY,
|
||||||
|
telemetry: {
|
||||||
|
values: [{
|
||||||
|
key: "lots-of-aggregate-telemetry"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath);
|
||||||
|
let plotView = applicableViews.find((viewProvider) => viewProvider.key === BAR_GRAPH_VIEW);
|
||||||
|
expect(plotView).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("The single plot view", () => {
|
describe("The single plot view", () => {
|
||||||
@ -462,6 +496,146 @@ describe("the plugin", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* disabling this until we develop the plot view
|
||||||
|
describe("The spectral plot view", () => {
|
||||||
|
let testTelemetryObject;
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
let testTelemetryObject2;
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
let config;
|
||||||
|
let spectralPlotObject;
|
||||||
|
let component;
|
||||||
|
let mockComposition;
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
let plotViewComponentObject;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const getFunc = openmct.$injector.get;
|
||||||
|
spyOn(openmct.$injector, "get")
|
||||||
|
.withArgs("exportImageService").and.returnValue({
|
||||||
|
exportPNG: () => {},
|
||||||
|
exportJPG: () => {}
|
||||||
|
})
|
||||||
|
.and.callFake(getFunc);
|
||||||
|
|
||||||
|
spectralPlotObject = {
|
||||||
|
identifier: {
|
||||||
|
namespace: "",
|
||||||
|
key: "test-spectral-plot"
|
||||||
|
},
|
||||||
|
type: "telemetry.plot.spectral",
|
||||||
|
name: "Test Spectral Plot"
|
||||||
|
};
|
||||||
|
|
||||||
|
testTelemetryObject = {
|
||||||
|
identifier: {
|
||||||
|
namespace: "",
|
||||||
|
key: "test-object"
|
||||||
|
},
|
||||||
|
type: "test-object",
|
||||||
|
name: "Test Object",
|
||||||
|
telemetry: {
|
||||||
|
values: [{
|
||||||
|
key: "utc",
|
||||||
|
format: "utc",
|
||||||
|
name: "Time",
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "some-key",
|
||||||
|
name: "Some attribute",
|
||||||
|
hints: {
|
||||||
|
range: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "some-other-key",
|
||||||
|
name: "Another attribute",
|
||||||
|
hints: {
|
||||||
|
range: 2
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
testTelemetryObject2 = {
|
||||||
|
identifier: {
|
||||||
|
namespace: "",
|
||||||
|
key: "test-object2"
|
||||||
|
},
|
||||||
|
type: "test-object",
|
||||||
|
name: "Test Object2",
|
||||||
|
telemetry: {
|
||||||
|
values: [{
|
||||||
|
key: "utc",
|
||||||
|
format: "utc",
|
||||||
|
name: "Time",
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "wavelength",
|
||||||
|
name: "Wavelength",
|
||||||
|
hints: {
|
||||||
|
range: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "some-other-key2",
|
||||||
|
name: "Another attribute2",
|
||||||
|
hints: {
|
||||||
|
range: 2
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mockComposition = new EventEmitter();
|
||||||
|
mockComposition.load = () => {
|
||||||
|
mockComposition.emit('add', testTelemetryObject);
|
||||||
|
|
||||||
|
return [testTelemetryObject];
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(openmct.composition, 'get').and.returnValue(mockComposition);
|
||||||
|
|
||||||
|
let viewContainer = document.createElement("div");
|
||||||
|
child.append(viewContainer);
|
||||||
|
component = new Vue({
|
||||||
|
el: viewContainer,
|
||||||
|
components: {
|
||||||
|
SpectralPlot
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct: openmct,
|
||||||
|
domainObject: spectralPlotObject,
|
||||||
|
composition: openmct.composition.get(spectralPlotObject)
|
||||||
|
},
|
||||||
|
template: "<spectral-plot></spectral-plot>"
|
||||||
|
});
|
||||||
|
|
||||||
|
cleanupFirst.push(() => {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
return telemetryPromise
|
||||||
|
.then(Vue.nextTick())
|
||||||
|
.then(() => {
|
||||||
|
plotViewComponentObject = component.$root.$children[0];
|
||||||
|
const configId = openmct.objects.makeKeyString(testTelemetryObject.identifier);
|
||||||
|
config = configStore.get(configId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Renders a collapsed legend for every telemetry", () => {
|
||||||
|
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
||||||
|
expect(legend.length).toBe(1);
|
||||||
|
expect(legend[0].innerHTML).toEqual("Test Object");
|
||||||
|
});
|
||||||
|
|
||||||
|
}); */
|
||||||
|
|
||||||
describe("The stacked plot view", () => {
|
describe("The stacked plot view", () => {
|
||||||
let testTelemetryObject;
|
let testTelemetryObject;
|
||||||
let testTelemetryObject2;
|
let testTelemetryObject2;
|
||||||
@ -963,7 +1137,7 @@ describe("the plugin", function () {
|
|||||||
expandControl.dispatchEvent(clickEvent);
|
expandControl.dispatchEvent(clickEvent);
|
||||||
|
|
||||||
const plotOptionsProperties = editOptionsEl.querySelectorAll(".js-plot-options-edit-properties .grid-row");
|
const plotOptionsProperties = editOptionsEl.querySelectorAll(".js-plot-options-edit-properties .grid-row");
|
||||||
expect(plotOptionsProperties.length).toEqual(7);
|
expect(plotOptionsProperties.length).toEqual(8);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows yKeyOptions', () => {
|
it('shows yKeyOptions', () => {
|
||||||
@ -991,4 +1165,39 @@ describe("the plugin", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("the spectral plot", () => {
|
||||||
|
const mockObject = {
|
||||||
|
name: 'A Very Nice Spectral Plot',
|
||||||
|
key: 'telemetry.plot.spectral',
|
||||||
|
creatable: true
|
||||||
|
};
|
||||||
|
|
||||||
|
it('defines a spectral plot object type with the correct key', () => {
|
||||||
|
const objectDef = openmct.types.get('telemetry.plot.spectral').definition;
|
||||||
|
expect(objectDef.key).toEqual(mockObject.key);
|
||||||
|
});
|
||||||
|
|
||||||
|
xit('is creatable', () => {
|
||||||
|
const objectDef = openmct.types.get('telemetry.plot.spectral').definition;
|
||||||
|
expect(objectDef.creatable).toEqual(mockObject.creatable);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("the aggregate spectral plot", () => {
|
||||||
|
const mockObject = {
|
||||||
|
name: 'An Even Nicer Aggregate Spectral Plot',
|
||||||
|
key: BAR_GRAPH_KEY,
|
||||||
|
creatable: true
|
||||||
|
};
|
||||||
|
|
||||||
|
it('defines a spectral plot object type with the correct key', () => {
|
||||||
|
const objectDef = openmct.types.get(BAR_GRAPH_KEY).definition;
|
||||||
|
expect(objectDef.key).toEqual(mockObject.key);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is creatable', () => {
|
||||||
|
const objectDef = openmct.types.get(BAR_GRAPH_KEY).definition;
|
||||||
|
expect(objectDef.creatable).toEqual(mockObject.creatable);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
export default function SpectralPlotCompositionPolicy(openmct) {
|
||||||
|
function hasSpectralDomainAndRange(metadata) {
|
||||||
|
const rangeValues = metadata.valuesForHints(['range']);
|
||||||
|
const domainValues = metadata.valuesForHints(['domain']);
|
||||||
|
const containsSomeSpectralData = domainValues.some(value => {
|
||||||
|
return ((value.key === 'wavelength') || (value.key === 'frequency'));
|
||||||
|
});
|
||||||
|
|
||||||
|
return rangeValues.length > 0
|
||||||
|
&& domainValues.length > 0
|
||||||
|
&& containsSomeSpectralData;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasSpectralTelemetry(domainObject) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(domainObject, 'telemetry')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let metadata = openmct.telemetry.getMetadata(domainObject);
|
||||||
|
|
||||||
|
return metadata.values().length > 0 && hasSpectralDomainAndRange(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
allow: function (parent, child) {
|
||||||
|
|
||||||
|
if ((parent.type === 'telemetry.plot.spectral')
|
||||||
|
&& ((child.type !== 'telemetry.plot.overlay') && (hasSpectralTelemetry(child) === false))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
75
src/plugins/plot/spectralPlot/SpectralPlotViewProvider.js
Normal file
75
src/plugins/plot/spectralPlot/SpectralPlotViewProvider.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import SpectralView from './SpectralView.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default function SpectralPlotViewProvider(openmct) {
|
||||||
|
function isCompactView(objectPath) {
|
||||||
|
return objectPath.find(object => object.type === 'time-strip');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: 'plot-spectral',
|
||||||
|
name: 'Spectral Plot',
|
||||||
|
cssClass: 'icon-telemetry',
|
||||||
|
canView(domainObject, objectPath) {
|
||||||
|
return domainObject && domainObject.type === 'telemetry.plot.spectral';
|
||||||
|
},
|
||||||
|
|
||||||
|
canEdit(domainObject, objectPath) {
|
||||||
|
return domainObject && domainObject.type === 'telemetry.plot.spectral';
|
||||||
|
},
|
||||||
|
|
||||||
|
view: function (domainObject, objectPath) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (element) {
|
||||||
|
let isCompact = isCompactView(objectPath);
|
||||||
|
component = new Vue({
|
||||||
|
el: element,
|
||||||
|
components: {
|
||||||
|
SpectralView
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
domainObject
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
options: {
|
||||||
|
compact: isCompact
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: '<spectral-view :options="options"></spectral-view>'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
13
src/plugins/plot/spectralPlot/SpectralView.vue
Normal file
13
src/plugins/plot/spectralPlot/SpectralView.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['openmct', 'domainObject']
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
@ -729,6 +729,12 @@ mct-plot {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************* BAR CHARTS */
|
||||||
|
.c-bar-chart {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
/***************** CURSOR GUIDES */
|
/***************** CURSOR GUIDES */
|
||||||
[class*='c-cursor-guide'] {
|
[class*='c-cursor-guide'] {
|
||||||
box-shadow: $shdwCursorGuide;
|
box-shadow: $shdwCursorGuide;
|
||||||
|
@ -40,6 +40,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.zerolinelayer {
|
||||||
|
// Hide unneeded plotly-styled horizontal line
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
path.xy2-y {
|
path.xy2-y {
|
||||||
stroke: $colorPlotHash !important; // Using this instead of $colorPlotAreaBorder because that is an rgba
|
stroke: $colorPlotHash !important; // Using this instead of $colorPlotAreaBorder because that is an rgba
|
||||||
opacity: $opacityPlotHash !important;
|
opacity: $opacityPlotHash !important;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user