diff --git a/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js b/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js
index 1c9c8d968ad..6f0745e34fb 100644
--- a/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js
+++ b/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js
@@ -189,6 +189,57 @@ test.describe('Overlay Plot', () => {
await assertLimitLinesExistAndAreVisible(page);
});
+ test('Limit lines adjust when series is resized', async ({ page }) => {
+ test.info().annotations.push({
+ type: 'issue',
+ description: 'https://github.com/nasa/openmct/issues/6987'
+ });
+ // Create an Overlay Plot with a default SWG
+ overlayPlot = await createDomainObjectWithDefaults(page, {
+ type: 'Overlay Plot'
+ });
+
+ await createDomainObjectWithDefaults(page, {
+ type: 'Sine Wave Generator',
+ parent: overlayPlot.uuid
+ });
+
+ await page.goto(overlayPlot.url);
+
+ // Assert that no limit lines are shown by default
+ await page.waitForSelector('.js-limit-area', { state: 'attached' });
+ expect(await page.locator('.c-plot-limit-line').count()).toBe(0);
+
+ // Enter edit mode
+ await page.getByLabel('Edit Object').click();
+
+ // Expand the "Sine Wave Generator" plot series options and enable limit lines
+ await page.getByRole('tab', { name: 'Config' }).click();
+ await page
+ .getByRole('list', { name: 'Plot Series Properties' })
+ .locator('span')
+ .first()
+ .click();
+ await page
+ .getByRole('list', { name: 'Plot Series Properties' })
+ .getByRole('checkbox', { name: 'Limit lines' })
+ .check();
+
+ await assertLimitLinesExistAndAreVisible(page);
+
+ // Save (exit edit mode)
+ await page.locator('button[title="Save"]').click();
+ await page.locator('li[title="Save and Finish Editing"]').click();
+
+ const initialCoords = await assertLimitLinesExistAndAreVisible(page);
+ // Resize the chart container by showing the snapshot pane.
+ await page.getByLabel('Show Snapshots').click();
+
+ const newCoords = await assertLimitLinesExistAndAreVisible(page);
+ // We just need to know that the first limit line redrew somewhere lower than the initial y position.
+ expect(newCoords.y).toBeGreaterThan(initialCoords.y);
+ });
+
test('The elements pool supports dragging series into multiple y-axis buckets', async ({
page
}) => {
@@ -337,4 +388,7 @@ async function assertLimitLinesExistAndAreVisible(page) {
for (let i = 0; i < limitLineCount; i++) {
await expect(page.locator('.c-plot-limit-line').nth(i)).toBeVisible();
}
+
+ const firstLimitLineCoords = await page.locator('.c-plot-limit-line').first().boundingBox();
+ return firstLimitLineCoords;
}
diff --git a/src/plugins/plot/PlotView.vue b/src/plugins/plot/PlotView.vue
index 59bc23a66d3..a83d81a3f37 100644
--- a/src/plugins/plot/PlotView.vue
+++ b/src/plugins/plot/PlotView.vue
@@ -201,10 +201,15 @@ export default {
if (this.compositionCollection) {
this.compositionCollection.on('add', this.subscribeToStaleness);
- this.compositionCollection.on('remove', this.triggerUnsubscribeFromStaleness);
+ this.compositionCollection.on('remove', this.removeSubscription);
this.compositionCollection.load();
}
},
+ removeSubscription(identifier) {
+ this.triggerUnsubscribeFromStaleness({
+ identifier
+ });
+ },
loadingUpdated(loading) {
this.loading = loading;
this.$emit('loading-updated', ...arguments);
@@ -212,7 +217,7 @@ export default {
destroy() {
if (this.compositionCollection) {
this.compositionCollection.off('add', this.subscribeToStaleness);
- this.compositionCollection.off('remove', this.triggerUnsubscribeFromStaleness);
+ this.compositionCollection.off('remove', this.removeSubscription);
}
this.imageExporter = null;
diff --git a/src/plugins/plot/chart/MctChart.vue b/src/plugins/plot/chart/MctChart.vue
index 31a7518d4f2..3af51ac03c4 100644
--- a/src/plugins/plot/chart/MctChart.vue
+++ b/src/plugins/plot/chart/MctChart.vue
@@ -39,13 +39,13 @@
@@ -201,9 +201,8 @@ export default {
handler() {
this.hiddenYAxisIds.forEach((id) => {
this.resetYOffsetAndSeriesDataForYAxis(id);
- this.updateLimitLines();
});
- this.scheduleDraw();
+ this.scheduleDraw(true);
},
deep: true
}
@@ -271,12 +270,19 @@ export default {
this.listenTo(this.config.xAxis, 'change', this.redrawIfNotAlreadyHandled);
this.config.series.forEach(this.onSeriesAdd, this);
this.$emit('chart-loaded');
+
+ this.handleWindowResize = _.debounce(this.handleWindowResize, 250);
+ this.chartResizeObserver = new ResizeObserver(this.handleWindowResize);
+ this.chartResizeObserver.observe(this.$parent.$refs.chartContainer);
},
beforeUnmount() {
this.destroy();
this.visibilityObserver.unobserve(this.chartContainer);
},
methods: {
+ handleWindowResize() {
+ this.scheduleDraw(true);
+ },
getConfig() {
const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier);
let config = configStore.get(configId);
@@ -445,7 +451,6 @@ export default {
this.makeLimitLines(series);
this.updateLimitLines();
- this.scheduleDraw();
},
resetAxisAndRedraw(newYAxisId, oldYAxisId, series) {
if (!oldYAxisId) {
@@ -459,8 +464,7 @@ export default {
//Make the chart elements again for the new y-axis and offset
this.makeChartElement(series);
this.makeLimitLines(series);
- this.updateLimitLines();
- this.scheduleDraw();
+ this.scheduleDraw(true);
},
destroy() {
this.destroyCanvas();
@@ -469,6 +473,10 @@ export default {
this.limitLines.forEach((line) => line.destroy());
this.pointSets.forEach((pointSet) => pointSet.destroy());
this.alarmSets.forEach((alarmSet) => alarmSet.destroy());
+ DrawLoader.releaseDrawAPI(this.drawAPI);
+ if (this.chartResizeObserver) {
+ this.chartResizeObserver.disconnect();
+ }
},
resetYOffsetAndSeriesDataForYAxis(yAxisId) {
delete this.offset[yAxisId].y;
@@ -703,12 +711,11 @@ export default {
return;
}
- this.updateLimitLines();
- this.scheduleDraw();
+ this.scheduleDraw(true);
},
- scheduleDraw() {
+ scheduleDraw(updateLimitLines) {
if (!this.drawScheduled) {
- const called = this.renderWhenVisible(this.draw);
+ const called = this.renderWhenVisible(this.draw.bind(this, updateLimitLines));
this.drawScheduled = called;
if (!this.drawnOnce && called) {
this.drawnOnce = true;
@@ -716,7 +723,7 @@ export default {
}
}
},
- draw() {
+ draw(updateLimitLines) {
this.drawScheduled = false;
if (this.isDestroyed || !this.chartVisible) {
return;
@@ -744,6 +751,11 @@ export default {
this.prepareToDrawAnnotationSelections(id);
}
});
+ // We must do the limit line drawing after the drawAPI has been cleared (which sets the height and width of the draw API)
+ // and the viewport is updated so that we have the right height/width for limit line x and y calculations
+ if (updateLimitLines) {
+ this.updateLimitLines();
+ }
},
updateViewport(yAxisId) {
if (!this.chartVisible) {
@@ -799,9 +811,12 @@ export default {
pointSets.forEach(this.drawPoints, this);
const alarmSets = this.alarmSets.filter(this.matchByYAxisId.bind(this, id));
alarmSets.forEach(this.drawAlarmPoints, this);
- //console.timeEnd('📈 drawSeries');
},
updateLimitLines() {
+ //reset
+ this.visibleLimitLabels = [];
+ this.visibleLimitLines = [];
+
this.config.series.models.forEach((series) => {
const yAxisId = series.get('yAxisId');
@@ -820,11 +835,7 @@ export default {
if (!this.drawAPI.origin) {
return;
}
-
let limitPointOverlap = [];
- //reset
- this.visibleLimitLabels = [];
- this.visibleLimitLines = [];
this.limitLines.forEach((limitLine) => {
limitLine.limits.forEach((limit) => {
diff --git a/src/plugins/plot/inspector/forms/SeriesForm.vue b/src/plugins/plot/inspector/forms/SeriesForm.vue
index 3b235630d2a..d0a39e2d74e 100644
--- a/src/plugins/plot/inspector/forms/SeriesForm.vue
+++ b/src/plugins/plot/inspector/forms/SeriesForm.vue
@@ -91,9 +91,16 @@
- Limit lines
+
+ Limit lines
+
-
+
diff --git a/src/plugins/plot/stackedPlot/StackedPlotItem.vue b/src/plugins/plot/stackedPlot/StackedPlotItem.vue
index a4342fa9ed7..15388e48a69 100644
--- a/src/plugins/plot/stackedPlot/StackedPlotItem.vue
+++ b/src/plugins/plot/stackedPlot/StackedPlotItem.vue
@@ -135,7 +135,7 @@ export default {
this.openmct.editor.off('isEditing', this.setEditState);
if (this.composition) {
this.composition.off('add', this.subscribeToStaleness);
- this.composition.off('remove', this.triggerUnsubscribeFromStaleness);
+ this.composition.off('remove', this.removeSubscription);
}
if (this.removeSelectable) {
@@ -161,6 +161,11 @@ export default {
}
}
},
+ removeSubscription(identifier) {
+ this.triggerUnsubscribeFromStaleness({
+ identifier
+ });
+ },
updateView() {
//If this object is not persistable, then package it with it's parent
const plotObject = this.getPlotObject();
@@ -172,7 +177,7 @@ export default {
this.composition = this.openmct.composition.get(plotObject);
this.composition.on('add', this.subscribeToStaleness);
- this.composition.on('remove', this.triggerUnsubscribeFromStaleness);
+ this.composition.on('remove', this.removeSubscription);
this.composition.load();
}