Refactor plot actions to save space (#5201)

* Move image export actions to 3-dot menu
* Move cursor guide and toggle grid lines to local controls for plots (on hover)
* toggle cursor and gridlines affect all plots in a stacked plot
* Fix tests
* Better message when exporting plots, fixed typo

Co-authored-by: Joe Pea <trusktr@gmail.com>
Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com>
This commit is contained in:
Shefali Joshi 2022-05-20 11:41:01 -07:00 committed by GitHub
parent 1ca5271c3e
commit 48916564e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 168 additions and 104 deletions

View File

@ -51,7 +51,7 @@ class ImageExporter {
const overlays = this.openmct.overlays;
const dialog = overlays.dialog({
iconClass: 'info',
message: 'Caputuring an image',
message: 'Capturing image, please wait...',
buttons: [
{
label: 'Cancel',

View File

@ -154,6 +154,22 @@
>
</button>
</div>
<div class="c-button-set c-button-set--strip-h">
<button
class="c-button icon-crosshair"
:class="{ 'is-active': cursorGuide }"
title="Toggle cursor guides"
@click="toggleCursorGuide"
>
</button>
<button
class="c-button"
:class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }"
title="Toggle grid lines"
@click="toggleGridLines"
>
</button>
</div>
</div>
<!--Cursor guides-->
@ -213,16 +229,16 @@ export default {
};
}
},
gridLines: {
initGridLines: {
type: Boolean,
default() {
return true;
}
},
cursorGuide: {
initCursorGuide: {
type: Boolean,
default() {
return true;
return false;
}
},
plotTickWidth: {
@ -252,7 +268,9 @@ export default {
isTimeOutOfSync: false,
showLimitLineLabels: undefined,
isFrozenOnMouseDown: false,
hasSameRangeValue: true
hasSameRangeValue: true,
cursorGuide: this.initCursorGuide,
gridLines: this.initGridLines
};
},
computed: {
@ -273,6 +291,14 @@ export default {
return this.plotTickWidth || this.tickWidth;
}
},
watch: {
initGridLines(newGridLines) {
this.gridLines = newGridLines;
},
initCursorGuide(newCursorGuide) {
this.cursorGuide = newCursorGuide;
}
},
mounted() {
document.addEventListener('keydown', this.handleKeyDown);
document.addEventListener('keyup', this.handleKeyUp);
@ -1130,6 +1156,14 @@ export default {
},
legendHoverChanged(data) {
this.showLimitLineLabels = data;
},
toggleCursorGuide() {
this.cursorGuide = !this.cursorGuide;
this.$emit('cursorGuide', this.cursorGuide);
},
toggleGridLines() {
this.gridLines = !this.gridLines;
this.$emit('gridLines', this.gridLines);
}
}
};

View File

@ -24,41 +24,6 @@
ref="plotWrapper"
class="c-plot holder holder-plot has-control-bar"
>
<div
v-if="!options.compact"
class="c-control-bar"
>
<span class="c-button-set c-button-set--strip-h">
<button
class="c-button icon-download"
title="Export This View's Data as PNG"
@click="exportPNG()"
>
<span class="c-button__label">PNG</span>
</button>
<button
class="c-button"
title="Export This View's Data as JPG"
@click="exportJPG()"
>
<span class="c-button__label">JPG</span>
</button>
</span>
<button
class="c-button icon-crosshair"
:class="{ 'is-active': cursorGuide }"
title="Toggle cursor guides"
@click="toggleCursorGuide"
>
</button>
<button
class="c-button"
:class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }"
title="Toggle grid lines"
@click="toggleGridLines"
>
</button>
</div>
<div
ref="plotContainer"
@ -70,8 +35,8 @@
class="c-loading--overlay loading"
></div>
<mct-plot
:grid-lines="gridLines"
:cursor-guide="cursorGuide"
:init-grid-lines="gridLines"
:init-cursor-guide="cursorGuide"
:options="options"
@loadingUpdated="loadingUpdated"
@statusUpdated="setStatus"
@ -135,15 +100,14 @@ export default {
this.imageExporter.exportPNG(plotElement, 'plot.png', 'export-plot');
},
toggleCursorGuide() {
this.cursorGuide = !this.cursorGuide;
},
toggleGridLines() {
this.gridLines = !this.gridLines;
},
setStatus(status) {
this.status = status;
},
getViewContext() {
return {
exportPNG: this.exportPNG,
exportJPG: this.exportJPG
};
}
}
};

View File

@ -80,9 +80,16 @@ export default function PlotViewProvider(openmct) {
}
};
},
template: '<plot :options="options"></plot>'
template: '<plot ref="plotComponent" :options="options"></plot>'
});
},
getViewContext() {
if (!component) {
return {};
}
return component.$refs.plotComponent.getViewContext();
},
destroy: function () {
component.$destroy();
component = undefined;

View File

@ -0,0 +1,57 @@
/*****************************************************************************
* 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.
*****************************************************************************/
import {isPlotView} from "@/plugins/plot/actions/utils";
const exportPNG = {
name: 'Export as PNG',
key: 'export-as-png',
description: 'Export This View\'s Data as PNG',
cssClass: 'c-icon-button icon-download',
group: 'view',
invoke(objectPath, view) {
view.getViewContext().exportPNG();
}
};
const exportJPG = {
name: 'Export as JPG',
key: 'export-as-jpg',
description: 'Export This View\'s Data as JPG',
cssClass: 'c-icon-button icon-download',
group: 'view',
invoke(objectPath, view) {
view.getViewContext().exportJPG();
}
};
const viewActions = [
exportPNG,
exportJPG
];
viewActions.forEach(action => {
action.appliesTo = (objectPath, view = {}) => {
return isPlotView(view);
};
});
export default viewActions;

View File

@ -0,0 +1,3 @@
export function isPlotView(view) {
return view.key === 'plot-single' || view.key === 'plot-overlay' || view.key === 'plot-stacked';
}

View File

@ -65,9 +65,16 @@ export default function OverlayPlotViewProvider(openmct) {
}
};
},
template: '<plot :options="options"></plot>'
template: '<plot ref="plotComponent" :options="options"></plot>'
});
},
getViewContext() {
if (!component) {
return {};
}
return component.$refs.plotComponent.getViewContext();
},
destroy: function () {
component.$destroy();
component = undefined;

View File

@ -25,6 +25,7 @@ import StackedPlotViewProvider from './stackedPlot/StackedPlotViewProvider';
import PlotsInspectorViewProvider from './inspector/PlotsInspectorViewProvider';
import OverlayPlotCompositionPolicy from './overlayPlot/OverlayPlotCompositionPolicy';
import StackedPlotCompositionPolicy from './stackedPlot/StackedPlotCompositionPolicy';
import PlotViewActions from "./actions/ViewActions";
export default function () {
return function install(openmct) {
@ -67,6 +68,9 @@ export default function () {
openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow);
openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow);
PlotViewActions.forEach(action => {
openmct.actions.register(action);
});
};
}

