Compare commits

...

7 Commits

Author SHA1 Message Date
Shefali Joshi
cd3938433d Merge branch 'master' into plots-underlays 2022-01-05 11:57:24 -08:00
Shefali Joshi
91b51aafa6 Merge branch 'master' into plots-underlays 2022-01-03 13:43:20 -08:00
Shefali Joshi
a6f873cc78 Merge branch 'master' into plots-underlays 2021-12-29 16:02:25 -08:00
Joshi
acdf8b86be Update to show markers from data 2021-12-29 16:00:41 -08:00
Joshi
ab09cdd3bd Draft of underlays for plots 2021-12-29 10:49:06 -08:00
Joshi
73260f17f2 Merge branch 'master' of https://github.com/nasa/openmct into plots-underlays 2021-12-28 09:50:06 -08:00
Joshi
1fbfc7d0d7 New view for plot underlays 2021-12-10 15:06:37 -08:00
6 changed files with 292 additions and 5 deletions

View File

@@ -47,7 +47,7 @@
import * as d3Scale from 'd3-scale';
import TimelineAxis from "../../ui/components/TimeSystemAxis.vue";
import SwimLane from "@/ui/components/swim-lane/SwimLane.vue";
import { getValidatedPlan } from "./util";
import { getValidatedData } from "./util";
import Vue from "vue";
const PADDING = 1;
@@ -159,7 +159,7 @@ export default {
return clientWidth - 200;
},
getPlanData(domainObject) {
this.planData = getValidatedPlan(domainObject);
this.planData = getValidatedData(domainObject);
},
updateViewBounds(bounds) {
if (bounds) {

View File

@@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
export function getValidatedPlan(domainObject) {
export function getValidatedData(domainObject) {
let body = domainObject.selectFile.body;
let json = {};
if (typeof body === 'string') {

View File

@@ -0,0 +1,198 @@
<!--
Open MCT, Copyright (c) 2014-2022, 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 ref="plotWrapper"
class="c-plot"
>
<div ref="underlay"
class="c-bar-chart"
></div>
</div>
</template>
<script>
import Plotly from 'plotly-basic';
import {getValidatedData} from "@/plugins/plan/util";
const PATH_COLORS = ['blue', 'red', 'green'];
const MARKER_COLOR = 'white';
export default {
inject: ['openmct', 'domainObject'],
props: {
data: {
type: Array,
default() {
return [];
}
}
},
watch: {
data: {
immediate: false,
handler: 'updatePlot'
}
},
mounted() {
this.getPlotData(this.domainObject);
Plotly.newPlot(this.$refs.underlay, Array.from(this.getShapes(this.shapesData)), this.getLayout(this.shapesData), {
responsive: true,
displayModeBar: false
});
this.registerListeners();
},
beforeDestroy() {
if (this.plotResizeObserver) {
this.plotResizeObserver.unobserve(this.$refs.plotWrapper);
clearTimeout(this.resizeTimer);
}
},
methods: {
getPlotData(domainObject) {
this.shapesData = getValidatedData(domainObject);
},
observeForChanges(mutatedObject) {
this.getPlotData(mutatedObject);
},
registerListeners() {
this.unlisten = this.openmct.objects.observe(this.domainObject, '*', this.observeForChanges);
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);
}
},
getShapes(data) {
let markerData = {
x: [],
y: []
};
const shapes = data.map((shapeData, index1) => {
if (!shapeData.x || !shapeData.y
|| !shapeData.x.length || !shapeData.y.length
|| shapeData.x.length !== shapeData.y.length) {
return "";
}
let text = [];
shapeData.x.forEach((point) => {
text.push(`${parseFloat(point).toPrecision(2)}`);
});
markerData.x = markerData.x.concat(shapeData.x);
markerData.y = markerData.y.concat(shapeData.y);
return {
x: shapeData.x,
y: shapeData.y,
mode: 'text',
text,
textfont: {
family: 'Helvetica Neue, Helvetica, Arial, sans-serif',
size: '12px',
color: PATH_COLORS[index1]
},
opacity: 0.5
};
});
shapes.push({
x: markerData.x,
y: markerData.y,
mode: "markers",
marker: {
size: 6,
color: MARKER_COLOR
}
});
return shapes;
},
getLayout(data) {
const shapes = data.map((shapeData, index1) => {
if (!shapeData.x || !shapeData.y
|| !shapeData.x.length || !shapeData.y.length
|| shapeData.x.length !== shapeData.y.length) {
return "";
}
let path = `M ${shapeData.x[0]},${shapeData.y[0]}`;
shapeData.x.forEach((point, index) => {
if (index > 0) {
path = `${path} L${point},${shapeData.y[index]}`;
}
});
return {
path,
type: 'path',
line: {
color: PATH_COLORS[index1]
},
opacity: 0.5
};
});
return {
shapes,
layer: 'below',
paper_bgcolor: 'transparent',
plot_bgcolor: 'transparent',
showlegend: false,
autosize: true,
//TODO: Revisit rangemode here
yaxis: {
automargin: true,
fixedrange: true,
rangemode: 'tozero'
},
xaxis: {
automargin: true,
fixedrange: true,
rangemode: 'tozero'
},
margin: {
l: 5,
r: 5,
t: 5,
b: 0
}
};
},
updatePlot() {
if (!this.$refs || !this.$refs.underlay) {
return;
}
Plotly.react(this.$refs.underlay, Array.from(this.getShapes(this.shapesData)), this.getLayout(this.shapesData));
}
}
};
</script>

View File

@@ -0,0 +1,64 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2022, 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 UnderlayPlot from './UnderlayPlot.vue';
import Vue from 'vue';
export default function UnderlayPlotViewProvider(openmct) {
return {
key: 'plot-underlay',
name: 'Underlay Plot',
cssClass: 'icon-telemetry',
canView(domainObject) {
return domainObject.type === 'telemetry.plot.underlay';
},
canEdit(domainObject) {
return domainObject.type === 'telemetry.plot.underlay';
},
view: function (domainObject, objectPath) {
let component;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
UnderlayPlot
},
provide: {
openmct,
domainObject
},
template: '<underlay-plot></underlay-plot>'
});
},
destroy: function () {
component.$destroy();
component = undefined;
}
};
}
};
}

