Ensure previews work for plots (#7459)

* fix large view in tree

* remove existing view concept

* fix plots in overlays

* remove debug and actually remove overlays when dismissed

* add test

* improve tests

* move test
This commit is contained in:
Scott Bell 2024-02-06 08:16:31 +01:00 committed by GitHub
parent 0aceb4b590
commit eeb8e9704b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 133 additions and 19 deletions

View File

@ -0,0 +1,88 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import { createDomainObjectWithDefaults } from '../../../../appActions.js';
import { expect, test } from '../../../../pluginFixtures.js';
test.describe('Plots work in Previews', () => {
test('We can preview plot in display layouts', async ({ page, openmctConfig }) => {
const { myItemsFolderName } = openmctConfig;
await page.goto('./', { waitUntil: 'domcontentloaded' });
// Create a Sinewave Generator
const sineWaveObject = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator'
});
// Create a Display Layout
await createDomainObjectWithDefaults(page, {
type: 'Display Layout',
name: 'Test Display Layout'
});
// Edit Display Layout
await page.getByLabel('Edit Object').click();
// Expand the 'My Items' folder in the left tree
await page.getByLabel(`Expand ${myItemsFolderName} folder`).click();
// Add the Sine Wave Generator to the Display Layout and save changes
const treePane = page.getByRole('tree', {
name: 'Main Tree'
});
const sineWaveGeneratorTreeItem = treePane.getByRole('treeitem', {
name: new RegExp(sineWaveObject.name)
});
const layoutGridHolder = page.getByLabel('Test Display Layout Layout Grid');
await sineWaveGeneratorTreeItem.dragTo(layoutGridHolder);
await page.getByLabel('Save').click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
// right click on the plot and select view large
await page.getByLabel('Sine', { exact: true }).click({ button: 'right' });
await page.getByLabel('View Historical Data').click();
await expect(page.getByLabel('Preview Container').getByLabel('Plot Canvas')).toBeVisible();
await page.getByLabel('Close').click();
await page.getByLabel('Expand Test Display Layout layout').click();
// change to a plot and ensure embiggen works
await page.getByLabel('Edit Object').click();
await page.getByLabel('Move Sub-object Frame').click();
await page.getByText('View type').click();
await page.getByText('Overlay Plot').click();
await page.getByLabel('Save').click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await expect(
page.getByLabel('Test Display Layout Layout', { exact: true }).getByLabel('Plot Canvas')
).toBeVisible();
await expect(page.getByLabel('Preview Container')).toBeHidden();
await page.getByLabel('Large View').click();
await expect(page.getByLabel('Preview Container').getByLabel('Plot Canvas')).toBeVisible();
await page.getByLabel('Close').click();
// get last sinewave tree item (in the display layout)
await page
.getByRole('treeitem', { name: /Sine Wave Generator/ })
.locator('a')
.last()
.click({ button: 'right' });
await page.getByLabel('View', { exact: true }).click();
await expect(page.getByLabel('Preview Container').getByLabel('Plot Canvas')).toBeVisible();
await page.getByLabel('Close').click();
});
});

View File