View File

@ -724,16 +724,16 @@ describe("the plugin", function () {
});
it("turns on cursor Guides all telemetry objects", (done) => {
expect(plotViewComponentObject.cursorGuide).toBeFalse();
plotViewComponentObject.toggleCursorGuide();
expect(plotViewComponentObject.$children[0].cursorGuide).toBeFalse();
plotViewComponentObject.$children[0].cursorGuide = true;
Vue.nextTick(() => {
expect(plotViewComponentObject.$children[0].component.$children[0].cursorGuide).toBeTrue();
expect(plotViewComponentObject.$children[0].cursorGuide).toBeTrue();
done();
});
});
it("shows grid lines for all telemetry objects", () => {
expect(plotViewComponentObject.gridLines).toBeTrue();
expect(plotViewComponentObject.$children[0].gridLines).toBeTrue();
let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks");
let visible = 0;
gridLinesContainer.forEach(el => {
@ -745,10 +745,10 @@ describe("the plugin", function () {
});
it("hides grid lines for all telemetry objects", (done) => {
expect(plotViewComponentObject.gridLines).toBeTrue();
plotViewComponentObject.toggleGridLines();
expect(plotViewComponentObject.$children[0].gridLines).toBeTrue();
plotViewComponentObject.$children[0].gridLines = false;
Vue.nextTick(() => {
expect(plotViewComponentObject.gridLines).toBeFalse();
expect(plotViewComponentObject.$children[0].gridLines).toBeFalse();
let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks");
let visible = 0;
gridLinesContainer.forEach(el => {

View File

@ -22,41 +22,6 @@
<template>
<div class="c-plot c-plot--stacked holder holder-plot has-control-bar">
<div
v-show="!hideExportButtons && !options.compact"
class="c-control-bar"
>
<span class="c-button-set c-button-set--strip-h">
<button
class="c-button icon-download"
title="Export This View's Data as PNG"
@click="exportPNG()"
>
<span class="c-button__label">PNG</span>
</button>
<button
class="c-button"
title="Export This View's Data as JPG"
@click="exportJPG()"
>
<span class="c-button__label">JPG</span>
</button>
</span>
<button
class="c-button icon-crosshair"
:class="{ 'is-active': cursorGuide }"
title="Toggle cursor guides"
@click="toggleCursorGuide"
>
</button>
<button
class="c-button"
:class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }"
title="Toggle grid lines"
@click="toggleGridLines"
>
</button>
</div>
<div class="l-view-section">
<stacked-plot-item
v-for="object in compositionObjects"
@ -69,6 +34,8 @@
:plot-tick-width="maxTickWidth"
@plotTickWidth="onTickWidthChange"
@loadingUpdated="loadingUpdated"
@cursorGuide="onCursorGuideChange"
@gridLines="onGridLinesChange"
/>
</div>
</div>
@ -184,20 +151,24 @@ export default {
this.hideExportButtons = false;
}.bind(this));
},
toggleCursorGuide() {
this.cursorGuide = !this.cursorGuide;
},
toggleGridLines() {
this.gridLines = !this.gridLines;
},
onTickWidthChange(width, plotId) {
if (!Object.prototype.hasOwnProperty.call(this.tickWidthMap, plotId)) {
return;
}
this.$set(this.tickWidthMap, plotId, width);
},
onCursorGuideChange(cursorGuide) {
this.cursorGuide = cursorGuide === true;
},
onGridLinesChange(gridLines) {
this.gridLines = gridLines === true;
},
getViewContext() {
return {
exportPNG: this.exportPNG,
exportJPG: this.exportJPG
};
}
}
};

View File

@ -96,6 +96,8 @@ export default {
}
const onTickWidthChange = this.onTickWidthChange;
const onCursorGuideChange = this.onCursorGuideChange;
const onGridLinesChange = this.onGridLinesChange;
const loadingUpdated = this.loadingUpdated;
const setStatus = this.setStatus;
@ -121,16 +123,24 @@ export default {
return {
...getProps(),
onTickWidthChange,
onCursorGuideChange,
onGridLinesChange,
loadingUpdated,
setStatus
};
},
template: '<div ref="plotWrapper" class="l-view-section u-style-receiver js-style-receiver" :class="{\'s-status-timeconductor-unsynced\': status && status === \'timeconductor-unsynced\'}"><div v-show="!!loading" class="c-loading--overlay loading"></div><mct-plot :grid-lines="gridLines" :cursor-guide="cursorGuide" :plot-tick-width="plotTickWidth" :options="options" @plotTickWidth="onTickWidthChange" @statusUpdated="setStatus" @loadingUpdated="loadingUpdated"/></div>'
template: '<div ref="plotWrapper" class="l-view-section u-style-receiver js-style-receiver" :class="{\'s-status-timeconductor-unsynced\': status && status === \'timeconductor-unsynced\'}"><div v-show="!!loading" class="c-loading--overlay loading"></div><mct-plot :init-grid-lines="gridLines" :init-cursor-guide="cursorGuide" :plot-tick-width="plotTickWidth" :options="options" @plotTickWidth="onTickWidthChange" @cursorGuide="onCursorGuideChange" @gridLines="onGridLinesChange" @statusUpdated="setStatus" @loadingUpdated="loadingUpdated"/></div>'
});
},
onTickWidthChange() {
this.$emit('plotTickWidth', ...arguments);
},
onCursorGuideChange() {
this.$emit('cursorGuide', ...arguments);
},
onGridLinesChange() {
this.$emit('gridLines', ...arguments);
},
setStatus(status) {
this.status = status;
this.updateComponentProp('status', status);

View File

@ -67,9 +67,16 @@ export default function StackedPlotViewProvider(openmct) {
}
};
},
template: '<stacked-plot :options="options"></stacked-plot>'
template: '<stacked-plot ref="plotComponent" :options="options"></stacked-plot>'
});
},
getViewContext() {
if (!component) {
return {};
}
return component.$refs.plotComponent.getViewContext();
},
destroy: function () {
component.$destroy();
component = undefined;