mirror of
https://github.com/nasa/openmct.git
synced 2025-02-20 17:33:23 +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 }) => {
|
||||
await page.getByText('Annotations').click();
|
||||
// Expand sidebar
|
||||
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');
|
||||
|
||||
// Add three tags
|
||||
await page.hover(`button:has-text("Add Tag") >> nth=2`);
|
||||
await page.locator(`button:has-text("Add Tag") >> nth=2`).click();
|
||||
await page.hover(`button:has-text("Add Tag")`);
|
||||
await page.locator(`button:has-text("Add Tag")`).click();
|
||||
await page.locator('[placeholder="Type to select tag"]').click();
|
||||
await page.locator('[aria-label="Autocomplete Options"] >> text=Science').click();
|
||||
await page.waitForSelector('[aria-label="Tag"]:has-text("Science")');
|
||||
|
||||
await page.hover(`button:has-text("Add Tag") >> nth=2`);
|
||||
await page.locator(`button:has-text("Add Tag") >> nth=2`).click();
|
||||
await page.hover(`button:has-text("Add Tag")`);
|
||||
await page.locator(`button:has-text("Add Tag")`).click();
|
||||
await page.locator('[placeholder="Type to select tag"]').click();
|
||||
await page.locator('[aria-label="Autocomplete Options"] >> text=Drilling').click();
|
||||
await page.waitForSelector('[aria-label="Tag"]:has-text("Drilling")');
|
||||
|
||||
await page.hover(`button:has-text("Add Tag") >> nth=2`);
|
||||
await page.locator(`button:has-text("Add Tag") >> nth=2`).click();
|
||||
await page.hover(`button:has-text("Add Tag")`);
|
||||
await page.locator(`button:has-text("Add Tag")`).click();
|
||||
await page.locator('[placeholder="Type to select tag"]').click();
|
||||
await page.locator('[aria-label="Autocomplete Options"] >> text=Driving').click();
|
||||
await page.waitForSelector('[aria-label="Tag"]:has-text("Driving")');
|
||||
@ -231,6 +232,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
|
||||
type: 'issue',
|
||||
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('[aria-label="Notebook Entry Input"]').click();
|
||||
await page.locator('[aria-label="Notebook Entry Input"]').fill(`First Entry`);
|
||||
|
@ -381,7 +381,7 @@ export default {
|
||||
});
|
||||
},
|
||||
updateSelection(selection) {
|
||||
if (selection?.[0]?.[1]?.context?.targetDetails?.entryId === undefined) {
|
||||
if (selection?.[0]?.[0]?.context?.targetDetails?.entryId === undefined) {
|
||||
this.selectedEntryId = '';
|
||||
}
|
||||
},
|
||||
|
@ -472,16 +472,11 @@ export default {
|
||||
targetDomainObjects[keyString] = this.domainObject;
|
||||
this.openmct.selection.select(
|
||||
[
|
||||
{
|
||||
element: this.openmct.layout.$refs.browseObject.$el,
|
||||
context: {
|
||||
item: this.domainObject
|
||||
}
|
||||
},
|
||||
{
|
||||
element: event.currentTarget,
|
||||
context: {
|
||||
type: 'notebook-entry-selection',
|
||||
item: this.domainObject,
|
||||
targetDetails,
|
||||
targetDomainObjects,
|
||||
annotations: this.notebookAnnotations,
|
||||
|
@ -23,16 +23,8 @@
|
||||
<div
|
||||
v-if="loaded"
|
||||
class="gl-plot"
|
||||
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
||||
>
|
||||
<plot-legend
|
||||
v-if="!isNestedWithinAStackedPlot"
|
||||
:cursor-locked="!!lockHighlightPoint"
|
||||
:series="seriesModels"
|
||||
:highlights="highlights"
|
||||
:legend="legend"
|
||||
@legendHoverChanged="legendHoverChanged"
|
||||
/>
|
||||
<slot></slot>
|
||||
<div class="plot-wrapper-axis-and-display-area flex-elem grows">
|
||||
<div
|
||||
v-if="seriesModels.length"
|
||||
@ -94,7 +86,6 @@
|
||||
:highlights="highlights"
|
||||
:annotated-points="annotatedPoints"
|
||||
:annotation-selections="annotationSelections"
|
||||
:show-limit-line-labels="showLimitLineLabels"
|
||||
:hidden-y-axis-ids="hiddenYAxisIds"
|
||||
:annotation-viewing-and-editing-allowed="annotationViewingAndEditingAllowed"
|
||||
@plotReinitializeCanvas="initCanvas"
|
||||
@ -217,7 +208,6 @@ import LinearScale from "./LinearScale";
|
||||
import PlotConfigurationModel from './configuration/PlotConfigurationModel';
|
||||
import configStore from './configuration/ConfigStore';
|
||||
|
||||
import PlotLegend from "./legend/PlotLegend.vue";
|
||||
import MctTicks from "./MctTicks.vue";
|
||||
import MctChart from "./chart/MctChart.vue";
|
||||
import XAxis from "./axis/XAxis.vue";
|
||||
@ -232,7 +222,6 @@ export default {
|
||||
components: {
|
||||
XAxis,
|
||||
YAxis,
|
||||
PlotLegend,
|
||||
MctTicks,
|
||||
MctChart
|
||||
},
|
||||
@ -296,7 +285,6 @@ export default {
|
||||
isRealTime: this.openmct.time.clock() !== undefined,
|
||||
loaded: false,
|
||||
isTimeOutOfSync: false,
|
||||
showLimitLineLabels: this.limitLineLabels,
|
||||
isFrozenOnMouseDown: false,
|
||||
cursorGuide: this.initCursorGuide,
|
||||
gridLines: this.initGridLines,
|
||||
@ -334,23 +322,9 @@ export default {
|
||||
return this.config.xAxis.get('frozen') === true && this.config.yAxis.get('frozen') === true;
|
||||
},
|
||||
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;
|
||||
},
|
||||
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() {
|
||||
let leftTickWidth = 0;
|
||||
this.yAxes.forEach((yAxis) => {
|
||||
@ -365,12 +339,6 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
limitLineLabels: {
|
||||
handler(limitLineLabels) {
|
||||
this.legendHoverChanged(limitLineLabels);
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
initGridLines(newGridLines) {
|
||||
this.gridLines = newGridLines;
|
||||
},
|
||||
@ -406,8 +374,7 @@ export default {
|
||||
}));
|
||||
}
|
||||
|
||||
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
this.$emit('configLoaded', configId);
|
||||
this.$emit('configLoaded', true);
|
||||
|
||||
this.listenTo(this.config.series, 'add', this.addSeries, this);
|
||||
this.listenTo(this.config.series, 'remove', this.removeSeries, this);
|
||||
@ -439,15 +406,20 @@ export default {
|
||||
methods: {
|
||||
updateSelection(selection) {
|
||||
const selectionContext = selection?.[0]?.[0]?.context?.item;
|
||||
if (!selectionContext
|
||||
|| this.openmct.objects.areIdsEqual(selectionContext.identifier, this.domainObject.identifier)) {
|
||||
// Selection changed, but it's us, so ignoring it
|
||||
// on clicking on a search result we highlight the annotation and zoom - we know it's an annotation result when isAnnotationSearchResult === true
|
||||
// We shouldn't zoom when we're selecting existing annotations to view them or creating new annotations.
|
||||
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;
|
||||
}
|
||||
|
||||
const selectionType = selection?.[0]?.[1]?.context?.type;
|
||||
if (selectionType !== 'plot-points-selection') {
|
||||
// wrong type of selection
|
||||
if (selectionContext
|
||||
&& (!isAnnotationSearchResult)
|
||||
&& this.openmct.objects.areIdsEqual(selectionContext.identifier, this.domainObject.identifier)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -460,7 +432,18 @@ export default {
|
||||
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) {
|
||||
// just use first annotation
|
||||
const boundingBoxes = Object.values(selectedAnnotations[0].targets);
|
||||
@ -494,10 +477,9 @@ export default {
|
||||
min: minY,
|
||||
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.prepareExistingAnnotationSelection(selectedAnnotations);
|
||||
},
|
||||
handleKeyDown(event) {
|
||||
if (event.key === 'Alt') {
|
||||
@ -688,9 +670,15 @@ export default {
|
||||
series.reset();
|
||||
});
|
||||
},
|
||||
shareCommonParent(domainObjectToFind) {
|
||||
return false;
|
||||
},
|
||||
compositionPathContainsId(domainObjectToFind) {
|
||||
if (!domainObjectToFind.composition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
compositionPathContainsId(domainObjectToClear) {
|
||||
return domainObjectToClear.composition.some((compositionIdentifier) => {
|
||||
return domainObjectToFind.composition.some((compositionIdentifier) => {
|
||||
return this.openmct.objects.areIdsEqual(compositionIdentifier, this.domainObject.identifier);
|
||||
});
|
||||
},
|
||||
@ -1044,8 +1032,6 @@ export default {
|
||||
|
||||
highlightValues(point) {
|
||||
this.highlightPoint = point;
|
||||
// TODO: used in StackedPlotController
|
||||
this.$emit('plotHighlightUpdate', point);
|
||||
if (this.lockHighlightPoint) {
|
||||
return;
|
||||
}
|
||||
@ -1157,7 +1143,7 @@ export default {
|
||||
endPixels: this.positionOverElement,
|
||||
start: this.positionOverPlot,
|
||||
end: this.positionOverPlot,
|
||||
color: [1, 1, 1, 0.5]
|
||||
color: [1, 1, 1, 0.25]
|
||||
};
|
||||
if (annotationEvent) {
|
||||
this.marquee.annotationEvent = true;
|
||||
@ -1168,13 +1154,21 @@ export default {
|
||||
}
|
||||
},
|
||||
selectNearbyAnnotations(event) {
|
||||
// need to stop propagation right away to prevent selecting the plot itself
|
||||
event.stopPropagation();
|
||||
|
||||
if (!this.annotationViewingAndEditingAllowed || this.annotationSelections.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
this.selectPlotAnnotations({
|
||||
targetDetails,
|
||||
@ -1182,33 +1176,50 @@ export default {
|
||||
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}) {
|
||||
const selection =
|
||||
[
|
||||
{
|
||||
element: this.openmct.layout.$refs.browseObject.$el,
|
||||
context: {
|
||||
item: this.domainObject
|
||||
}
|
||||
},
|
||||
{
|
||||
element: this.$el,
|
||||
context: {
|
||||
type: 'plot-points-selection',
|
||||
targetDetails,
|
||||
targetDomainObjects,
|
||||
annotations,
|
||||
annotationType: this.openmct.annotation.ANNOTATION_TYPES.PLOT_SPATIAL,
|
||||
onAnnotationChange: this.onAnnotationChange
|
||||
}
|
||||
}
|
||||
];
|
||||
const annotationContext = {
|
||||
type: 'clicked-on-plot-selection',
|
||||
targetDetails,
|
||||
targetDomainObjects,
|
||||
annotations,
|
||||
annotationType: this.openmct.annotation.ANNOTATION_TYPES.PLOT_SPATIAL,
|
||||
onAnnotationChange: this.onAnnotationChange
|
||||
};
|
||||
const selection = this.createPathSelection();
|
||||
if (selection.length && this.openmct.objects.areIdsEqual(selection[0].context.item.identifier, this.domainObject.identifier)) {
|
||||
selection[0].context = {
|
||||
...selection[0].context,
|
||||
...annotationContext
|
||||
};
|
||||
} else {
|
||||
selection.unshift({
|
||||
element: this.$el,
|
||||
context: {
|
||||
item: this.domainObject,
|
||||
...annotationContext
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.openmct.selection.select(selection, true);
|
||||
},
|
||||
selectNewPlotAnnotations(boundingBoxPerYAxis, pointsInBox, event) {
|
||||
let targetDomainObjects = {};
|
||||
let targetDetails = {};
|
||||
let annotations = {};
|
||||
let annotations = [];
|
||||
pointsInBox.forEach(pointInBox => {
|
||||
if (pointInBox.length) {
|
||||
const seriesID = pointInBox[0].series.keyString;
|
||||
@ -1752,9 +1763,6 @@ export default {
|
||||
this.config.series.models.forEach(this.loadSeriesData, this);
|
||||
}
|
||||
},
|
||||
legendHoverChanged(data) {
|
||||
this.showLimitLineLabels = data;
|
||||
},
|
||||
toggleCursorGuide() {
|
||||
this.cursorGuide = !this.cursorGuide;
|
||||
this.$emit('cursorGuide', this.cursorGuide);
|
||||
|
@ -36,12 +36,26 @@
|
||||
:model="{progressPerc: undefined}"
|
||||
/>
|
||||
<mct-plot
|
||||
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
||||
:init-grid-lines="gridLines"
|
||||
:init-cursor-guide="cursorGuide"
|
||||
:options="options"
|
||||
:limit-line-labels="limitLineLabels"
|
||||
@loadingUpdated="loadingUpdated"
|
||||
@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>
|
||||
</template>
|
||||
@ -50,13 +64,15 @@
|
||||
import eventHelpers from './lib/eventHelpers';
|
||||
import ImageExporter from '../../exporters/ImageExporter';
|
||||
import MctPlot from './MctPlot.vue';
|
||||
import PlotLegend from "./legend/PlotLegend.vue";
|
||||
import ProgressBar from "../../ui/components/ProgressBar.vue";
|
||||
import StalenessUtils from '@/utils/staleness';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MctPlot,
|
||||
ProgressBar
|
||||
ProgressBar,
|
||||
PlotLegend
|
||||
},
|
||||
inject: ['openmct', 'domainObject', 'path'],
|
||||
props: {
|
||||
@ -77,7 +93,13 @@ export default {
|
||||
gridLines: !this.options.compact,
|
||||
loading: false,
|
||||
status: '',
|
||||
staleObjects: []
|
||||
staleObjects: [],
|
||||
limitLineLabels: undefined,
|
||||
lockHighlightPoint: false,
|
||||
highlights: [],
|
||||
expanded: false,
|
||||
position: undefined,
|
||||
configReady: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -87,6 +109,16 @@ export default {
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
plotLegendPositionClass() {
|
||||
return this.position ? `plot-legend-${this.position}` : '';
|
||||
},
|
||||
plotLegendExpandedStateClass() {
|
||||
if (this.expanded) {
|
||||
return 'plot-legend-expanded';
|
||||
} else {
|
||||
return 'plot-legend-collapsed';
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -183,6 +215,24 @@ export default {
|
||||
exportPNG: this.exportPNG,
|
||||
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:color', this.updateSeriesColors.bind(this, series), this);
|
||||
},
|
||||
removeSeries(plotSeries) {
|
||||
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');
|
||||
});
|
||||
this.singleSeries = this.seriesModels.length === 1;
|
||||
this.updateSeriesColors();
|
||||
},
|
||||
updateSeriesColors() {
|
||||
this.seriesColors = this.seriesModels.map(model => {
|
||||
return model.get('color').asHexString();
|
||||
});
|
||||
|
@ -533,7 +533,6 @@ export default {
|
||||
},
|
||||
updateLimitsAndDraw() {
|
||||
this.drawLimitLines();
|
||||
this.scheduleDraw();
|
||||
},
|
||||
scheduleDraw() {
|
||||
if (!this.drawScheduled) {
|
||||
|
@ -67,6 +67,10 @@ export default class SeriesCollection extends Collection {
|
||||
}, this);
|
||||
}
|
||||
watchTelemetryContainer(domainObject) {
|
||||
if (domainObject.type === 'telemetry.plot.stacked') {
|
||||
return;
|
||||
}
|
||||
|
||||
const composition = this.openmct.composition.get(domainObject);
|
||||
this.listenTo(composition, 'add', this.addTelemetryObject, this);
|
||||
this.listenTo(composition, 'remove', this.removeTelemetryObject, this);
|
||||
|
@ -93,7 +93,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
v-if="plotSeries.length && (isStackedPlotObject || !isNestedWithinAStackedPlot)"
|
||||
v-if="isStackedPlotObject || !isNestedWithinAStackedPlot"
|
||||
class="grid-properties"
|
||||
>
|
||||
<ul
|
||||
@ -190,10 +190,13 @@ export default {
|
||||
mounted() {
|
||||
eventHelpers.extend(this);
|
||||
this.config = this.getConfig();
|
||||
this.initYAxesConfiguration();
|
||||
if (!this.isStackedPlotObject) {
|
||||
this.initYAxesConfiguration();
|
||||
this.registerListeners();
|
||||
} else {
|
||||
this.initLegendConfiguration();
|
||||
}
|
||||
|
||||
this.registerListeners();
|
||||
this.initLegendConfiguration();
|
||||
this.loaded = true;
|
||||
|
||||
},
|
||||
@ -245,9 +248,9 @@ export default {
|
||||
}
|
||||
},
|
||||
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() {
|
||||
if (this.config) {
|
||||
|
@ -53,7 +53,6 @@
|
||||
>
|
||||
<h2 title="Legend options">Legend</h2>
|
||||
<legend-form
|
||||
v-if="plotSeries.length"
|
||||
class="grid-properties"
|
||||
:legend="config.legend"
|
||||
/>
|
||||
@ -97,20 +96,23 @@ export default {
|
||||
mounted() {
|
||||
eventHelpers.extend(this);
|
||||
this.config = this.getConfig();
|
||||
this.yAxes = [{
|
||||
id: this.config.yAxis.id,
|
||||
seriesCount: 0
|
||||
}];
|
||||
if (this.config.additionalYAxes) {
|
||||
this.yAxes = this.yAxes.concat(this.config.additionalYAxes.map(yAxis => {
|
||||
return {
|
||||
id: yAxis.id,
|
||||
seriesCount: 0
|
||||
};
|
||||
}));
|
||||
if (!this.isStackedPlotObject) {
|
||||
this.yAxes = [{
|
||||
id: this.config.yAxis.id,
|
||||
seriesCount: 0
|
||||
}];
|
||||
if (this.config.additionalYAxes) {
|
||||
this.yAxes = this.yAxes.concat(this.config.additionalYAxes.map(yAxis => {
|
||||
return {
|
||||
id: yAxis.id,
|
||||
seriesCount: 0
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
this.registerListeners();
|
||||
this.loaded = true;
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
@ -12,11 +12,12 @@ export default function PlotsInspectorViewProvider(openmct) {
|
||||
}
|
||||
|
||||
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 isStackedPlotObject = object && object.type === 'telemetry.plot.stacked';
|
||||
const isParentStackedPlotObject = parent && parent.type === 'telemetry.plot.stacked';
|
||||
|
||||
return isStackedPlotObject || isOverlayPlotObject;
|
||||
return isOverlayPlotObject || isParentStackedPlotObject;
|
||||
},
|
||||
view: function (selection) {
|
||||
let component;
|
||||
|
@ -12,12 +12,10 @@ export default function StackedPlotsInspectorViewProvider(openmct) {
|
||||
}
|
||||
|
||||
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 isParentStackedPlotObject = parent && parent.type === 'telemetry.plot.stacked';
|
||||
const isStackedPlotObject = object && object.type === 'telemetry.plot.stacked';
|
||||
|
||||
return !isOverlayPlotObject && isParentStackedPlotObject;
|
||||
return isStackedPlotObject;
|
||||
},
|
||||
view: function (selection) {
|
||||
let component;
|
||||
|
@ -49,10 +49,10 @@
|
||||
title="Cursor is point locked. Click anywhere in the plot to unlock."
|
||||
></div>
|
||||
<plot-legend-item-collapsed
|
||||
v-for="(seriesObject, seriesIndex) in series"
|
||||
:key="`${seriesObject.keyString}-${seriesIndex}`"
|
||||
v-for="(seriesObject, seriesIndex) in seriesModels"
|
||||
:key="`${seriesObject.keyString}-${seriesIndex}-collapsed`"
|
||||
:highlights="highlights"
|
||||
:value-to-show-when-collapsed="legend.get('valueToShowWhenCollapsed')"
|
||||
:value-to-show-when-collapsed="valueToShowWhenCollapsed"
|
||||
:series-object="seriesObject"
|
||||
@legendHoverChanged="legendHoverChanged"
|
||||
/>
|
||||
@ -95,11 +95,10 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<plot-legend-item-expanded
|
||||
v-for="(seriesObject, seriesIndex) in series"
|
||||
v-for="(seriesObject, seriesIndex) in seriesModels"
|
||||
:key="`${seriesObject.keyString}-${seriesIndex}-expanded`"
|
||||
:series-object="seriesObject"
|
||||
:highlights="highlights"
|
||||
:legend="legend"
|
||||
@legendHoverChanged="legendHoverChanged"
|
||||
/>
|
||||
</tbody>
|
||||
@ -111,6 +110,9 @@
|
||||
<script>
|
||||
import PlotLegendItemCollapsed from "./PlotLegendItemCollapsed.vue";
|
||||
import PlotLegendItemExpanded from "./PlotLegendItemExpanded.vue";
|
||||
import configStore from "../configuration/ConfigStore";
|
||||
import eventHelpers from "../lib/eventHelpers";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PlotLegendItemExpanded,
|
||||
@ -124,57 +126,113 @@ export default {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
series: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
highlights: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLegendExpanded: this.legend.get('expanded') === true
|
||||
isLegendExpanded: false,
|
||||
seriesModels: [],
|
||||
loaded: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
showUnitsWhenExpanded() {
|
||||
return this.legend.get('showUnitsWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showUnitsWhenExpanded') === true;
|
||||
},
|
||||
showMinimumWhenExpanded() {
|
||||
return this.legend.get('showMinimumWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showMinimumWhenExpanded') === true;
|
||||
},
|
||||
showMaximumWhenExpanded() {
|
||||
return this.legend.get('showMaximumWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showMaximumWhenExpanded') === true;
|
||||
},
|
||||
showValueWhenExpanded() {
|
||||
return this.legend.get('showValueWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showValueWhenExpanded') === true;
|
||||
},
|
||||
showTimestampWhenExpanded() {
|
||||
return this.legend.get('showTimestampWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showTimestampWhenExpanded') === true;
|
||||
},
|
||||
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: {
|
||||
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() {
|
||||
this.isLegendExpanded = !this.isLegendExpanded;
|
||||
this.legend.set('expanded', this.isLegendExpanded);
|
||||
this.$emit('expanded', this.isLegendExpanded);
|
||||
},
|
||||
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 eventHelpers from "../lib/eventHelpers";
|
||||
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
||||
import configStore from "../configuration/ConfigStore";
|
||||
|
||||
export default {
|
||||
mixins: [stalenessMixin],
|
||||
inject: ['openmct', 'domainObject'],
|
||||
props: {
|
||||
valueToShowWhenCollapsed: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
seriesObject: {
|
||||
type: Object,
|
||||
required: true,
|
||||
@ -88,10 +85,14 @@ export default {
|
||||
formattedYValue: '',
|
||||
formattedXValue: '',
|
||||
mctLimitStateClass: '',
|
||||
formattedYValueFromStats: ''
|
||||
formattedYValueFromStats: '',
|
||||
loaded: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
valueToShowWhenCollapsed() {
|
||||
return this.loaded ? this.legend.get('valueToShowWhenCollapsed') : [];
|
||||
},
|
||||
valueToDisplayWhenCollapsedClass() {
|
||||
return `value-to-display-${ this.valueToShowWhenCollapsed }`;
|
||||
},
|
||||
@ -109,6 +110,9 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
eventHelpers.extend(this);
|
||||
this.config = this.getConfig();
|
||||
this.legend = this.config.legend;
|
||||
this.loaded = true;
|
||||
this.listenTo(this.seriesObject, 'change:color', (newColor) => {
|
||||
this.updateColor(newColor);
|
||||
}, this);
|
||||
@ -122,8 +126,13 @@ export default {
|
||||
this.stopListening();
|
||||
},
|
||||
methods: {
|
||||
getConfig() {
|
||||
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
|
||||
return configStore.get(configId);
|
||||
},
|
||||
initialize(highlightedObject) {
|
||||
const seriesObject = highlightedObject ? highlightedObject.series : this.seriesObject;
|
||||
const seriesObject = highlightedObject?.series || this.seriesObject;
|
||||
|
||||
this.isMissing = seriesObject.domainObject.status === 'missing';
|
||||
this.colorAsHexString = seriesObject.get('color').asHexString();
|
||||
|
@ -83,6 +83,7 @@
|
||||
import {getLimitClass} from "@/plugins/plot/chart/limitUtil";
|
||||
import eventHelpers from "@/plugins/plot/lib/eventHelpers";
|
||||
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
||||
import configStore from "../configuration/ConfigStore";
|
||||
|
||||
export default {
|
||||
mixins: [stalenessMixin],
|
||||
@ -100,10 +101,6 @@ export default {
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -116,24 +113,25 @@ export default {
|
||||
formattedXValue: '',
|
||||
formattedMinY: '',
|
||||
formattedMaxY: '',
|
||||
mctLimitStateClass: ''
|
||||
mctLimitStateClass: '',
|
||||
loaded: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
showUnitsWhenExpanded() {
|
||||
return this.legend.get('showUnitsWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showUnitsWhenExpanded') === true;
|
||||
},
|
||||
showMinimumWhenExpanded() {
|
||||
return this.legend.get('showMinimumWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showMinimumWhenExpanded') === true;
|
||||
},
|
||||
showMaximumWhenExpanded() {
|
||||
return this.legend.get('showMaximumWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showMaximumWhenExpanded') === true;
|
||||
},
|
||||
showValueWhenExpanded() {
|
||||
return this.legend.get('showValueWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showValueWhenExpanded') === true;
|
||||
},
|
||||
showTimestampWhenExpanded() {
|
||||
return this.legend.get('showTimestampWhenExpanded') === true;
|
||||
return this.loaded && this.legend.get('showTimestampWhenExpanded') === true;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -146,6 +144,9 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
eventHelpers.extend(this);
|
||||
this.config = this.getConfig();
|
||||
this.legend = this.config.legend;
|
||||
this.loaded = true;
|
||||
this.listenTo(this.seriesObject, 'change:color', (newColor) => {
|
||||
this.updateColor(newColor);
|
||||
}, this);
|
||||
@ -159,8 +160,13 @@ export default {
|
||||
this.stopListening();
|
||||
},
|
||||
methods: {
|
||||
getConfig() {
|
||||
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
|
||||
return configStore.get(configId);
|
||||
},
|
||||
initialize(highlightedObject) {
|
||||
const seriesObject = highlightedObject ? highlightedObject.series : this.seriesObject;
|
||||
const seriesObject = highlightedObject?.series || this.seriesObject;
|
||||
|
||||
this.isMissing = seriesObject.domainObject.status === 'missing';
|
||||
this.colorAsHexString = seriesObject.get('color').asHexString();
|
||||
|
@ -27,13 +27,16 @@
|
||||
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
|
||||
>
|
||||
<plot-legend
|
||||
v-if="compositionObjectsConfigLoaded"
|
||||
:cursor-locked="!!lockHighlightPoint"
|
||||
:series="seriesModels"
|
||||
:highlights="highlights"
|
||||
:legend="legend"
|
||||
@legendHoverChanged="legendHoverChanged"
|
||||
@expanded="updateExpanded"
|
||||
@position="updatePosition"
|
||||
/>
|
||||
<div class="l-view-section">
|
||||
<div
|
||||
class="l-view-section"
|
||||
>
|
||||
<stacked-plot-item
|
||||
v-for="objectWrapper in compositionObjects"
|
||||
:key="objectWrapper.keyString"
|
||||
@ -51,7 +54,7 @@
|
||||
@gridLines="onGridLinesChange"
|
||||
@lockHighlightPoint="lockHighlightPointUpdated"
|
||||
@highlights="highlightsUpdated"
|
||||
@configLoaded="registerSeriesListeners"
|
||||
@configLoaded="configLoadedForObject(objectWrapper.keyString)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -66,14 +69,13 @@ import ColorPalette from "@/ui/color/ColorPalette";
|
||||
import PlotLegend from "../legend/PlotLegend.vue";
|
||||
import StackedPlotItem from './StackedPlotItem.vue';
|
||||
import ImageExporter from '../../../exporters/ImageExporter';
|
||||
import eventHelpers from "@/plugins/plot/lib/eventHelpers";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
StackedPlotItem,
|
||||
PlotLegend
|
||||
},
|
||||
inject: ['openmct', 'domainObject', 'composition', 'path'],
|
||||
inject: ['openmct', 'domainObject', 'path'],
|
||||
props: {
|
||||
options: {
|
||||
type: Object,
|
||||
@ -87,24 +89,25 @@ export default {
|
||||
hideExportButtons: false,
|
||||
cursorGuide: false,
|
||||
gridLines: true,
|
||||
loading: false,
|
||||
configLoaded: {},
|
||||
compositionObjects: [],
|
||||
tickWidthMap: {},
|
||||
legend: {},
|
||||
loaded: false,
|
||||
lockHighlightPoint: false,
|
||||
highlights: [],
|
||||
seriesModels: [],
|
||||
showLimitLineLabels: undefined,
|
||||
colorPalette: new ColorPalette()
|
||||
colorPalette: new ColorPalette(),
|
||||
compositionObjectsConfigLoaded: false,
|
||||
position: 'top',
|
||||
expanded: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
plotLegendPositionClass() {
|
||||
return `plot-legend-${this.config.legend.get('position')}`;
|
||||
return `plot-legend-${this.position}`;
|
||||
},
|
||||
plotLegendExpandedStateClass() {
|
||||
if (this.config.legend.get('expanded')) {
|
||||
if (this.expanded) {
|
||||
return 'plot-legend-expanded';
|
||||
} else {
|
||||
return 'plot-legend-collapsed';
|
||||
@ -118,17 +121,14 @@ export default {
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
eventHelpers.extend(this);
|
||||
this.seriesConfig = {};
|
||||
|
||||
//We only need to initialize the stacked plot config for legend properties
|
||||
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
this.config = this.getConfig(configId);
|
||||
|
||||
this.legend = this.config.legend;
|
||||
|
||||
this.loaded = true;
|
||||
this.imageExporter = new ImageExporter(this.openmct);
|
||||
|
||||
this.composition = this.openmct.composition.get(this.domainObject);
|
||||
this.composition.on('add', this.addChild);
|
||||
this.composition.on('remove', this.removeChild);
|
||||
this.composition.on('reorder', this.compositionReorder);
|
||||
@ -142,7 +142,6 @@ export default {
|
||||
id: configId,
|
||||
domainObject: this.domainObject,
|
||||
openmct: this.openmct,
|
||||
palette: this.colorPalette,
|
||||
callback: (data) => {
|
||||
this.data = data;
|
||||
}
|
||||
@ -155,10 +154,19 @@ export default {
|
||||
loadingUpdated(loaded) {
|
||||
this.loading = loaded;
|
||||
},
|
||||
destroy() {
|
||||
this.stopListening();
|
||||
configStore.deleteStore(this.config.id);
|
||||
configLoadedForObject(childObjIdentifier) {
|
||||
const childObjId = this.openmct.objects.makeKeyString(childObjIdentifier);
|
||||
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('remove', this.removeChild);
|
||||
this.composition.off('reorder', this.compositionReorder);
|
||||
@ -173,6 +181,7 @@ export default {
|
||||
object: child,
|
||||
keyString: id
|
||||
});
|
||||
this.setConfigLoadedForComposition();
|
||||
},
|
||||
|
||||
removeChild(childIdentifier) {
|
||||
@ -180,23 +189,36 @@ export default {
|
||||
|
||||
this.$delete(this.tickWidthMap, id);
|
||||
|
||||
const configIndex = this.domainObject.configuration.series.findIndex((seriesConfig) => {
|
||||
return this.openmct.objects.areIdsEqual(seriesConfig.identifier, childIdentifier);
|
||||
});
|
||||
const childObj = this.compositionObjects.filter((c) => {
|
||||
const identifier = c.keyString;
|
||||
|
||||
if (configIndex > -1) {
|
||||
this.domainObject.configuration.series.splice(configIndex, 1);
|
||||
return identifier === id;
|
||||
})[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) => {
|
||||
const identifier = c.keyString;
|
||||
|
||||
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) {
|
||||
@ -245,39 +267,18 @@ export default {
|
||||
lockHighlightPointUpdated(data) {
|
||||
this.lockHighlightPoint = data;
|
||||
},
|
||||
updateExpanded(expanded) {
|
||||
this.expanded = expanded;
|
||||
},
|
||||
updatePosition(position) {
|
||||
this.position = position;
|
||||
},
|
||||
updateReady(ready) {
|
||||
this.configReady = ready;
|
||||
},
|
||||
highlightsUpdated(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) {
|
||||
this.cursorGuide = cursorGuide === true;
|
||||
},
|
||||
|
@ -100,10 +100,6 @@ export default {
|
||||
this.updateView();
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.removeSelectable) {
|
||||
this.removeSelectable();
|
||||
}
|
||||
|
||||
if (this.component) {
|
||||
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>'
|
||||
});
|
||||
|
||||
this.setSelection();
|
||||
},
|
||||
onLockHighlightPointUpdated() {
|
||||
this.$emit('lockHighlightPoint', ...arguments);
|
||||
@ -205,17 +199,6 @@ export default {
|
||||
this.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() {
|
||||
return {
|
||||
limitLineLabels: this.showLimitLineLabels,
|
||||
@ -230,7 +213,7 @@ export default {
|
||||
},
|
||||
getPlotObject() {
|
||||
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;
|
||||
} else {
|
||||
//If object is missing, warn and return object
|
||||
|
@ -57,7 +57,6 @@ export default function StackedPlotViewProvider(openmct) {
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject,
|
||||
composition: openmct.composition.get(domainObject),
|
||||
path: objectPath
|
||||
},
|
||||
data() {
|
||||
|
@ -173,7 +173,7 @@ describe("the plugin", function () {
|
||||
let testTelemetryObject2;
|
||||
let config;
|
||||
let component;
|
||||
let mockComposition;
|
||||
let mockCompositionList = [];
|
||||
let plotViewComponentObject;
|
||||
|
||||
afterAll(() => {
|
||||
@ -271,14 +271,34 @@ describe("the plugin", function () {
|
||||
}
|
||||
};
|
||||
|
||||
mockComposition = new EventEmitter();
|
||||
mockComposition.load = () => {
|
||||
mockComposition.emit('add', testTelemetryObject);
|
||||
stackedPlotObject.composition = [{
|
||||
identifier: testTelemetryObject.identifier
|
||||
}];
|
||||
|
||||
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");
|
||||
child.append(viewContainer);
|
||||
@ -290,7 +310,6 @@ describe("the plugin", function () {
|
||||
provide: {
|
||||
openmct: openmct,
|
||||
domainObject: stackedPlotObject,
|
||||
composition: openmct.composition.get(stackedPlotObject),
|
||||
path: [stackedPlotObject]
|
||||
},
|
||||
template: "<stacked-plot></stacked-plot>"
|
||||
@ -321,7 +340,7 @@ describe("the plugin", function () {
|
||||
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");
|
||||
expect(xAxisElement.length).toBe(1);
|
||||
|
||||
@ -329,13 +348,8 @@ describe("the plugin", function () {
|
||||
min: 0,
|
||||
max: 4
|
||||
});
|
||||
|
||||
Vue.nextTick(() => {
|
||||
let ticks = xAxisElement[0].querySelectorAll(".gl-plot-tick");
|
||||
expect(ticks.length).toBe(9);
|
||||
|
||||
done();
|
||||
});
|
||||
let ticks = xAxisElement[0].querySelectorAll(".gl-plot-tick");
|
||||
expect(ticks.length).toBe(9);
|
||||
});
|
||||
|
||||
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) => {
|
||||
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(() => {
|
||||
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('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(() => {
|
||||
expect(plotViewComponentObject.compositionObjects.length).toBe(0);
|
||||
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) => {
|
||||
let originalLength = config.series.models[0].getSeriesData().length;
|
||||
config.series.models[0].add({
|
||||
@ -459,7 +468,7 @@ describe("the plugin", function () {
|
||||
max: 10
|
||||
});
|
||||
Vue.nextTick(() => {
|
||||
expect(plotViewComponentObject.$children[1].component.$children[1].xScale.domain()).toEqual({
|
||||
expect(plotViewComponentObject.$children[0].component.$children[1].xScale.domain()).toEqual({
|
||||
min: 0,
|
||||
max: 10
|
||||
});
|
||||
@ -476,7 +485,7 @@ describe("the plugin", function () {
|
||||
});
|
||||
});
|
||||
Vue.nextTick(() => {
|
||||
const yAxesScales = plotViewComponentObject.$children[1].component.$children[1].yScale;
|
||||
const yAxesScales = plotViewComponentObject.$children[0].component.$children[1].yScale;
|
||||
yAxesScales.forEach((yAxisScale) => {
|
||||
expect(yAxisScale.scale.domain()).toEqual({
|
||||
min: 10,
|
||||
|
@ -42,7 +42,6 @@
|
||||
@import "../ui/inspector/elements.scss";
|
||||
@import "../ui/inspector/inspector.scss";
|
||||
@import "../ui/inspector/location.scss";
|
||||
@import "../ui/inspector/annotations/annotation-inspector.scss";
|
||||
@import "../ui/layout/app-logo.scss";
|
||||
@import "../ui/layout/create-button.scss";
|
||||
@import "../ui/layout/layout.scss";
|
||||
|
@ -145,7 +145,7 @@ export default {
|
||||
|
||||
this.unlistenComposition();
|
||||
|
||||
if (this.parentObject) {
|
||||
if (this.parentObject && this.parentObject.type === 'telemetry.plot.overlay') {
|
||||
this.setYAxisIds();
|
||||
this.composition = this.openmct.composition.get(this.parentObject);
|
||||
|
||||
@ -175,6 +175,7 @@ export default {
|
||||
setYAxisIds() {
|
||||
const configId = this.openmct.objects.makeKeyString(this.parentObject.identifier);
|
||||
this.config = configStore.get(configId);
|
||||
this.yAxes = [];
|
||||
this.yAxes.push({
|
||||
id: this.config.yAxis.id,
|
||||
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;
|
||||
},
|
||||
targetDetails() {
|
||||
return this?.selection?.[0]?.[1]?.context?.targetDetails ?? {};
|
||||
return this?.selection?.[0]?.[0]?.context?.targetDetails ?? {};
|
||||
},
|
||||
shouldShowTagsEditor() {
|
||||
return Object.keys(this.targetDetails).length > 0;
|
||||
const showingTagsEditor = Object.keys(this.targetDetails).length > 0;
|
||||
|
||||
if (showingTagsEditor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
targetDomainObjects() {
|
||||
return this?.selection?.[0]?.[1]?.context?.targetDomainObjects ?? {};
|
||||
return this?.selection?.[0]?.[0]?.context?.targetDomainObjects ?? {};
|
||||
},
|
||||
selectedAnnotations() {
|
||||
return this?.selection?.[0]?.[1]?.context?.annotations;
|
||||
return this?.selection?.[0]?.[0]?.context?.annotations;
|
||||
},
|
||||
annotationType() {
|
||||
return this?.selection?.[0]?.[1]?.context?.annotationType;
|
||||
return this?.selection?.[0]?.[0]?.context?.annotationType;
|
||||
},
|
||||
annotationFilter() {
|
||||
return this?.selection?.[0]?.[1]?.context?.annotationFilter;
|
||||
return this?.selection?.[0]?.[0]?.context?.annotationFilter;
|
||||
},
|
||||
onAnnotationChange() {
|
||||
return this?.selection?.[0]?.[1]?.context?.onAnnotationChange;
|
||||
return this?.selection?.[0]?.[0]?.context?.onAnnotationChange;
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
@ -195,6 +201,7 @@ export default {
|
||||
}
|
||||
},
|
||||
async loadAnnotationForTargetObject(target) {
|
||||
console.debug(`📝 Loading annotations for target`, target);
|
||||
const targetID = this.openmct.objects.makeKeyString(target.identifier);
|
||||
const allAnnotationsForTarget = await this.openmct.annotation.getAnnotations(target.identifier);
|
||||
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 =
|
||||
[
|
||||
{
|
||||
element: this.openmct.layout.$refs.browseObject.$el,
|
||||
context: {
|
||||
item: this.result
|
||||
}
|
||||
},
|
||||
{
|
||||
element: this.$el,
|
||||
context: {
|
||||
type: 'plot-points-selection',
|
||||
item: this.result.targetModels[0],
|
||||
type: 'plot-annotation-search-result',
|
||||
targetDetails,
|
||||
targetDomainObjects,
|
||||
annotations: [this.result],
|
||||
|
Loading…
x
Reference in New Issue
Block a user