mirror of
https://github.com/nasa/openmct.git
synced 2025-06-19 23:53:49 +00:00
1.7.8 master (#4373)
* Notebook conflict auto retry 1.7.7 (#4230) * Use timeFormatter.parse to get the timestamp of imagery since the source could be something other than key (#4238) * If there is a pending create request for an id, queue a duplicate request. (#4243) * [Telemetry Tables] Handling Request Loading (#4245) * Fix file selection on pressing enter key (#4246) * starting loading as false, since that makes sense (#4247) * Hide independent time conductor mode if only 1 mode option is available. (#4250) * Fix bargraph color selection (#4253) * snapshot clicked while in edit mode should open in preview mode #4115 (#4257) * Fix missing object handling in several vues (#4259) * Flexible Layouts display Condition Sets as their editing/browsing interface (#4179) * Flexible Layouts display Condition Sets as their editing/browsing interface #4141 * [Telemetry Table] Progress bar tests (#4249) * Remove alert styling and hide pause button if in Fixed Time mode. (#4263) * [Table/Collection Fixes] Clearing correctly, no mutating options, no duplicate requests (#4261) * Condition sets only persist if actively editing (#4262) * Imagery views should follow time context (#4264) * Equal stacked plot y widths for all it's sub-plots (#4267) * Fix Bar Graph related CSS (#4270) * Bar graph review comment fixes (#4232) * Mct4196 - Fixes Conditional Styling not being applied when editing a Condition Widget (#4255) * Fix plot zoom when child of time strip (#4272) * Resume plot if no pan, zoom, or drag action is taken (#4138) (#4256) * [Telemetry Collection] No duplicate requests on load (#4274) * doing the easy thing first (#4278) * Bargraph time metadata should consider 'source' (#4289) * Show clicked image in large view (#4280) * added icon for inspector (#4275) * Bar graph style nullcheck (#4291) * Stacked plots need to align the Y axis (#4286) * Duplicate Request Fixes (#4295) * Add braintree sanitize url lib and sanitize form urls (#4296) * Mct4177 fix for telemetry endpoints with '.' in the key (#4308) * Remove additional request to load plots when mounted. (#4314) * Fix plots dup requests (#4324) * Merging 1.7.8 into master. Co-authored-by: Andrew Henry <akhenry@gmail.com> Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov> Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov> Co-authored-by: Khalid Adil <khalidadil29@gmail.com> Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com> Co-authored-by: Scott Bell <scott@traclabs.com> Co-authored-by: Michael Rogers <michael@mhrogers.com>
This commit is contained in:
304
src/plugins/charts/BarGraphView.vue
Normal file
304
src/plugins/charts/BarGraphView.vue
Normal file
@ -0,0 +1,304 @@
|
||||
<!--
|
||||
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"
|
||||
@subscribe="subscribeToAll"
|
||||
@unsubscribe="removeAllSubscriptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BarGraph from './BarGraphPlot.vue';
|
||||
import _ from 'lodash';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BarGraph
|
||||
},
|
||||
inject: ['openmct', 'domainObject', 'path'],
|
||||
data() {
|
||||
this.telemetryObjects = {};
|
||||
this.telemetryObjectFormats = {};
|
||||
this.subscriptions = [];
|
||||
this.composition = {};
|
||||
|
||||
return {
|
||||
trace: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
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.loadComposition();
|
||||
|
||||
this.openmct.time.on('bounds', this.refreshData);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.time.off('bounds', this.refreshData);
|
||||
|
||||
this.removeAllSubscriptions();
|
||||
|
||||
if (!this.composition) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.composition.off('add', this.addTelemetryObject);
|
||||
this.composition.off('remove', this.removeTelemetryObject);
|
||||
},
|
||||
methods: {
|
||||
addTelemetryObject(telemetryObject) {
|
||||
// grab information we need from the added telmetry object
|
||||
const key = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
this.telemetryObjects[key] = telemetryObject;
|
||||
const metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
this.telemetryObjectFormats[key] = this.openmct.telemetry.getFormatMap(metadata);
|
||||
const telemetryObjectPath = [telemetryObject, ...this.path];
|
||||
const telemetryIsAlias = this.openmct.objects.isObjectPathToALink(telemetryObject, telemetryObjectPath);
|
||||
|
||||
// make an update object that's a clone of the existing styles object so we preserve existing choices
|
||||
let stylesUpdate = {};
|
||||
if (this.domainObject.configuration.barStyles.series[key]) {
|
||||
stylesUpdate = _.clone(this.domainObject.configuration.barStyles.series[key]);
|
||||
}
|
||||
|
||||
stylesUpdate.name = telemetryObject.name;
|
||||
stylesUpdate.type = telemetryObject.type;
|
||||
stylesUpdate.isAlias = telemetryIsAlias;
|
||||
|
||||
// if something has changed, mutate and notify listeners
|
||||
if (!_.isEqual(stylesUpdate, this.domainObject.configuration.barStyles.series[key])) {
|
||||
this.openmct.objects.mutate(
|
||||
this.domainObject,
|
||||
`configuration.barStyles.series["${key}"]`,
|
||||
stylesUpdate
|
||||
);
|
||||
}
|
||||
|
||||
// ask for the current telemetry data, then subcribe for changes
|
||||
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]);
|
||||
},
|
||||
getAxisMetadata(telemetryObject) {
|
||||
const metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
if (!metadata) {
|
||||
return {};
|
||||
}
|
||||
|
||||
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() {
|
||||
const { start, end } = this.openmct.time.bounds();
|
||||
|
||||
return {
|
||||
end,
|
||||
start
|
||||
};
|
||||
},
|
||||
loadComposition() {
|
||||
this.composition = this.openmct.composition.get(this.domainObject);
|
||||
|
||||
if (!this.composition) {
|
||||
this.addTelemetryObject(this.domainObject);
|
||||
|
||||
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.telemetryObjectFormats && this.telemetryObjectFormats[key]) {
|
||||
delete this.telemetryObjectFormats[key];
|
||||
}
|
||||
|
||||
if (this.domainObject.configuration.barStyles.series[key]) {
|
||||
delete this.domainObject.configuration.barStyles.series[key];
|
||||
this.openmct.objects.mutate(
|
||||
this.domainObject,
|
||||
`configuration.barStyles.series["${key}"]`,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
this.removeSubscription(key);
|
||||
|
||||
this.trace = this.trace.filter(t => t.key !== key);
|
||||
},
|
||||
addDataToGraph(telemetryObject, data, axisMetadata) {
|
||||
const key = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
|
||||
if (data.message) {
|
||||
this.openmct.notifications.alert(data.message);
|
||||
}
|
||||
|
||||
if (!this.isDataInTimeRange(data, key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let xValues = [];
|
||||
let yValues = [];
|
||||
|
||||
//populate X and Y values for plotly
|
||||
axisMetadata.xAxisMetadata.forEach((metadata) => {
|
||||
xValues.push(metadata.name);
|
||||
if (data[metadata.key]) {
|
||||
const formattedValue = this.format(key, metadata.key, data);
|
||||
yValues.push(formattedValue);
|
||||
} else {
|
||||
yValues.push(null);
|
||||
}
|
||||
});
|
||||
|
||||
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.series[key].color
|
||||
},
|
||||
hoverinfo: 'skip'
|
||||
};
|
||||
|
||||
this.addTrace(trace, key);
|
||||
},
|
||||
isDataInTimeRange(datum, key) {
|
||||
const timeSystemKey = this.openmct.time.timeSystem().key;
|
||||
let currentTimestamp = this.parse(key, timeSystemKey, datum);
|
||||
|
||||
return currentTimestamp && this.openmct.time.bounds().end >= currentTimestamp;
|
||||
},
|
||||
format(telemetryObjectKey, metadataKey, data) {
|
||||
const formats = this.telemetryObjectFormats[telemetryObjectKey];
|
||||
|
||||
return formats[metadataKey].format(data);
|
||||
},
|
||||
parse(telemetryObjectKey, metadataKey, datum) {
|
||||
if (!datum) {
|
||||
return;
|
||||
}
|
||||
|
||||
const formats = this.telemetryObjectFormats[telemetryObjectKey];
|
||||
|
||||
return formats[metadataKey].parse(datum);
|
||||
},
|
||||
requestDataFor(telemetryObject) {
|
||||
const axisMetadata = this.getAxisMetadata(telemetryObject);
|
||||
this.openmct.telemetry.request(telemetryObject)
|
||||
.then(data => {
|
||||
data.forEach((datum) => {
|
||||
this.addDataToGraph(telemetryObject, datum, axisMetadata);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn(`Error fetching data`, error);
|
||||
});
|
||||
},
|
||||
subscribeToObject(telemetryObject) {
|
||||
const key = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
|
||||
this.removeSubscription(key);
|
||||
|
||||
const options = this.getOptions();
|
||||
const axisMetadata = this.getAxisMetadata(telemetryObject);
|
||||
const unsubscribe = this.openmct.telemetry.subscribe(telemetryObject,
|
||||
data => this.addDataToGraph(telemetryObject, data, axisMetadata)
|
||||
, options);
|
||||
|
||||
this.subscriptions.push({
|
||||
key,
|
||||
unsubscribe
|
||||
});
|
||||
},
|
||||
subscribeToAll() {
|
||||
const telemetryObjects = Object.values(this.telemetryObjects);
|
||||
telemetryObjects.forEach(this.subscribeToObject);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
Reference in New Issue
Block a user