Compare commits
7 Commits
fix-gha-pl
...
plots-unde
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd3938433d | ||
|
|
91b51aafa6 | ||
|
|
a6f873cc78 | ||
|
|
acdf8b86be | ||
|
|
ab09cdd3bd | ||
|
|
73260f17f2 | ||
|
|
1fbfc7d0d7 |
@@ -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) {
|
||||
|
||||
@@ -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') {
|
||||
|
||||
198
src/plugins/plot/UnderlayPlot.vue
Normal file
198
src/plugins/plot/UnderlayPlot.vue
Normal 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>
|
||||
64
src/plugins/plot/UnderlayPlotViewProvider.js
Normal file
64
src/plugins/plot/UnderlayPlotViewProvider.js
Normal 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user