@ -61,6 +61,7 @@ class Overlay extends EventEmitter {
dismiss() {
this.emit('destroy');
this.destroy();
this.container.remove();
}
//Ensures that any callers are notified that the overlay is dismissed

View File

@ -22,8 +22,20 @@
<template>
<div ref="chart" class="gl-plot-chart-area">
<canvas id="2dContext" :style="canvasStyle" class="js-overlay-canvas" role="img"></canvas>
<canvas id="webglContext" :style="canvasStyle" class="js-main-canvas" role="img"></canvas>
<canvas
id="2dContext"
:style="canvasStyle"
class="js-overlay-canvas"
role="img"
aria-label="Overlay Canvas"
></canvas>
<canvas
id="webglContext"
:style="canvasStyle"
class="js-main-canvas"
role="img"
aria-label="Plot Canvas"
></canvas>
<div ref="limitArea" class="js-limit-area" aria-hidden="true">
<limit-label
v-for="(limitLabel, index) in visibleLimitLabels"
@ -202,9 +214,7 @@ export default {
this.drawnOnce = false;
const rootContainer = this.openmct.element;
const options = {
root: rootContainer,
rootMargin: '0px',
threshold: 1.0
root: rootContainer
};
this.visibilityObserver = new IntersectionObserver(this.visibilityChanged, options);
eventHelpers.extend(this);
@ -286,11 +296,16 @@ export default {
// and we need to use the Open MCT root element as the root of the intersection observer.
if (entry.target === this.chartContainer) {
const wasVisible = this.chartVisible;
this.chartVisible = entry.isIntersecting;
if (!this.chartVisible) {
// destroy the chart
const isNowVisible = entry.isIntersecting;
const chartInOverlayWindow = this.chartContainer?.closest('.js-overlay') !== null;
if (!isNowVisible && !chartInOverlayWindow) {
this.chartVisible = false;
this.destroyCanvas();
} else if (!wasVisible && this.chartVisible) {
} else if (!isNowVisible && chartInOverlayWindow) {
this.chartVisible = true;
} else if (!wasVisible && isNowVisible) {
this.chartVisible = true;
// rebuild the chart
this.buildCanvasElements();
const canvasInitialized = this.readyCanvasForDrawing();
@ -298,8 +313,8 @@ export default {
this.draw();
}
this.$emit('plot-reinitialize-canvas');
} else if (wasVisible && this.chartVisible) {
// ignore, moving on
} else {
this.chartVisible = isNowVisible;
}
}
},

View File

@ -228,8 +228,8 @@ DrawWebGL.prototype.setDimensions = function (dimensions, origin) {
}
if (dimensions && dimensions.length > 0 && origin && origin.length > 0) {
this.gl.uniform2fv(this.uDimensions, dimensions);
this.gl.uniform2fv(this.uOrigin, origin);
this.gl?.uniform2fv(this.uDimensions, dimensions);
this.gl?.uniform2fv(this.uOrigin, origin);
}
};

View File

@ -75,6 +75,7 @@
class="c-icon-button"
:class="item.cssClass"
:title="item.name"
:aria-label="item.name"
@click="item.onItemClicked"
>
<span class="c-icon-button__label">{{ item.name }}</span>

View File

@ -69,20 +69,23 @@ export default class PreviewAction extends EventEmitter {
}
);
let overlay = this._openmct.overlays.overlay({
const overlay = this._openmct.overlays.overlay({
element: vNode.el,
size: 'large',
autoHide: false,
buttons: [
{
label: 'Done',
callback: () => overlay.dismiss()
callback: () => {
overlay.dismiss();
}
}
],
onDestroy: () => {
PreviewAction.isVisible = false;
destroy();
this.emit('isVisible', false);
overlay.dismiss();
}
});

View File

@ -43,18 +43,24 @@ export default class VisibilityObserver {
this.isIntersecting = true;
this.calledOnce = false;
const options = {
root: rootContainer,
rootMargin: '0px',
threshold: 1.0
root: rootContainer
};
this.#observer = new IntersectionObserver(this.#observerCallback, options);
this.lastUnfiredFunc = null;
this.renderWhenVisible = this.renderWhenVisible.bind(this);
}
#inOverlay() {
return this.#element.closest('.js-overlay') !== null;
}
#observerCallback = ([entry]) => {
if (entry.target === this.#element) {
this.isIntersecting = entry.isIntersecting;
if (this.#inOverlay() && !entry.isIntersecting) {
this.isIntersecting = true;
} else {
this.isIntersecting = entry.isIntersecting;
}
if (this.isIntersecting && this.lastUnfiredFunc) {
window.requestAnimationFrame(this.lastUnfiredFunc);
this.lastUnfiredFunc = null;