mirror of
https://github.com/nasa/openmct.git
synced 2025-06-11 11:51:40 +00:00
Fix stacked plots legend (#6199)
* Add listeners to remove stacked plot series and make keys unique * don't add overlay plots to stacked plot legends * Ensure series colors are drawn correctly in the plot legend * Remove legend from mct plot. Remove series reactivity from stackd plot and add them to the legend instead. * Clean up stacked plots so that the plot legend needs fewer props Also make sure that plot selection inside a stacked plot works - this had regressed due to plot annotations * Fix console error in plot elements pool and plot legend - reset arrays to empty * Ensure color in the y axis swatch updates correctly * Fix small issues with removing objects from STacked plots * Fix selection for annotations and also select stacked plot child items * fix notebook tagging * remove unused annotation editor and change selection to single object * remove reference to deleted css * fix e2e tests * Fix small typos into the selection context for Notebooks. * Add a typ that identifies that an annotation selection is coming from a search result --------- Co-authored-by: Scott Bell <scott@traclabs.com>
This commit is contained in:
parent
393c801426
commit
f570424357
@ -41,6 +41,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Inspect Notebook Entry Network Requests', async ({ page }) => {
|
test('Inspect Notebook Entry Network Requests', async ({ page }) => {
|
||||||
|
await page.getByText('Annotations').click();
|
||||||
// Expand sidebar
|
// Expand sidebar
|
||||||
await page.locator('.c-notebook__toggle-nav-button').click();
|
await page.locator('.c-notebook__toggle-nav-button').click();
|
||||||
|
|
||||||
@ -162,20 +163,20 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
|
|||||||
await page.locator('[aria-label="Notebook Entry Input"] >> nth=2').press('Enter');
|
await page.locator('[aria-label="Notebook Entry Input"] >> nth=2').press('Enter');
|
||||||
|
|
||||||
// Add three tags
|
// Add three tags
|
||||||
await page.hover(`button:has-text("Add Tag") >> nth=2`);
|
await page.hover(`button:has-text("Add Tag")`);
|
||||||
await page.locator(`button:has-text("Add Tag") >> nth=2`).click();
|
await page.locator(`button:has-text("Add Tag")`).click();
|
||||||
await page.locator('[placeholder="Type to select tag"]').click();
|
await page.locator('[placeholder="Type to select tag"]').click();
|
||||||
await page.locator('[aria-label="Autocomplete Options"] >> text=Science').click();
|
await page.locator('[aria-label="Autocomplete Options"] >> text=Science').click();
|
||||||
await page.waitForSelector('[aria-label="Tag"]:has-text("Science")');
|
await page.waitForSelector('[aria-label="Tag"]:has-text("Science")');
|
||||||
|
|
||||||
await page.hover(`button:has-text("Add Tag") >> nth=2`);
|
await page.hover(`button:has-text("Add Tag")`);
|
||||||
await page.locator(`button:has-text("Add Tag") >> nth=2`).click();
|
await page.locator(`button:has-text("Add Tag")`).click();
|
||||||
await page.locator('[placeholder="Type to select tag"]').click();
|
await page.locator('[placeholder="Type to select tag"]').click();
|
||||||
await page.locator('[aria-label="Autocomplete Options"] >> text=Drilling').click();
|
await page.locator('[aria-label="Autocomplete Options"] >> text=Drilling').click();
|
||||||
await page.waitForSelector('[aria-label="Tag"]:has-text("Drilling")');
|
await page.waitForSelector('[aria-label="Tag"]:has-text("Drilling")');
|
||||||
|
|
||||||
await page.hover(`button:has-text("Add Tag") >> nth=2`);
|
await page.hover(`button:has-text("Add Tag")`);
|
||||||
await page.locator(`button:has-text("Add Tag") >> nth=2`).click();
|
await page.locator(`button:has-text("Add Tag")`).click();
|
||||||
await page.locator('[placeholder="Type to select tag"]').click();
|
await page.locator('[placeholder="Type to select tag"]').click();
|
||||||
await page.locator('[aria-label="Autocomplete Options"] >> text=Driving').click();
|
await page.locator('[aria-label="Autocomplete Options"] >> text=Driving').click();
|
||||||
await page.waitForSelector('[aria-label="Tag"]:has-text("Driving")');
|
await page.waitForSelector('[aria-label="Tag"]:has-text("Driving")');
|
||||||
@ -231,6 +232,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
|
|||||||
type: 'issue',
|
type: 'issue',
|
||||||
description: 'https://github.com/akhenry/openmct-yamcs/issues/69'
|
description: 'https://github.com/akhenry/openmct-yamcs/issues/69'
|
||||||
});
|
});
|
||||||
|
await page.getByText('Annotations').click();
|
||||||
await page.locator('text=To start a new entry, click here or drag and drop any object').click();
|
await page.locator('text=To start a new entry, click here or drag and drop any object').click();
|
||||||
await page.locator('[aria-label="Notebook Entry Input"]').click();
|
await page.locator('[aria-label="Notebook Entry Input"]').click();
|
||||||
await page.locator('[aria-label="Notebook Entry Input"]').fill(`First Entry`);
|
await page.locator('[aria-label="Notebook Entry Input"]').fill(`First Entry`);
|
||||||
|
@ -381,7 +381,7 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
updateSelection(selection) {
|
updateSelection(selection) {
|
||||||
if (selection?.[0]?.[1]?.context?.targetDetails?.entryId === undefined) {
|
if (selection?.[0]?.[0]?.context?.targetDetails?.entryId === undefined) {
|
||||||
this.selectedEntryId = '';
|
this.selectedEntryId = '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -472,16 +472,11 @@ export default {
|
|||||||
targetDomainObjects[keyString] = this.domainObject;
|
targetDomainObjects[keyString] = this.domainObject;
|
||||||
this.openmct.selection.select(
|
this.openmct.selection.select(
|
||||||
[
|
[
|
||||||
{
|
|
||||||
element: this.openmct.layout.$refs.browseObject.$el,
|
|
||||||
context: {
|
|
||||||
item: this.domainObject
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
element: event.currentTarget,
|
element: event.currentTarget,
|
||||||
context: {
|
context: {
|
||||||
type: 'notebook-entry-selection',
|
type: 'notebook-entry-selection',
|
||||||
|
item: this.domainObject,
|
||||||
targetDetails,
|
targetDetails,
|
||||||
targetDomainObjects,
|
targetDomainObjects,
|
||||||
annotations: this.notebookAnnotations,
|
annotations: this.notebookAnnotations,
|
||||||
|
@ -23,16 +23,8 @@
|
|||||||
<div
|
<div
|
||||||
v-if="loaded"
|
v-if="loaded"
|
||||||
class="gl-plot"
|
class="gl-plot"
|
||||||
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
|
||||||
>
|
>
|
||||||
<plot-legend
|
<slot></slot>
|
||||||
v-if="!isNestedWithinAStackedPlot"
|
|
||||||
:cursor-locked="!!lockHighlightPoint"
|
|
||||||
:series="seriesModels"
|
|
||||||
:highlights="highlights"
|
|
||||||
:legend="legend"
|
|
||||||
@legendHoverChanged="legendHoverChanged"
|
|
||||||
/>
|
|
||||||
<div class="plot-wrapper-axis-and-display-area flex-elem grows">
|
<div class="plot-wrapper-axis-and-display-area flex-elem grows">
|
||||||
<div
|
<div
|
||||||
v-if="seriesModels.length"
|
v-if="seriesModels.length"
|
||||||
@ -94,7 +86,6 @@
|
|||||||
:highlights="highlights"
|
:highlights="highlights"
|
||||||
:annotated-points="annotatedPoints"
|
:annotated-points="annotatedPoints"
|
||||||
:annotation-selections="annotationSelections"
|
:annotation-selections="annotationSelections"
|
||||||
:show-limit-line-labels="showLimitLineLabels"
|
|
||||||
:hidden-y-axis-ids="hiddenYAxisIds"
|
:hidden-y-axis-ids="hiddenYAxisIds"
|
||||||
:annotation-viewing-and-editing-allowed="annotationViewingAndEditingAllowed"
|
:annotation-viewing-and-editing-allowed="annotationViewingAndEditingAllowed"
|
||||||
@plotReinitializeCanvas="initCanvas"
|
@plotReinitializeCanvas="initCanvas"
|
||||||
@ -217,7 +208,6 @@ 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 MctTicks from "./MctTicks.vue";
|
import MctTicks from "./MctTicks.vue";
|
||||||
import MctChart from "./chart/MctChart.vue";
|
import MctChart from "./chart/MctChart.vue";
|
||||||
import XAxis from "./axis/XAxis.vue";
|
import XAxis from "./axis/XAxis.vue";
|
||||||
@ -232,7 +222,6 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
XAxis,
|
XAxis,
|
||||||
YAxis,
|
YAxis,
|
||||||
PlotLegend,
|
|
||||||
MctTicks,
|
MctTicks,
|
||||||
MctChart
|
MctChart
|
||||||
},
|
},
|
||||||
@ -296,7 +285,6 @@ export default {
|
|||||||
isRealTime: this.openmct.time.clock() !== undefined,
|
isRealTime: this.openmct.time.clock() !== undefined,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
isTimeOutOfSync: false,
|
isTimeOutOfSync: false,
|
||||||
showLimitLineLabels: this.limitLineLabels,
|
|
||||||
isFrozenOnMouseDown: false,
|
isFrozenOnMouseDown: false,
|
||||||
cursorGuide: this.initCursorGuide,
|
cursorGuide: this.initCursorGuide,
|
||||||
gridLines: this.initGridLines,
|
gridLines: this.initGridLines,
|
||||||
@ -334,23 +322,9 @@ export default {
|
|||||||
return this.config.xAxis.get('frozen') === true && this.config.yAxis.get('frozen') === true;
|
return this.config.xAxis.get('frozen') === true && this.config.yAxis.get('frozen') === true;
|
||||||
},
|
},
|
||||||
annotationViewingAndEditingAllowed() {
|
annotationViewingAndEditingAllowed() {
|
||||||
// only allow annotations viewing/editing if plot is paused or in fixed time mode
|
// only allow annotations viewing/editing if plot is paused or in fixed time mode
|
||||||
return this.isFrozen || !this.isRealTime;
|
return this.isFrozen || !this.isRealTime;
|
||||||
},
|
},
|
||||||
plotLegendPositionClass() {
|
|
||||||
return !this.isNestedWithinAStackedPlot ? `plot-legend-${this.config.legend.get('position')}` : '';
|
|
||||||
},
|
|
||||||
plotLegendExpandedStateClass() {
|
|
||||||
if (this.isNestedWithinAStackedPlot) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.config.legend.get('expanded')) {
|
|
||||||
return 'plot-legend-expanded';
|
|
||||||
} else {
|
|
||||||
return 'plot-legend-collapsed';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plotLeftTickWidth() {
|
plotLeftTickWidth() {
|
||||||
let leftTickWidth = 0;
|
let leftTickWidth = 0;
|
||||||
this.yAxes.forEach((yAxis) => {
|
this.yAxes.forEach((yAxis) => {
|
||||||
@ -365,12 +339,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
limitLineLabels: {
|
|
||||||
handler(limitLineLabels) {
|
|
||||||
this.legendHoverChanged(limitLineLabels);
|
|
||||||
},
|
|
||||||
deep: true
|
|
||||||
},
|
|
||||||
initGridLines(newGridLines) {
|
initGridLines(newGridLines) {
|
||||||
this.gridLines = newGridLines;
|
this.gridLines = newGridLines;
|
||||||
},
|
},
|
||||||
@ -406,8 +374,7 @@ export default {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
this.$emit('configLoaded', true);
|
||||||
this.$emit('configLoaded', configId);
|
|
||||||
|
|
||||||
this.listenTo(this.config.series, 'add', this.addSeries, this);
|
this.listenTo(this.config.series, 'add', this.addSeries, this);
|
||||||
this.listenTo(this.config.series, 'remove', this.removeSeries, this);
|
this.listenTo(this.config.series, 'remove', this.removeSeries, this);
|
||||||
@ -439,15 +406,20 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
updateSelection(selection) {
|
updateSelection(selection) {
|
||||||
const selectionContext = selection?.[0]?.[0]?.context?.item;
|
const selectionContext = selection?.[0]?.[0]?.context?.item;
|
||||||
if (!selectionContext
|
// on clicking on a search result we highlight the annotation and zoom - we know it's an annotation result when isAnnotationSearchResult === true
|
||||||
|| this.openmct.objects.areIdsEqual(selectionContext.identifier, this.domainObject.identifier)) {
|
// We shouldn't zoom when we're selecting existing annotations to view them or creating new annotations.
|
||||||
// Selection changed, but it's us, so ignoring it
|
const selectionType = selection?.[0]?.[0]?.context?.type;
|
||||||
|
const validSelectionTypes = ['clicked-on-plot-selection', 'plot-annotation-search-result'];
|
||||||
|
const isAnnotationSearchResult = selectionType === 'plot-annotation-search-result';
|
||||||
|
|
||||||
|
if (!validSelectionTypes.includes(selectionType)) {
|
||||||
|
// wrong type of selection
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectionType = selection?.[0]?.[1]?.context?.type;
|
if (selectionContext
|
||||||
if (selectionType !== 'plot-points-selection') {
|
&& (!isAnnotationSearchResult)
|
||||||
// wrong type of selection
|
&& this.openmct.objects.areIdsEqual(selectionContext.identifier, this.domainObject.identifier)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +432,18 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedAnnotations = selection?.[0]?.[1]?.context?.annotations;
|
const selectedAnnotations = selection?.[0]?.[0]?.context?.annotations;
|
||||||
|
//This section is only for the annotations search results entry to displaying annotations
|
||||||
|
if (isAnnotationSearchResult) {
|
||||||
|
this.showAnnotationsFromSearchResults(selectedAnnotations);
|
||||||
|
}
|
||||||
|
|
||||||
|
//This section is common to all entry points for annotation display
|
||||||
|
this.prepareExistingAnnotationSelection(selectedAnnotations);
|
||||||
|
},
|
||||||
|
showAnnotationsFromSearchResults(selectedAnnotations) {
|
||||||
|
//Start section
|
||||||
|
|
||||||
if (selectedAnnotations?.length) {
|
if (selectedAnnotations?.length) {
|
||||||
// just use first annotation
|
// just use first annotation
|
||||||
const boundingBoxes = Object.values(selectedAnnotations[0].targets);
|
const boundingBoxes = Object.values(selectedAnnotations[0].targets);
|
||||||
@ -494,10 +477,9 @@ export default {
|
|||||||
min: minY,
|
min: minY,
|
||||||
max: maxY
|
max: maxY
|
||||||
});
|
});
|
||||||
|
//Zoom out just a touch so that the highlighted section for annotations doesn't take over the whole view - which is not a nice look.
|
||||||
this.zoom('out', 0.2);
|
this.zoom('out', 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.prepareExistingAnnotationSelection(selectedAnnotations);
|
|
||||||
},
|
},
|
||||||
handleKeyDown(event) {
|
handleKeyDown(event) {
|
||||||
if (event.key === 'Alt') {
|
if (event.key === 'Alt') {
|
||||||
@ -688,9 +670,15 @@ export default {
|
|||||||
series.reset();
|
series.reset();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
shareCommonParent(domainObjectToFind) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
compositionPathContainsId(domainObjectToFind) {
|
||||||
|
if (!domainObjectToFind.composition) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
compositionPathContainsId(domainObjectToClear) {
|
return domainObjectToFind.composition.some((compositionIdentifier) => {
|
||||||
return domainObjectToClear.composition.some((compositionIdentifier) => {
|
|
||||||
return this.openmct.objects.areIdsEqual(compositionIdentifier, this.domainObject.identifier);
|
return this.openmct.objects.areIdsEqual(compositionIdentifier, this.domainObject.identifier);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -1044,8 +1032,6 @@ export default {
|
|||||||
|
|
||||||
highlightValues(point) {
|
highlightValues(point) {
|
||||||
this.highlightPoint = point;
|
this.highlightPoint = point;
|
||||||
// TODO: used in StackedPlotController
|
|
||||||
this.$emit('plotHighlightUpdate', point);
|
|
||||||
if (this.lockHighlightPoint) {
|
if (this.lockHighlightPoint) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1157,7 +1143,7 @@ export default {
|
|||||||
endPixels: this.positionOverElement,
|
endPixels: this.positionOverElement,
|
||||||
start: this.positionOverPlot,
|
start: this.positionOverPlot,
|
||||||
end: this.positionOverPlot,
|
end: this.positionOverPlot,
|
||||||
color: [1, 1, 1, 0.5]
|
color: [1, 1, 1, 0.25]
|
||||||
};
|
};
|
||||||
if (annotationEvent) {
|
if (annotationEvent) {
|
||||||
this.marquee.annotationEvent = true;
|
this.marquee.annotationEvent = true;
|
||||||
@ -1168,13 +1154,21 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectNearbyAnnotations(event) {
|
selectNearbyAnnotations(event) {
|
||||||
|
// need to stop propagation right away to prevent selecting the plot itself
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
if (!this.annotationViewingAndEditingAllowed || this.annotationSelections.length) {
|
if (!this.annotationViewingAndEditingAllowed || this.annotationSelections.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nearbyAnnotations = this.gatherNearbyAnnotations();
|
const nearbyAnnotations = this.gatherNearbyAnnotations();
|
||||||
|
if (!nearbyAnnotations.length) {
|
||||||
|
const emptySelection = this.createPathSelection();
|
||||||
|
this.openmct.selection.select(emptySelection, true);
|
||||||
|
// should show plot itself if we didn't find any annotations
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { targetDomainObjects, targetDetails } = this.prepareExistingAnnotationSelection(nearbyAnnotations);
|
const { targetDomainObjects, targetDetails } = this.prepareExistingAnnotationSelection(nearbyAnnotations);
|
||||||
this.selectPlotAnnotations({
|
this.selectPlotAnnotations({
|
||||||
targetDetails,
|
targetDetails,
|
||||||
@ -1182,33 +1176,50 @@ export default {
|
|||||||
annotations: nearbyAnnotations
|
annotations: nearbyAnnotations
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
createPathSelection() {
|
||||||
|
let selection = [];
|
||||||
|
this.path.forEach((pathObject, index) => {
|
||||||
|
selection.push({
|
||||||
|
element: this.openmct.layout.$refs.browseObject.$el,
|
||||||
|
context: {
|
||||||
|
item: pathObject
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return selection;
|
||||||
|
},
|
||||||
selectPlotAnnotations({targetDetails, targetDomainObjects, annotations}) {
|
selectPlotAnnotations({targetDetails, targetDomainObjects, annotations}) {
|
||||||
const selection =
|
const annotationContext = {
|
||||||
[
|
type: 'clicked-on-plot-selection',
|
||||||
{
|
targetDetails,
|
||||||
element: this.openmct.layout.$refs.browseObject.$el,
|
targetDomainObjects,
|
||||||
context: {
|
annotations,
|
||||||
item: this.domainObject
|
annotationType: this.openmct.annotation.ANNOTATION_TYPES.PLOT_SPATIAL,
|
||||||
}
|
onAnnotationChange: this.onAnnotationChange
|
||||||
},
|
};
|
||||||
{
|
const selection = this.createPathSelection();
|
||||||
element: this.$el,
|
if (selection.length && this.openmct.objects.areIdsEqual(selection[0].context.item.identifier, this.domainObject.identifier)) {
|
||||||
context: {
|
selection[0].context = {
|
||||||
type: 'plot-points-selection',
|
...selection[0].context,
|
||||||
targetDetails,
|
...annotationContext
|
||||||
targetDomainObjects,
|
};
|
||||||
annotations,
|
} else {
|
||||||
annotationType: this.openmct.annotation.ANNOTATION_TYPES.PLOT_SPATIAL,
|
selection.unshift({
|
||||||
onAnnotationChange: this.onAnnotationChange
|
element: this.$el,
|
||||||
}
|
context: {
|
||||||
}
|
item: this.domainObject,
|
||||||
];
|
...annotationContext
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.openmct.selection.select(selection, true);
|
this.openmct.selection.select(selection, true);
|
||||||
},
|
},
|
||||||
selectNewPlotAnnotations(boundingBoxPerYAxis, pointsInBox, event) {
|
selectNewPlotAnnotations(boundingBoxPerYAxis, pointsInBox, event) {
|
||||||
let targetDomainObjects = {};
|
let targetDomainObjects = {};
|
||||||
let targetDetails = {};
|
let targetDetails = {};
|
||||||
let annotations = {};
|
let annotations = [];
|
||||||
pointsInBox.forEach(pointInBox => {
|
pointsInBox.forEach(pointInBox => {
|
||||||
if (pointInBox.length) {
|
if (pointInBox.length) {
|
||||||
const seriesID = pointInBox[0].series.keyString;
|
const seriesID = pointInBox[0].series.keyString;
|
||||||
@ -1752,9 +1763,6 @@ export default {
|
|||||||
this.config.series.models.forEach(this.loadSeriesData, this);
|
this.config.series.models.forEach(this.loadSeriesData, this);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
legendHoverChanged(data) {
|
|
||||||
this.showLimitLineLabels = data;
|
|
||||||
},
|
|
||||||
toggleCursorGuide() {
|
toggleCursorGuide() {
|
||||||
this.cursorGuide = !this.cursorGuide;
|
this.cursorGuide = !this.cursorGuide;
|
||||||
this.$emit('cursorGuide', this.cursorGuide);
|
this.$emit('cursorGuide', this.cursorGuide);
|
||||||
|
@ -36,12 +36,26 @@
|
|||||||
:model="{progressPerc: undefined}"
|
:model="{progressPerc: undefined}"
|
||||||
/>
|
/>
|
||||||
<mct-plot
|
<mct-plot
|
||||||
|
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
||||||
:init-grid-lines="gridLines"
|
:init-grid-lines="gridLines"
|
||||||
:init-cursor-guide="cursorGuide"
|
:init-cursor-guide="cursorGuide"
|
||||||
:options="options"
|
:options="options"
|
||||||
|
:limit-line-labels="limitLineLabels"
|
||||||
@loadingUpdated="loadingUpdated"
|
@loadingUpdated="loadingUpdated"
|
||||||
@statusUpdated="setStatus"
|
@statusUpdated="setStatus"
|
||||||
/>
|
@configLoaded="updateReady"
|
||||||
|
@lockHighlightPoint="lockHighlightPointUpdated"
|
||||||
|
@highlights="highlightsUpdated"
|
||||||
|
>
|
||||||
|
<plot-legend
|
||||||
|
v-if="configReady"
|
||||||
|
:cursor-locked="lockHighlightPoint"
|
||||||
|
:highlights="highlights"
|
||||||
|
@legendHoverChanged="legendHoverChanged"
|
||||||
|
@expanded="updateExpanded"
|
||||||
|
@position="updatePosition"
|
||||||
|
/>
|
||||||
|
</mct-plot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -50,13 +64,15 @@
|
|||||||
import eventHelpers from './lib/eventHelpers';
|
import eventHelpers from './lib/eventHelpers';
|
||||||
import ImageExporter from '../../exporters/ImageExporter';
|
import ImageExporter from '../../exporters/ImageExporter';
|
||||||
import MctPlot from './MctPlot.vue';
|
import MctPlot from './MctPlot.vue';
|
||||||
|
import PlotLegend from "./legend/PlotLegend.vue";
|
||||||
import ProgressBar from "../../ui/components/ProgressBar.vue";
|
import ProgressBar from "../../ui/components/ProgressBar.vue";
|
||||||
import StalenessUtils from '@/utils/staleness';
|
import StalenessUtils from '@/utils/staleness';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
MctPlot,
|
MctPlot,
|
||||||
ProgressBar
|
ProgressBar,
|
||||||
|
PlotLegend
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'domainObject', 'path'],
|
inject: ['openmct', 'domainObject', 'path'],
|
||||||
props: {
|
props: {
|
||||||
@ -77,7 +93,13 @@ export default {
|
|||||||
gridLines: !this.options.compact,
|
gridLines: !this.options.compact,
|
||||||
loading: false,
|
loading: false,
|
||||||
status: '',
|
status: '',
|
||||||
staleObjects: []
|
staleObjects: [],
|
||||||
|
limitLineLabels: undefined,
|
||||||
|
lockHighlightPoint: false,
|
||||||
|
highlights: [],
|
||||||
|
expanded: false,
|
||||||
|
position: undefined,
|
||||||
|
configReady: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -87,6 +109,16 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
|
},
|
||||||
|
plotLegendPositionClass() {
|
||||||
|
return this.position ? `plot-legend-${this.position}` : '';
|
||||||
|
},
|
||||||
|
plotLegendExpandedStateClass() {
|
||||||
|
if (this.expanded) {
|
||||||
|
return 'plot-legend-expanded';
|
||||||
|
} else {
|
||||||
|
return 'plot-legend-collapsed';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -183,6 +215,24 @@ export default {
|
|||||||
exportPNG: this.exportPNG,
|
exportPNG: this.exportPNG,
|
||||||
exportJPG: this.exportJPG
|
exportJPG: this.exportJPG
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
lockHighlightPointUpdated(data) {
|
||||||
|
this.lockHighlightPoint = data;
|
||||||
|
},
|
||||||
|
highlightsUpdated(data) {
|
||||||
|
this.highlights = data;
|
||||||
|
},
|
||||||
|
legendHoverChanged(data) {
|
||||||
|
this.limitLineLabels = data;
|
||||||
|
},
|
||||||
|
updateExpanded(expanded) {
|
||||||
|
this.expanded = expanded;
|
||||||
|
},
|
||||||
|
updatePosition(position) {
|
||||||
|
this.position = position;
|
||||||
|
},
|
||||||
|
updateReady(ready) {
|
||||||
|
this.configReady = ready;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -202,6 +202,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.listenTo(series, 'change:yAxisId', this.addOrRemoveSeries.bind(this, series), this);
|
this.listenTo(series, 'change:yAxisId', this.addOrRemoveSeries.bind(this, series), this);
|
||||||
|
this.listenTo(series, 'change:color', this.updateSeriesColors.bind(this, series), this);
|
||||||
},
|
},
|
||||||
removeSeries(plotSeries) {
|
removeSeries(plotSeries) {
|
||||||
const seriesIndex = this.seriesModels.findIndex(model => this.openmct.objects.areIdsEqual(model.get('identifier'), plotSeries.get('identifier')));
|
const seriesIndex = this.seriesModels.findIndex(model => this.openmct.objects.areIdsEqual(model.get('identifier'), plotSeries.get('identifier')));
|
||||||
@ -216,6 +217,9 @@ export default {
|
|||||||
return model.get('yKey') === this.seriesModels[0].get('yKey');
|
return model.get('yKey') === this.seriesModels[0].get('yKey');
|
||||||
});
|
});
|
||||||
this.singleSeries = this.seriesModels.length === 1;
|
this.singleSeries = this.seriesModels.length === 1;
|
||||||
|
this.updateSeriesColors();
|
||||||
|
},
|
||||||
|
updateSeriesColors() {
|
||||||
this.seriesColors = this.seriesModels.map(model => {
|
this.seriesColors = this.seriesModels.map(model => {
|
||||||
return model.get('color').asHexString();
|
return model.get('color').asHexString();
|
||||||
});
|
});
|
||||||
|
@ -533,7 +533,6 @@ export default {
|
|||||||
},
|
},
|
||||||
updateLimitsAndDraw() {
|
updateLimitsAndDraw() {
|
||||||
this.drawLimitLines();
|
this.drawLimitLines();
|
||||||
this.scheduleDraw();
|
|
||||||
},
|
},
|
||||||
scheduleDraw() {
|
scheduleDraw() {
|
||||||
if (!this.drawScheduled) {
|
if (!this.drawScheduled) {
|
||||||
|
@ -67,6 +67,10 @@ export default class SeriesCollection extends Collection {
|
|||||||
}, this);
|
}, this);
|
||||||
}
|
}
|
||||||
watchTelemetryContainer(domainObject) {
|
watchTelemetryContainer(domainObject) {
|
||||||
|
if (domainObject.type === 'telemetry.plot.stacked') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const composition = this.openmct.composition.get(domainObject);
|
const composition = this.openmct.composition.get(domainObject);
|
||||||
this.listenTo(composition, 'add', this.addTelemetryObject, this);
|
this.listenTo(composition, 'add', this.addTelemetryObject, this);
|
||||||
this.listenTo(composition, 'remove', this.removeTelemetryObject, this);
|
this.listenTo(composition, 'remove', this.removeTelemetryObject, this);
|
||||||
|
@ -93,7 +93,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="plotSeries.length && (isStackedPlotObject || !isNestedWithinAStackedPlot)"
|
v-if="isStackedPlotObject || !isNestedWithinAStackedPlot"
|
||||||
class="grid-properties"
|
class="grid-properties"
|
||||||
>
|
>
|
||||||
<ul
|
<ul
|
||||||
@ -190,10 +190,13 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
eventHelpers.extend(this);
|
eventHelpers.extend(this);
|
||||||
this.config = this.getConfig();
|
this.config = this.getConfig();
|
||||||
this.initYAxesConfiguration();
|
if (!this.isStackedPlotObject) {
|
||||||
|
this.initYAxesConfiguration();
|
||||||
|
this.registerListeners();
|
||||||
|
} else {
|
||||||
|
this.initLegendConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
this.registerListeners();
|
|
||||||
this.initLegendConfiguration();
|
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -245,9 +248,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getConfig() {
|
getConfig() {
|
||||||
this.configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
|
||||||
return configStore.get(this.configId);
|
return configStore.get(configId);
|
||||||
},
|
},
|
||||||
registerListeners() {
|
registerListeners() {
|
||||||
if (this.config) {
|
if (this.config) {
|
||||||
|
@ -53,7 +53,6 @@
|
|||||||
>
|
>
|
||||||
<h2 title="Legend options">Legend</h2>
|
<h2 title="Legend options">Legend</h2>
|
||||||
<legend-form
|
<legend-form
|
||||||
v-if="plotSeries.length"
|
|
||||||
class="grid-properties"
|
class="grid-properties"
|
||||||
:legend="config.legend"
|
:legend="config.legend"
|
||||||
/>
|
/>
|
||||||
@ -97,20 +96,23 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
eventHelpers.extend(this);
|
eventHelpers.extend(this);
|
||||||
this.config = this.getConfig();
|
this.config = this.getConfig();
|
||||||
this.yAxes = [{
|
if (!this.isStackedPlotObject) {
|
||||||
id: this.config.yAxis.id,
|
this.yAxes = [{
|
||||||
seriesCount: 0
|
id: this.config.yAxis.id,
|
||||||
}];
|
seriesCount: 0
|
||||||
if (this.config.additionalYAxes) {
|
}];
|
||||||
this.yAxes = this.yAxes.concat(this.config.additionalYAxes.map(yAxis => {
|
if (this.config.additionalYAxes) {
|
||||||
return {
|
this.yAxes = this.yAxes.concat(this.config.additionalYAxes.map(yAxis => {
|
||||||
id: yAxis.id,
|
return {
|
||||||
seriesCount: 0
|
id: yAxis.id,
|
||||||
};
|
seriesCount: 0
|
||||||
}));
|
};
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.registerListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.registerListeners();
|
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
@ -12,11 +12,12 @@ export default function PlotsInspectorViewProvider(openmct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let object = selection[0][0].context.item;
|
let object = selection[0][0].context.item;
|
||||||
|
let parent = selection[0].length > 1 && selection[0][1].context.item;
|
||||||
|
|
||||||
const isOverlayPlotObject = object && object.type === 'telemetry.plot.overlay';
|
const isOverlayPlotObject = object && object.type === 'telemetry.plot.overlay';
|
||||||
const isStackedPlotObject = object && object.type === 'telemetry.plot.stacked';
|
const isParentStackedPlotObject = parent && parent.type === 'telemetry.plot.stacked';
|
||||||
|
|
||||||
return isStackedPlotObject || isOverlayPlotObject;
|
return isOverlayPlotObject || isParentStackedPlotObject;
|
||||||
},
|
},
|
||||||
view: function (selection) {
|
view: function (selection) {
|
||||||
let component;
|
let component;
|
||||||
|
@ -12,12 +12,10 @@ export default function StackedPlotsInspectorViewProvider(openmct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const object = selection[0][0].context.item;
|
const object = selection[0][0].context.item;
|
||||||
const parent = selection[0].length > 1 && selection[0][1].context.item;
|
|
||||||
|
|
||||||
const isOverlayPlotObject = object && object.type === 'telemetry.plot.overlay';
|
const isStackedPlotObject = object && object.type === 'telemetry.plot.stacked';
|
||||||
const isParentStackedPlotObject = parent && parent.type === 'telemetry.plot.stacked';
|
|
||||||
|
|
||||||
return !isOverlayPlotObject && isParentStackedPlotObject;
|
return isStackedPlotObject;
|
||||||
},
|
},
|
||||||
view: function (selection) {
|
view: function (selection) {
|
||||||
let component;
|
let component;
|
||||||
|
@ -49,10 +49,10 @@
|
|||||||
title="Cursor is point locked. Click anywhere in the plot to unlock."
|
title="Cursor is point locked. Click anywhere in the plot to unlock."
|
||||||
></div>
|
></div>
|
||||||
<plot-legend-item-collapsed
|
<plot-legend-item-collapsed
|
||||||
v-for="(seriesObject, seriesIndex) in series"
|
v-for="(seriesObject, seriesIndex) in seriesModels"
|
||||||
:key="`${seriesObject.keyString}-${seriesIndex}`"
|
:key="`${seriesObject.keyString}-${seriesIndex}-collapsed`"
|
||||||
:highlights="highlights"
|
:highlights="highlights"
|
||||||
:value-to-show-when-collapsed="legend.get('valueToShowWhenCollapsed')"
|
:value-to-show-when-collapsed="valueToShowWhenCollapsed"
|
||||||
:series-object="seriesObject"
|
:series-object="seriesObject"
|
||||||
@legendHoverChanged="legendHoverChanged"
|
@legendHoverChanged="legendHoverChanged"
|
||||||
/>
|
/>
|
||||||
@ -95,11 +95,10 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<plot-legend-item-expanded
|
<plot-legend-item-expanded
|
||||||
v-for="(seriesObject, seriesIndex) in series"
|
v-for="(seriesObject, seriesIndex) in seriesModels"
|
||||||
:key="`${seriesObject.keyString}-${seriesIndex}-expanded`"
|
:key="`${seriesObject.keyString}-${seriesIndex}-expanded`"
|
||||||
:series-object="seriesObject"
|
:series-object="seriesObject"
|
||||||
:highlights="highlights"
|
:highlights="highlights"
|
||||||
:legend="legend"
|
|
||||||
@legendHoverChanged="legendHoverChanged"
|
@legendHoverChanged="legendHoverChanged"
|
||||||
/>
|
/>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -111,6 +110,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import PlotLegendItemCollapsed from "./PlotLegendItemCollapsed.vue";
|
import PlotLegendItemCollapsed from "./PlotLegendItemCollapsed.vue";
|
||||||
import PlotLegendItemExpanded from "./PlotLegendItemExpanded.vue";
|
import PlotLegendItemExpanded from "./PlotLegendItemExpanded.vue";
|
||||||
|
import configStore from "../configuration/ConfigStore";
|
||||||
|
import eventHelpers from "../lib/eventHelpers";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
PlotLegendItemExpanded,
|
PlotLegendItemExpanded,
|
||||||
@ -124,57 +126,113 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
series: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
highlights: {
|
highlights: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default() {
|
default() {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLegendExpanded: this.legend.get('expanded') === true
|
isLegendExpanded: false,
|
||||||
|
seriesModels: [],
|
||||||
|
loaded: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showUnitsWhenExpanded() {
|
showUnitsWhenExpanded() {
|
||||||
return this.legend.get('showUnitsWhenExpanded') === true;
|
return this.loaded && this.legend.get('showUnitsWhenExpanded') === true;
|
||||||
},
|
},
|
||||||
showMinimumWhenExpanded() {
|
showMinimumWhenExpanded() {
|
||||||
return this.legend.get('showMinimumWhenExpanded') === true;
|
return this.loaded && this.legend.get('showMinimumWhenExpanded') === true;
|
||||||
},
|
},
|
||||||
showMaximumWhenExpanded() {
|
showMaximumWhenExpanded() {
|
||||||
return this.legend.get('showMaximumWhenExpanded') === true;
|
return this.loaded && this.legend.get('showMaximumWhenExpanded') === true;
|
||||||
},
|
},
|
||||||
showValueWhenExpanded() {
|
showValueWhenExpanded() {
|
||||||
return this.legend.get('showValueWhenExpanded') === true;
|
return this.loaded && this.legend.get('showValueWhenExpanded') === true;
|
||||||
},
|
},
|
||||||
showTimestampWhenExpanded() {
|
showTimestampWhenExpanded() {
|
||||||
return this.legend.get('showTimestampWhenExpanded') === true;
|
return this.loaded && this.legend.get('showTimestampWhenExpanded') === true;
|
||||||
},
|
},
|
||||||
isLegendHidden() {
|
isLegendHidden() {
|
||||||
return this.legend.get('hideLegendWhenSmall') === true;
|
return this.loaded && this.legend.get('hideLegendWhenSmall') === true;
|
||||||
|
},
|
||||||
|
valueToShowWhenCollapsed() {
|
||||||
|
return this.loaded && this.legend.get('valueToShowWhenCollapsed');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.seriesModels = [];
|
||||||
|
eventHelpers.extend(this);
|
||||||
|
this.config = this.getConfig();
|
||||||
|
this.legend = this.config.legend;
|
||||||
|
this.loaded = true;
|
||||||
|
this.isLegendExpanded = this.legend.get('expanded') === true;
|
||||||
|
this.listenTo(this.config.legend, 'change:position', this.updatePosition, this);
|
||||||
|
this.updatePosition();
|
||||||
|
|
||||||
|
this.initialize();
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.objectComposition) {
|
||||||
|
this.objectComposition.off('add', this.addTelemetryObject);
|
||||||
|
this.objectComposition.off('remove', this.removeTelemetryObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopListening();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
initialize() {
|
||||||
|
if (this.domainObject.type === 'telemetry.plot.stacked') {
|
||||||
|
this.objectComposition = this.openmct.composition.get(this.domainObject);
|
||||||
|
this.objectComposition.on('add', this.addTelemetryObject);
|
||||||
|
this.objectComposition.on('remove', this.removeTelemetryObject);
|
||||||
|
this.objectComposition.load();
|
||||||
|
} else {
|
||||||
|
this.registerListeners(this.config);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getConfig() {
|
||||||
|
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
|
||||||
|
return configStore.get(configId);
|
||||||
|
},
|
||||||
|
addTelemetryObject(object) {
|
||||||
|
//get the config for each child
|
||||||
|
const configId = this.openmct.objects.makeKeyString(object.identifier);
|
||||||
|
const config = configStore.get(configId);
|
||||||
|
if (config) {
|
||||||
|
this.registerListeners(config);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
registerListeners(config) {
|
||||||
|
//listen to any changes to the telemetry endpoints that are associated with the child
|
||||||
|
this.listenTo(config.series, 'add', this.addSeries, this);
|
||||||
|
this.listenTo(config.series, 'remove', this.removeSeries, this);
|
||||||
|
config.series.forEach(this.addSeries, this);
|
||||||
|
},
|
||||||
|
addSeries(series) {
|
||||||
|
this.$set(this.seriesModels, this.seriesModels.length, series);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeSeries(plotSeries) {
|
||||||
|
this.stopListening(plotSeries);
|
||||||
|
|
||||||
|
const seriesIndex = this.seriesModels.findIndex(series => series.keyString === plotSeries.keyString);
|
||||||
|
this.seriesModels.splice(seriesIndex, 1);
|
||||||
|
},
|
||||||
expandLegend() {
|
expandLegend() {
|
||||||
this.isLegendExpanded = !this.isLegendExpanded;
|
this.isLegendExpanded = !this.isLegendExpanded;
|
||||||
this.legend.set('expanded', this.isLegendExpanded);
|
this.legend.set('expanded', this.isLegendExpanded);
|
||||||
|
this.$emit('expanded', this.isLegendExpanded);
|
||||||
},
|
},
|
||||||
legendHoverChanged(data) {
|
legendHoverChanged(data) {
|
||||||
this.$emit('legendHoverChanged', data);
|
this.$emit('legendHoverChanged', data);
|
||||||
|
},
|
||||||
|
updatePosition() {
|
||||||
|
this.$emit('position', this.legend.get('position'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -57,15 +57,12 @@
|
|||||||
import {getLimitClass} from "@/plugins/plot/chart/limitUtil";
|
import {getLimitClass} from "@/plugins/plot/chart/limitUtil";
|
||||||
import eventHelpers from "../lib/eventHelpers";
|
import eventHelpers from "../lib/eventHelpers";
|
||||||
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
||||||
|
import configStore from "../configuration/ConfigStore";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [stalenessMixin],
|
mixins: [stalenessMixin],
|
||||||
inject: ['openmct', 'domainObject'],
|
inject: ['openmct', 'domainObject'],
|
||||||
props: {
|
props: {
|
||||||
valueToShowWhenCollapsed: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
seriesObject: {
|
seriesObject: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
@ -88,10 +85,14 @@ export default {
|
|||||||
formattedYValue: '',
|
formattedYValue: '',
|
||||||
formattedXValue: '',
|
formattedXValue: '',
|
||||||
mctLimitStateClass: '',
|
mctLimitStateClass: '',
|
||||||
formattedYValueFromStats: ''
|
formattedYValueFromStats: '',
|
||||||
|
loaded: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
valueToShowWhenCollapsed() {
|
||||||
|
return this.loaded ? this.legend.get('valueToShowWhenCollapsed') : [];
|
||||||
|
},
|
||||||
valueToDisplayWhenCollapsedClass() {
|
valueToDisplayWhenCollapsedClass() {
|
||||||
return `value-to-display-${ this.valueToShowWhenCollapsed }`;
|
return `value-to-display-${ this.valueToShowWhenCollapsed }`;
|
||||||
},
|
},
|
||||||
@ -109,6 +110,9 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
eventHelpers.extend(this);
|
eventHelpers.extend(this);
|
||||||
|
this.config = this.getConfig();
|
||||||
|
this.legend = this.config.legend;
|
||||||
|
this.loaded = true;
|
||||||
this.listenTo(this.seriesObject, 'change:color', (newColor) => {
|
this.listenTo(this.seriesObject, 'change:color', (newColor) => {
|
||||||
this.updateColor(newColor);
|
this.updateColor(newColor);
|
||||||
}, this);
|
}, this);
|
||||||
@ -122,8 +126,13 @@ export default {
|
|||||||
this.stopListening();
|
this.stopListening();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getConfig() {
|
||||||
|
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
|
||||||
|
return configStore.get(configId);
|
||||||
|
},
|
||||||
initialize(highlightedObject) {
|
initialize(highlightedObject) {
|
||||||
const seriesObject = highlightedObject ? highlightedObject.series : this.seriesObject;
|
const seriesObject = highlightedObject?.series || this.seriesObject;
|
||||||
|
|
||||||
this.isMissing = seriesObject.domainObject.status === 'missing';
|
this.isMissing = seriesObject.domainObject.status === 'missing';
|
||||||
this.colorAsHexString = seriesObject.get('color').asHexString();
|
this.colorAsHexString = seriesObject.get('color').asHexString();
|
||||||
|
@ -83,6 +83,7 @@
|
|||||||
import {getLimitClass} from "@/plugins/plot/chart/limitUtil";
|
import {getLimitClass} from "@/plugins/plot/chart/limitUtil";
|
||||||
import eventHelpers from "@/plugins/plot/lib/eventHelpers";
|
import eventHelpers from "@/plugins/plot/lib/eventHelpers";
|
||||||
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
||||||
|
import configStore from "../configuration/ConfigStore";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [stalenessMixin],
|
mixins: [stalenessMixin],
|
||||||
@ -100,10 +101,6 @@ export default {
|
|||||||
default() {
|
default() {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -116,24 +113,25 @@ export default {
|
|||||||
formattedXValue: '',
|
formattedXValue: '',
|
||||||
formattedMinY: '',
|
formattedMinY: '',
|
||||||
formattedMaxY: '',
|
formattedMaxY: '',
|
||||||
mctLimitStateClass: ''
|
mctLimitStateClass: '',
|
||||||
|
loaded: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showUnitsWhenExpanded() {
|
showUnitsWhenExpanded() {
|
||||||
return this.legend.get('showUnitsWhenExpanded') === true;
|
return this.loaded && this.legend.get('showUnitsWhenExpanded') === true;
|
||||||
},
|
},
|
||||||
showMinimumWhenExpanded() {
|
showMinimumWhenExpanded() {
|
||||||
return this.legend.get('showMinimumWhenExpanded') === true;
|
return this.loaded && this.legend.get('showMinimumWhenExpanded') === true;
|
||||||
},
|
},
|
||||||
showMaximumWhenExpanded() {
|
showMaximumWhenExpanded() {
|
||||||
return this.legend.get('showMaximumWhenExpanded') === true;
|
return this.loaded && this.legend.get('showMaximumWhenExpanded') === true;
|
||||||
},
|
},
|
||||||
showValueWhenExpanded() {
|
showValueWhenExpanded() {
|
||||||
return this.legend.get('showValueWhenExpanded') === true;
|
return this.loaded && this.legend.get('showValueWhenExpanded') === true;
|
||||||
},
|
},
|
||||||
showTimestampWhenExpanded() {
|
showTimestampWhenExpanded() {
|
||||||
return this.legend.get('showTimestampWhenExpanded') === true;
|
return this.loaded && this.legend.get('showTimestampWhenExpanded') === true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -146,6 +144,9 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
eventHelpers.extend(this);
|
eventHelpers.extend(this);
|
||||||
|
this.config = this.getConfig();
|
||||||
|
this.legend = this.config.legend;
|
||||||
|
this.loaded = true;
|
||||||
this.listenTo(this.seriesObject, 'change:color', (newColor) => {
|
this.listenTo(this.seriesObject, 'change:color', (newColor) => {
|
||||||
this.updateColor(newColor);
|
this.updateColor(newColor);
|
||||||
}, this);
|
}, this);
|
||||||
@ -159,8 +160,13 @@ export default {
|
|||||||
this.stopListening();
|
this.stopListening();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getConfig() {
|
||||||
|
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
|
||||||
|
return configStore.get(configId);
|
||||||
|
},
|
||||||
initialize(highlightedObject) {
|
initialize(highlightedObject) {
|
||||||
const seriesObject = highlightedObject ? highlightedObject.series : this.seriesObject;
|
const seriesObject = highlightedObject?.series || this.seriesObject;
|
||||||
|
|
||||||
this.isMissing = seriesObject.domainObject.status === 'missing';
|
this.isMissing = seriesObject.domainObject.status === 'missing';
|
||||||
this.colorAsHexString = seriesObject.get('color').asHexString();
|
this.colorAsHexString = seriesObject.get('color').asHexString();
|
||||||
|
@ -27,13 +27,16 @@
|
|||||||
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
||||||
>
|
>
|
||||||
<plot-legend
|
<plot-legend
|
||||||
|
v-if="compositionObjectsConfigLoaded"
|
||||||
:cursor-locked="!!lockHighlightPoint"
|
:cursor-locked="!!lockHighlightPoint"
|
||||||
:series="seriesModels"
|
|
||||||
:highlights="highlights"
|
:highlights="highlights"
|
||||||
:legend="legend"
|
|
||||||
@legendHoverChanged="legendHoverChanged"
|
@legendHoverChanged="legendHoverChanged"
|
||||||
|
@expanded="updateExpanded"
|
||||||
|
@position="updatePosition"
|
||||||
/>
|
/>
|
||||||
<div class="l-view-section">
|
<div
|
||||||
|
class="l-view-section"
|
||||||
|
>
|
||||||
<stacked-plot-item
|
<stacked-plot-item
|
||||||
v-for="objectWrapper in compositionObjects"
|
v-for="objectWrapper in compositionObjects"
|
||||||
:key="objectWrapper.keyString"
|
:key="objectWrapper.keyString"
|
||||||
@ -51,7 +54,7 @@
|
|||||||
@gridLines="onGridLinesChange"
|
@gridLines="onGridLinesChange"
|
||||||
@lockHighlightPoint="lockHighlightPointUpdated"
|
@lockHighlightPoint="lockHighlightPointUpdated"
|
||||||
@highlights="highlightsUpdated"
|
@highlights="highlightsUpdated"
|
||||||
@configLoaded="registerSeriesListeners"
|
@configLoaded="configLoadedForObject(objectWrapper.keyString)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -66,14 +69,13 @@ import ColorPalette from "@/ui/color/ColorPalette";
|
|||||||
import PlotLegend from "../legend/PlotLegend.vue";
|
import PlotLegend from "../legend/PlotLegend.vue";
|
||||||
import StackedPlotItem from './StackedPlotItem.vue';
|
import StackedPlotItem from './StackedPlotItem.vue';
|
||||||
import ImageExporter from '../../../exporters/ImageExporter';
|
import ImageExporter from '../../../exporters/ImageExporter';
|
||||||
import eventHelpers from "@/plugins/plot/lib/eventHelpers";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
StackedPlotItem,
|
StackedPlotItem,
|
||||||
PlotLegend
|
PlotLegend
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'domainObject', 'composition', 'path'],
|
inject: ['openmct', 'domainObject', 'path'],
|
||||||
props: {
|
props: {
|
||||||
options: {
|
options: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -87,24 +89,25 @@ export default {
|
|||||||
hideExportButtons: false,
|
hideExportButtons: false,
|
||||||
cursorGuide: false,
|
cursorGuide: false,
|
||||||
gridLines: true,
|
gridLines: true,
|
||||||
loading: false,
|
configLoaded: {},
|
||||||
compositionObjects: [],
|
compositionObjects: [],
|
||||||
tickWidthMap: {},
|
tickWidthMap: {},
|
||||||
legend: {},
|
|
||||||
loaded: false,
|
loaded: false,
|
||||||
lockHighlightPoint: false,
|
lockHighlightPoint: false,
|
||||||
highlights: [],
|
highlights: [],
|
||||||
seriesModels: [],
|
|
||||||
showLimitLineLabels: undefined,
|
showLimitLineLabels: undefined,
|
||||||
colorPalette: new ColorPalette()
|
colorPalette: new ColorPalette(),
|
||||||
|
compositionObjectsConfigLoaded: false,
|
||||||
|
position: 'top',
|
||||||
|
expanded: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
plotLegendPositionClass() {
|
plotLegendPositionClass() {
|
||||||
return `plot-legend-${this.config.legend.get('position')}`;
|
return `plot-legend-${this.position}`;
|
||||||
},
|
},
|
||||||
plotLegendExpandedStateClass() {
|
plotLegendExpandedStateClass() {
|
||||||
if (this.config.legend.get('expanded')) {
|
if (this.expanded) {
|
||||||
return 'plot-legend-expanded';
|
return 'plot-legend-expanded';
|
||||||
} else {
|
} else {
|
||||||
return 'plot-legend-collapsed';
|
return 'plot-legend-collapsed';
|
||||||
@ -118,17 +121,14 @@ export default {
|
|||||||
this.destroy();
|
this.destroy();
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
eventHelpers.extend(this);
|
//We only need to initialize the stacked plot config for legend properties
|
||||||
this.seriesConfig = {};
|
|
||||||
|
|
||||||
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
this.config = this.getConfig(configId);
|
this.config = this.getConfig(configId);
|
||||||
|
|
||||||
this.legend = this.config.legend;
|
|
||||||
|
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
this.imageExporter = new ImageExporter(this.openmct);
|
this.imageExporter = new ImageExporter(this.openmct);
|
||||||
|
|
||||||
|
this.composition = this.openmct.composition.get(this.domainObject);
|
||||||
this.composition.on('add', this.addChild);
|
this.composition.on('add', this.addChild);
|
||||||
this.composition.on('remove', this.removeChild);
|
this.composition.on('remove', this.removeChild);
|
||||||
this.composition.on('reorder', this.compositionReorder);
|
this.composition.on('reorder', this.compositionReorder);
|
||||||
@ -142,7 +142,6 @@ export default {
|
|||||||
id: configId,
|
id: configId,
|
||||||
domainObject: this.domainObject,
|
domainObject: this.domainObject,
|
||||||
openmct: this.openmct,
|
openmct: this.openmct,
|
||||||
palette: this.colorPalette,
|
|
||||||
callback: (data) => {
|
callback: (data) => {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
@ -155,10 +154,19 @@ export default {
|
|||||||
loadingUpdated(loaded) {
|
loadingUpdated(loaded) {
|
||||||
this.loading = loaded;
|
this.loading = loaded;
|
||||||
},
|
},
|
||||||
destroy() {
|
configLoadedForObject(childObjIdentifier) {
|
||||||
this.stopListening();
|
const childObjId = this.openmct.objects.makeKeyString(childObjIdentifier);
|
||||||
configStore.deleteStore(this.config.id);
|
this.configLoaded[childObjId] = true;
|
||||||
|
this.setConfigLoadedForComposition();
|
||||||
|
},
|
||||||
|
setConfigLoadedForComposition() {
|
||||||
|
this.compositionObjectsConfigLoaded = this.compositionObjects.length && this.compositionObjects.every(childObject => {
|
||||||
|
const id = childObject.keyString;
|
||||||
|
|
||||||
|
return this.configLoaded[id] === true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy() {
|
||||||
this.composition.off('add', this.addChild);
|
this.composition.off('add', this.addChild);
|
||||||
this.composition.off('remove', this.removeChild);
|
this.composition.off('remove', this.removeChild);
|
||||||
this.composition.off('reorder', this.compositionReorder);
|
this.composition.off('reorder', this.compositionReorder);
|
||||||
@ -173,6 +181,7 @@ export default {
|
|||||||
object: child,
|
object: child,
|
||||||
keyString: id
|
keyString: id
|
||||||
});
|
});
|
||||||
|
this.setConfigLoadedForComposition();
|
||||||
},
|
},
|
||||||
|
|
||||||
removeChild(childIdentifier) {
|
removeChild(childIdentifier) {
|
||||||
@ -180,23 +189,36 @@ export default {
|
|||||||
|
|
||||||
this.$delete(this.tickWidthMap, id);
|
this.$delete(this.tickWidthMap, id);
|
||||||
|
|
||||||
const configIndex = this.domainObject.configuration.series.findIndex((seriesConfig) => {
|
const childObj = this.compositionObjects.filter((c) => {
|
||||||
return this.openmct.objects.areIdsEqual(seriesConfig.identifier, childIdentifier);
|
const identifier = c.keyString;
|
||||||
});
|
|
||||||
|
|
||||||
if (configIndex > -1) {
|
return identifier === id;
|
||||||
this.domainObject.configuration.series.splice(configIndex, 1);
|
})[0];
|
||||||
|
|
||||||
|
if (childObj) {
|
||||||
|
if (childObj.object.type !== 'telemetry.plot.overlay') {
|
||||||
|
const config = this.getConfig(childObj.keyString);
|
||||||
|
if (config) {
|
||||||
|
config.series.remove(config.series.at(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.removeSeries({
|
|
||||||
keyString: id
|
|
||||||
});
|
|
||||||
|
|
||||||
this.compositionObjects = this.compositionObjects.filter((c) => {
|
this.compositionObjects = this.compositionObjects.filter((c) => {
|
||||||
const identifier = c.keyString;
|
const identifier = c.keyString;
|
||||||
|
|
||||||
return identifier !== id;
|
return identifier !== id;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const configIndex = this.domainObject.configuration.series.findIndex((seriesConfig) => {
|
||||||
|
return this.openmct.objects.areIdsEqual(seriesConfig.identifier, childIdentifier);
|
||||||
|
});
|
||||||
|
if (configIndex > -1) {
|
||||||
|
const cSeries = this.domainObject.configuration.series.slice();
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'configuration.series', cSeries);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setConfigLoadedForComposition();
|
||||||
},
|
},
|
||||||
|
|
||||||
compositionReorder(reorderPlan) {
|
compositionReorder(reorderPlan) {
|
||||||
@ -245,39 +267,18 @@ export default {
|
|||||||
lockHighlightPointUpdated(data) {
|
lockHighlightPointUpdated(data) {
|
||||||
this.lockHighlightPoint = data;
|
this.lockHighlightPoint = data;
|
||||||
},
|
},
|
||||||
|
updateExpanded(expanded) {
|
||||||
|
this.expanded = expanded;
|
||||||
|
},
|
||||||
|
updatePosition(position) {
|
||||||
|
this.position = position;
|
||||||
|
},
|
||||||
|
updateReady(ready) {
|
||||||
|
this.configReady = ready;
|
||||||
|
},
|
||||||
highlightsUpdated(data) {
|
highlightsUpdated(data) {
|
||||||
this.highlights = data;
|
this.highlights = data;
|
||||||
},
|
},
|
||||||
registerSeriesListeners(configId) {
|
|
||||||
const config = this.getConfig(configId);
|
|
||||||
this.seriesConfig[configId] = config;
|
|
||||||
const childObject = config.get('domainObject');
|
|
||||||
|
|
||||||
//TODO differentiate between objects with composition and those without
|
|
||||||
if (childObject.type === 'telemetry.plot.overlay') {
|
|
||||||
this.listenTo(config.series, 'add', this.addSeries, this);
|
|
||||||
this.listenTo(config.series, 'remove', this.removeSeries, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
config.series.models.forEach(this.addSeries, this);
|
|
||||||
},
|
|
||||||
addSeries(series) {
|
|
||||||
const childObject = series.domainObject;
|
|
||||||
//don't add the series if it can have child series this will happen in registerSeriesListeners
|
|
||||||
if (childObject.type !== 'telemetry.plot.overlay') {
|
|
||||||
const index = this.seriesModels.length;
|
|
||||||
this.$set(this.seriesModels, index, series);
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
removeSeries(plotSeries) {
|
|
||||||
const index = this.seriesModels.findIndex(seriesModel => seriesModel.keyString === plotSeries.keyString);
|
|
||||||
if (index > -1) {
|
|
||||||
this.$delete(this.seriesModels, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.stopListening(plotSeries);
|
|
||||||
},
|
|
||||||
onCursorGuideChange(cursorGuide) {
|
onCursorGuideChange(cursorGuide) {
|
||||||
this.cursorGuide = cursorGuide === true;
|
this.cursorGuide = cursorGuide === true;
|
||||||
},
|
},
|
||||||
|
@ -100,10 +100,6 @@ export default {
|
|||||||
this.updateView();
|
this.updateView();
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.removeSelectable) {
|
|
||||||
this.removeSelectable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.component) {
|
if (this.component) {
|
||||||
this.component.$destroy();
|
this.component.$destroy();
|
||||||
}
|
}
|
||||||
@ -180,8 +176,6 @@ export default {
|
|||||||
},
|
},
|
||||||
template: '<div v-if="!isMissing" ref="plotWrapper" class="l-view-section u-style-receiver js-style-receiver" :class="{\'s-status-timeconductor-unsynced\': status && status === \'timeconductor-unsynced\', \'is-stale\': isStale}"><progress-bar v-show="loading !== false" class="c-telemetry-table__progress-bar" :model="{progressPerc: undefined}" /><mct-plot :init-grid-lines="gridLines" :init-cursor-guide="cursorGuide" :plot-tick-width="plotTickWidth" :limit-line-labels="limitLineLabels" :color-palette="colorPalette" :options="options" @plotTickWidth="onTickWidthChange" @lockHighlightPoint="onLockHighlightPointUpdated" @highlights="onHighlightsUpdated" @configLoaded="onConfigLoaded" @cursorGuide="onCursorGuideChange" @gridLines="onGridLinesChange" @statusUpdated="setStatus" @loadingUpdated="loadingUpdated"/></div>'
|
template: '<div v-if="!isMissing" ref="plotWrapper" class="l-view-section u-style-receiver js-style-receiver" :class="{\'s-status-timeconductor-unsynced\': status && status === \'timeconductor-unsynced\', \'is-stale\': isStale}"><progress-bar v-show="loading !== false" class="c-telemetry-table__progress-bar" :model="{progressPerc: undefined}" /><mct-plot :init-grid-lines="gridLines" :init-cursor-guide="cursorGuide" :plot-tick-width="plotTickWidth" :limit-line-labels="limitLineLabels" :color-palette="colorPalette" :options="options" @plotTickWidth="onTickWidthChange" @lockHighlightPoint="onLockHighlightPointUpdated" @highlights="onHighlightsUpdated" @configLoaded="onConfigLoaded" @cursorGuide="onCursorGuideChange" @gridLines="onGridLinesChange" @statusUpdated="setStatus" @loadingUpdated="loadingUpdated"/></div>'
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setSelection();
|
|
||||||
},
|
},
|
||||||
onLockHighlightPointUpdated() {
|
onLockHighlightPointUpdated() {
|
||||||
this.$emit('lockHighlightPoint', ...arguments);
|
this.$emit('lockHighlightPoint', ...arguments);
|
||||||
@ -205,17 +199,6 @@ export default {
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
this.updateComponentProp('status', status);
|
this.updateComponentProp('status', status);
|
||||||
},
|
},
|
||||||
setSelection() {
|
|
||||||
let childContext = {};
|
|
||||||
childContext.item = this.childObject;
|
|
||||||
this.context = childContext;
|
|
||||||
if (this.removeSelectable) {
|
|
||||||
this.removeSelectable();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.removeSelectable = this.openmct.selection.selectable(
|
|
||||||
this.$el, this.context);
|
|
||||||
},
|
|
||||||
getProps() {
|
getProps() {
|
||||||
return {
|
return {
|
||||||
limitLineLabels: this.showLimitLineLabels,
|
limitLineLabels: this.showLimitLineLabels,
|
||||||
@ -230,7 +213,7 @@ export default {
|
|||||||
},
|
},
|
||||||
getPlotObject() {
|
getPlotObject() {
|
||||||
if (this.childObject.configuration && this.childObject.configuration.series) {
|
if (this.childObject.configuration && this.childObject.configuration.series) {
|
||||||
//If the object has a configuration, allow initialization of the config from it's persisted config
|
//If the object has a configuration (like an overlay plot), allow initialization of the config from it's persisted config
|
||||||
return this.childObject;
|
return this.childObject;
|
||||||
} else {
|
} else {
|
||||||
//If object is missing, warn and return object
|
//If object is missing, warn and return object
|
||||||
|
@ -57,7 +57,6 @@ export default function StackedPlotViewProvider(openmct) {
|
|||||||
provide: {
|
provide: {
|
||||||
openmct,
|
openmct,
|
||||||
domainObject,
|
domainObject,
|
||||||
composition: openmct.composition.get(domainObject),
|
|
||||||
path: objectPath
|
path: objectPath
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -173,7 +173,7 @@ describe("the plugin", function () {
|
|||||||
let testTelemetryObject2;
|
let testTelemetryObject2;
|
||||||
let config;
|
let config;
|
||||||
let component;
|
let component;
|
||||||
let mockComposition;
|
let mockCompositionList = [];
|
||||||
let plotViewComponentObject;
|
let plotViewComponentObject;
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
@ -271,14 +271,34 @@ describe("the plugin", function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mockComposition = new EventEmitter();
|
stackedPlotObject.composition = [{
|
||||||
mockComposition.load = () => {
|
identifier: testTelemetryObject.identifier
|
||||||
mockComposition.emit('add', testTelemetryObject);
|
}];
|
||||||
|
|
||||||
return [testTelemetryObject];
|
mockCompositionList = [];
|
||||||
};
|
spyOn(openmct.composition, 'get').and.callFake((domainObject) => {
|
||||||
|
//We need unique compositions here - one for the StackedPlot view and one for the PlotLegend view
|
||||||
|
const numObjects = domainObject.composition.length;
|
||||||
|
const mockComposition = new EventEmitter();
|
||||||
|
mockComposition.load = () => {
|
||||||
|
if (numObjects === 1) {
|
||||||
|
mockComposition.emit('add', testTelemetryObject);
|
||||||
|
|
||||||
spyOn(openmct.composition, 'get').and.returnValue(mockComposition);
|
return [testTelemetryObject];
|
||||||
|
} else if (numObjects === 2) {
|
||||||
|
mockComposition.emit('add', testTelemetryObject);
|
||||||
|
mockComposition.emit('add', testTelemetryObject2);
|
||||||
|
|
||||||
|
return [testTelemetryObject, testTelemetryObject2];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mockCompositionList.push(mockComposition);
|
||||||
|
|
||||||
|
return mockComposition;
|
||||||
|
});
|
||||||
|
|
||||||
let viewContainer = document.createElement("div");
|
let viewContainer = document.createElement("div");
|
||||||
child.append(viewContainer);
|
child.append(viewContainer);
|
||||||
@ -290,7 +310,6 @@ describe("the plugin", function () {
|
|||||||
provide: {
|
provide: {
|
||||||
openmct: openmct,
|
openmct: openmct,
|
||||||
domainObject: stackedPlotObject,
|
domainObject: stackedPlotObject,
|
||||||
composition: openmct.composition.get(stackedPlotObject),
|
|
||||||
path: [stackedPlotObject]
|
path: [stackedPlotObject]
|
||||||
},
|
},
|
||||||
template: "<stacked-plot></stacked-plot>"
|
template: "<stacked-plot></stacked-plot>"
|
||||||
@ -321,7 +340,7 @@ describe("the plugin", function () {
|
|||||||
expect(legend.length).toBe(6);
|
expect(legend.length).toBe(6);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Renders X-axis ticks for the telemetry object", (done) => {
|
it("Renders X-axis ticks for the telemetry object", () => {
|
||||||
let xAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-x .gl-plot-tick-wrapper");
|
let xAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-x .gl-plot-tick-wrapper");
|
||||||
expect(xAxisElement.length).toBe(1);
|
expect(xAxisElement.length).toBe(1);
|
||||||
|
|
||||||
@ -329,13 +348,8 @@ describe("the plugin", function () {
|
|||||||
min: 0,
|
min: 0,
|
||||||
max: 4
|
max: 4
|
||||||
});
|
});
|
||||||
|
let ticks = xAxisElement[0].querySelectorAll(".gl-plot-tick");
|
||||||
Vue.nextTick(() => {
|
expect(ticks.length).toBe(9);
|
||||||
let ticks = xAxisElement[0].querySelectorAll(".gl-plot-tick");
|
|
||||||
expect(ticks.length).toBe(9);
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Renders Y-axis ticks for the telemetry object", (done) => {
|
it("Renders Y-axis ticks for the telemetry object", (done) => {
|
||||||
@ -401,17 +415,22 @@ describe("the plugin", function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('plots a new series when a new telemetry object is added', (done) => {
|
it('plots a new series when a new telemetry object is added', (done) => {
|
||||||
mockComposition.emit('add', testTelemetryObject2);
|
//setting composition here so that any new triggers to composition.load with correctly load the mockComposition in the beforeEach
|
||||||
|
stackedPlotObject.composition = [testTelemetryObject, testTelemetryObject2];
|
||||||
|
mockCompositionList[0].emit('add', testTelemetryObject2);
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
||||||
expect(legend.length).toBe(2);
|
expect(legend.length).toBe(2);
|
||||||
expect(legend[1].innerHTML).toEqual("Test Object2");
|
expect(legend[1].innerHTML).toEqual("Test Object2");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('removes plots from series when a telemetry object is removed', (done) => {
|
it('removes plots from series when a telemetry object is removed', (done) => {
|
||||||
mockComposition.emit('remove', testTelemetryObject.identifier);
|
stackedPlotObject.composition = [];
|
||||||
|
mockCompositionList[0].emit('remove', testTelemetryObject.identifier);
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
expect(plotViewComponentObject.compositionObjects.length).toBe(0);
|
expect(plotViewComponentObject.compositionObjects.length).toBe(0);
|
||||||
done();
|
done();
|
||||||
@ -429,16 +448,6 @@ describe("the plugin", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Renders a new series when added to one of the plots", (done) => {
|
|
||||||
mockComposition.emit('add', testTelemetryObject2);
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
|
||||||
expect(legend.length).toBe(2);
|
|
||||||
expect(legend[1].innerHTML).toEqual("Test Object2");
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Adds a new point to the plot", (done) => {
|
it("Adds a new point to the plot", (done) => {
|
||||||
let originalLength = config.series.models[0].getSeriesData().length;
|
let originalLength = config.series.models[0].getSeriesData().length;
|
||||||
config.series.models[0].add({
|
config.series.models[0].add({
|
||||||
@ -459,7 +468,7 @@ describe("the plugin", function () {
|
|||||||
max: 10
|
max: 10
|
||||||
});
|
});
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
expect(plotViewComponentObject.$children[1].component.$children[1].xScale.domain()).toEqual({
|
expect(plotViewComponentObject.$children[0].component.$children[1].xScale.domain()).toEqual({
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 10
|
max: 10
|
||||||
});
|
});
|
||||||
@ -476,7 +485,7 @@ describe("the plugin", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
const yAxesScales = plotViewComponentObject.$children[1].component.$children[1].yScale;
|
const yAxesScales = plotViewComponentObject.$children[0].component.$children[1].yScale;
|
||||||
yAxesScales.forEach((yAxisScale) => {
|
yAxesScales.forEach((yAxisScale) => {
|
||||||
expect(yAxisScale.scale.domain()).toEqual({
|
expect(yAxisScale.scale.domain()).toEqual({
|
||||||
min: 10,
|
min: 10,
|
||||||
|
@ -42,7 +42,6 @@
|
|||||||
@import "../ui/inspector/elements.scss";
|
@import "../ui/inspector/elements.scss";
|
||||||
@import "../ui/inspector/inspector.scss";
|
@import "../ui/inspector/inspector.scss";
|
||||||
@import "../ui/inspector/location.scss";
|
@import "../ui/inspector/location.scss";
|
||||||
@import "../ui/inspector/annotations/annotation-inspector.scss";
|
|
||||||
@import "../ui/layout/app-logo.scss";
|
@import "../ui/layout/app-logo.scss";
|
||||||
@import "../ui/layout/create-button.scss";
|
@import "../ui/layout/create-button.scss";
|
||||||
@import "../ui/layout/layout.scss";
|
@import "../ui/layout/layout.scss";
|
||||||
|
@ -145,7 +145,7 @@ export default {
|
|||||||
|
|
||||||
this.unlistenComposition();
|
this.unlistenComposition();
|
||||||
|
|
||||||
if (this.parentObject) {
|
if (this.parentObject && this.parentObject.type === 'telemetry.plot.overlay') {
|
||||||
this.setYAxisIds();
|
this.setYAxisIds();
|
||||||
this.composition = this.openmct.composition.get(this.parentObject);
|
this.composition = this.openmct.composition.get(this.parentObject);
|
||||||
|
|
||||||
@ -175,6 +175,7 @@ export default {
|
|||||||
setYAxisIds() {
|
setYAxisIds() {
|
||||||
const configId = this.openmct.objects.makeKeyString(this.parentObject.identifier);
|
const configId = this.openmct.objects.makeKeyString(this.parentObject.identifier);
|
||||||
this.config = configStore.get(configId);
|
this.config = configStore.get(configId);
|
||||||
|
this.yAxes = [];
|
||||||
this.yAxes.push({
|
this.yAxes.push({
|
||||||
id: this.config.yAxis.id,
|
id: this.config.yAxis.id,
|
||||||
elements: this.parentObject.configuration.series.filter(
|
elements: this.parentObject.configuration.series.filter(
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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 class="c-annotation__row">
|
|
||||||
<textarea
|
|
||||||
v-model="contentModel"
|
|
||||||
class="c-annotation__text_area"
|
|
||||||
type="text"
|
|
||||||
></textarea>
|
|
||||||
<div>
|
|
||||||
<span>{{ modifiedOnDate }}</span>
|
|
||||||
<span>{{ modifiedOnTime }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Moment from 'moment';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
inject: ['openmct'],
|
|
||||||
props: {
|
|
||||||
annotation: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
contentModel: {
|
|
||||||
get() {
|
|
||||||
return this.annotation.contentText;
|
|
||||||
},
|
|
||||||
set(contentText) {
|
|
||||||
console.debug(`Set tag called with ${contentText}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifiedOnDate() {
|
|
||||||
return this.formatTime(this.annotation.modified, 'YYYY-MM-DD');
|
|
||||||
},
|
|
||||||
modifiedOnTime() {
|
|
||||||
return this.formatTime(this.annotation.modified, 'HH:mm:ss');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getAvailableTagByID(tagID) {
|
|
||||||
return this.openmct.annotation.getAvailableTags().find(tag => {
|
|
||||||
return tag.id === tagID;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
formatTime(unixTime, timeFormat) {
|
|
||||||
return Moment.utc(unixTime).format(timeFormat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -111,25 +111,31 @@ export default {
|
|||||||
return this?.selection?.[0]?.[0]?.context?.item;
|
return this?.selection?.[0]?.[0]?.context?.item;
|
||||||
},
|
},
|
||||||
targetDetails() {
|
targetDetails() {
|
||||||
return this?.selection?.[0]?.[1]?.context?.targetDetails ?? {};
|
return this?.selection?.[0]?.[0]?.context?.targetDetails ?? {};
|
||||||
},
|
},
|
||||||
shouldShowTagsEditor() {
|
shouldShowTagsEditor() {
|
||||||
return Object.keys(this.targetDetails).length > 0;
|
const showingTagsEditor = Object.keys(this.targetDetails).length > 0;
|
||||||
|
|
||||||
|
if (showingTagsEditor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
targetDomainObjects() {
|
targetDomainObjects() {
|
||||||
return this?.selection?.[0]?.[1]?.context?.targetDomainObjects ?? {};
|
return this?.selection?.[0]?.[0]?.context?.targetDomainObjects ?? {};
|
||||||
},
|
},
|
||||||
selectedAnnotations() {
|
selectedAnnotations() {
|
||||||
return this?.selection?.[0]?.[1]?.context?.annotations;
|
return this?.selection?.[0]?.[0]?.context?.annotations;
|
||||||
},
|
},
|
||||||
annotationType() {
|
annotationType() {
|
||||||
return this?.selection?.[0]?.[1]?.context?.annotationType;
|
return this?.selection?.[0]?.[0]?.context?.annotationType;
|
||||||
},
|
},
|
||||||
annotationFilter() {
|
annotationFilter() {
|
||||||
return this?.selection?.[0]?.[1]?.context?.annotationFilter;
|
return this?.selection?.[0]?.[0]?.context?.annotationFilter;
|
||||||
},
|
},
|
||||||
onAnnotationChange() {
|
onAnnotationChange() {
|
||||||
return this?.selection?.[0]?.[1]?.context?.onAnnotationChange;
|
return this?.selection?.[0]?.[0]?.context?.onAnnotationChange;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
@ -195,6 +201,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async loadAnnotationForTargetObject(target) {
|
async loadAnnotationForTargetObject(target) {
|
||||||
|
console.debug(`📝 Loading annotations for target`, target);
|
||||||
const targetID = this.openmct.objects.makeKeyString(target.identifier);
|
const targetID = this.openmct.objects.makeKeyString(target.identifier);
|
||||||
const allAnnotationsForTarget = await this.openmct.annotation.getAnnotations(target.identifier);
|
const allAnnotationsForTarget = await this.openmct.annotation.getAnnotations(target.identifier);
|
||||||
const filteredAnnotationsForSelection = allAnnotationsForTarget.filter(annotation => {
|
const filteredAnnotationsForSelection = allAnnotationsForTarget.filter(annotation => {
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
.c-inspect-annotations {
|
|
||||||
> * + * {
|
|
||||||
margin-top: $interiorMargin;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content{
|
|
||||||
> * + * {
|
|
||||||
margin-top: $interiorMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -150,16 +150,11 @@ export default {
|
|||||||
});
|
});
|
||||||
const selection =
|
const selection =
|
||||||
[
|
[
|
||||||
{
|
|
||||||
element: this.openmct.layout.$refs.browseObject.$el,
|
|
||||||
context: {
|
|
||||||
item: this.result
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
element: this.$el,
|
element: this.$el,
|
||||||
context: {
|
context: {
|
||||||
type: 'plot-points-selection',
|
item: this.result.targetModels[0],
|
||||||
|
type: 'plot-annotation-search-result',
|
||||||
targetDetails,
|
targetDetails,
|
||||||
targetDomainObjects,
|
targetDomainObjects,
|
||||||
annotations: [this.result],
|
annotations: [this.result],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user