mirror of
https://github.com/nasa/openmct.git
synced 2025-02-06 11:09:21 +00:00
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:
parent
0aceb4b590
commit
eeb8e9704b
88
e2e/tests/functional/plugins/plot/previews.e2e.spec.js
Normal file
88
e2e/tests/functional/plugins/plot/previews.e2e.spec.js
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
@ -61,6 +61,7 @@ class Overlay extends EventEmitter {
|
|||||||
dismiss() {
|
dismiss() {
|
||||||
this.emit('destroy');
|
this.emit('destroy');
|
||||||
this.destroy();
|
this.destroy();
|
||||||
|
this.container.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Ensures that any callers are notified that the overlay is dismissed
|
//Ensures that any callers are notified that the overlay is dismissed
|
||||||
|
@ -22,8 +22,20 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div ref="chart" class="gl-plot-chart-area">
|
<div ref="chart" class="gl-plot-chart-area">
|
||||||
<canvas id="2dContext" :style="canvasStyle" class="js-overlay-canvas" role="img"></canvas>
|
<canvas
|
||||||
<canvas id="webglContext" :style="canvasStyle" class="js-main-canvas" role="img"></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">
|
<div ref="limitArea" class="js-limit-area" aria-hidden="true">
|
||||||
<limit-label
|
<limit-label
|
||||||
v-for="(limitLabel, index) in visibleLimitLabels"
|
v-for="(limitLabel, index) in visibleLimitLabels"
|
||||||
@ -202,9 +214,7 @@ export default {
|
|||||||
this.drawnOnce = false;
|
this.drawnOnce = false;
|
||||||
const rootContainer = this.openmct.element;
|
const rootContainer = this.openmct.element;
|
||||||
const options = {
|
const options = {
|
||||||
root: rootContainer,
|
root: rootContainer
|
||||||
rootMargin: '0px',
|
|
||||||
threshold: 1.0
|
|
||||||
};
|
};
|
||||||
this.visibilityObserver = new IntersectionObserver(this.visibilityChanged, options);
|
this.visibilityObserver = new IntersectionObserver(this.visibilityChanged, options);
|
||||||
eventHelpers.extend(this);
|
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.
|
// and we need to use the Open MCT root element as the root of the intersection observer.
|
||||||
if (entry.target === this.chartContainer) {
|
if (entry.target === this.chartContainer) {
|
||||||
const wasVisible = this.chartVisible;
|
const wasVisible = this.chartVisible;
|
||||||
this.chartVisible = entry.isIntersecting;
|
const isNowVisible = entry.isIntersecting;
|
||||||
if (!this.chartVisible) {
|
const chartInOverlayWindow = this.chartContainer?.closest('.js-overlay') !== null;
|
||||||
// destroy the chart
|
|
||||||
|
if (!isNowVisible && !chartInOverlayWindow) {
|
||||||
|
this.chartVisible = false;
|
||||||
this.destroyCanvas();
|
this.destroyCanvas();
|
||||||
} else if (!wasVisible && this.chartVisible) {
|
} else if (!isNowVisible && chartInOverlayWindow) {
|
||||||
|
this.chartVisible = true;
|
||||||
|
} else if (!wasVisible && isNowVisible) {
|
||||||
|
this.chartVisible = true;
|
||||||
// rebuild the chart
|
// rebuild the chart
|
||||||
this.buildCanvasElements();
|
this.buildCanvasElements();
|
||||||
const canvasInitialized = this.readyCanvasForDrawing();
|
const canvasInitialized = this.readyCanvasForDrawing();
|
||||||
@ -298,8 +313,8 @@ export default {
|
|||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
this.$emit('plot-reinitialize-canvas');
|
this.$emit('plot-reinitialize-canvas');
|
||||||
} else if (wasVisible && this.chartVisible) {
|
} else {
|
||||||
// ignore, moving on
|
this.chartVisible = isNowVisible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -228,8 +228,8 @@ DrawWebGL.prototype.setDimensions = function (dimensions, origin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dimensions && dimensions.length > 0 && origin && origin.length > 0) {
|
if (dimensions && dimensions.length > 0 && origin && origin.length > 0) {
|
||||||
this.gl.uniform2fv(this.uDimensions, dimensions);
|
this.gl?.uniform2fv(this.uDimensions, dimensions);
|
||||||
this.gl.uniform2fv(this.uOrigin, origin);
|
this.gl?.uniform2fv(this.uOrigin, origin);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
class="c-icon-button"
|
class="c-icon-button"
|
||||||
:class="item.cssClass"
|
:class="item.cssClass"
|
||||||
:title="item.name"
|
:title="item.name"
|
||||||
|
:aria-label="item.name"
|
||||||
@click="item.onItemClicked"
|
@click="item.onItemClicked"
|
||||||
>
|
>
|
||||||
<span class="c-icon-button__label">{{ item.name }}</span>
|
<span class="c-icon-button__label">{{ item.name }}</span>
|
||||||
|
@ -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,
|
element: vNode.el,
|
||||||
size: 'large',
|
size: 'large',
|
||||||
autoHide: false,
|
autoHide: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
label: 'Done',
|
label: 'Done',
|
||||||
callback: () => overlay.dismiss()
|
callback: () => {
|
||||||
|
overlay.dismiss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
onDestroy: () => {
|
onDestroy: () => {
|
||||||
PreviewAction.isVisible = false;
|
PreviewAction.isVisible = false;
|
||||||
destroy();
|
destroy();
|
||||||
this.emit('isVisible', false);
|
this.emit('isVisible', false);
|
||||||
|
overlay.dismiss();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -43,18 +43,24 @@ export default class VisibilityObserver {
|
|||||||
this.isIntersecting = true;
|
this.isIntersecting = true;
|
||||||
this.calledOnce = false;
|
this.calledOnce = false;
|
||||||
const options = {
|
const options = {
|
||||||
root: rootContainer,
|
root: rootContainer
|
||||||
rootMargin: '0px',
|
|
||||||
threshold: 1.0
|
|
||||||
};
|
};
|
||||||
this.#observer = new IntersectionObserver(this.#observerCallback, options);
|
this.#observer = new IntersectionObserver(this.#observerCallback, options);
|
||||||
this.lastUnfiredFunc = null;
|
this.lastUnfiredFunc = null;
|
||||||
this.renderWhenVisible = this.renderWhenVisible.bind(this);
|
this.renderWhenVisible = this.renderWhenVisible.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#inOverlay() {
|
||||||
|
return this.#element.closest('.js-overlay') !== null;
|
||||||
|
}
|
||||||
|
|
||||||
#observerCallback = ([entry]) => {
|
#observerCallback = ([entry]) => {
|
||||||
if (entry.target === this.#element) {
|
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) {
|
if (this.isIntersecting && this.lastUnfiredFunc) {
|
||||||
window.requestAnimationFrame(this.lastUnfiredFunc);
|
window.requestAnimationFrame(this.lastUnfiredFunc);
|
||||||
this.lastUnfiredFunc = null;
|
this.lastUnfiredFunc = null;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user