View File

@@ -20,6 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import PlotViewProvider from './PlotViewProvider';
import UnderlayPlotViewProvider from './UnderlayPlotViewProvider';
import OverlayPlotViewProvider from './overlayPlot/OverlayPlotViewProvider';
import StackedPlotViewProvider from './stackedPlot/StackedPlotViewProvider';
import PlotsInspectorViewProvider from './inspector/PlotsInspectorViewProvider';
@@ -59,9 +60,33 @@ export default function () {
priority: 890
});
openmct.types.addType('telemetry.plot.underlay', {
name: 'Underlay Plot',
key: 'telemetry.plot.underlay',
description: 'A plot view for a compatible underlay plot file.',
creatable: true,
cssClass: 'icon-telemetry',
form: [
{
name: 'Upload Telemetry (JSON File)',
key: 'selectFile',
control: 'file-input',
required: true,
text: 'Select File...',
type: 'application/json',
property: [
"selectFile"
]
}
],
initialize: function (domainObject) {
}
});
openmct.objectViews.addProvider(new StackedPlotViewProvider(openmct));
openmct.objectViews.addProvider(new OverlayPlotViewProvider(openmct));
openmct.objectViews.addProvider(new PlotViewProvider(openmct));
openmct.objectViews.addProvider(new UnderlayPlotViewProvider(openmct));
openmct.inspectorViews.addProvider(new PlotsInspectorViewProvider(openmct));

View File

@@ -57,7 +57,7 @@
import TimelineObjectView from './TimelineObjectView.vue';
import TimelineAxis from '../../ui/components/TimeSystemAxis.vue';
import SwimLane from "@/ui/components/swim-lane/SwimLane.vue";
import { getValidatedPlan } from "../plan/util";
import { getValidatedData } from "../plan/util";
const unknownObjectType = {
definition: {
@@ -106,7 +106,7 @@ export default {
let objectPath = [domainObject].concat(this.objectPath.slice());
let rowCount = 0;
if (domainObject.type === 'plan') {
rowCount = Object.keys(getValidatedPlan(domainObject)).length;
rowCount = Object.keys(getValidatedData(domainObject)).length;
}
let height = domainObject.type === 'telemetry.plot.stacked' ? `${domainObject.composition.length * 100}px` : '100px';