From bdb1867c7361e9d3122a72f0115693f674db5efb Mon Sep 17 00:00:00 2001 From: Shefali Joshi Date: Wed, 8 Jun 2022 15:17:40 -0700 Subject: [PATCH] Selection of stacked plot items and customizing them (#5198) * Adds stacked plot inspector view provider for non subObjects * Initialize config for telemetry objects that cannot be persisted with the config in the stacked plot Use events to save telemetry object config changes to the stacked plot Remove changes that weren't relevant anymore * Ensure the telemetry objects that cannot be persisted are initialized correctly * Fixes for selection indication in Stacked Plots - Better theme constant colors. - Fixed broken selectors. - Changes also improve selection editing UI for Display and Flex Layouts. * Ensure unique colors for stacked plot if they are auto assigned * Fix bug hiding legend when viewing plots nested within a stacked plot * Move stacked plots tests to it's own pluginSpec to simplify tests Co-authored-by: Charles Hacskaylo Co-authored-by: Andrew Henry Co-authored-by: Rukmini Bose --- .../components/layout-frame.scss | 1 - .../components/flexible-layout.scss | 4 + src/plugins/plot/MctPlot.vue | 41 +- .../configuration/PlotConfigurationModel.js | 3 +- .../plot/configuration/SeriesCollection.js | 2 +- src/plugins/plot/configuration/YAxisModel.js | 2 +- .../plot/inspector/PlotOptionsBrowse.vue | 26 +- .../plot/inspector/PlotOptionsEdit.vue | 46 +- .../inspector/PlotsInspectorViewProvider.js | 6 +- .../StackedPlotsInspectorViewProvider.js | 59 ++ .../plot/inspector/forms/SeriesForm.vue | 67 +- .../plot/inspector/forms/YAxisForm.vue | 18 +- src/plugins/plot/legend/PlotLegend.vue | 8 +- .../plot/legend/PlotLegendItemCollapsed.vue | 2 +- src/plugins/plot/plugin.js | 13 +- src/plugins/plot/pluginSpec.js | 387 +-------- src/plugins/plot/stackedPlot/StackedPlot.vue | 124 ++- .../plot/stackedPlot/StackedPlotItem.vue | 104 ++- .../stackedPlot/mixins/objectStyles-mixin.js | 10 +- src/plugins/plot/stackedPlot/pluginSpec.js | 771 ++++++++++++++++++ src/styles/_constants-espresso.scss | 6 +- src/styles/_constants-maelstrom.scss | 6 +- src/styles/_constants-snow.scss | 4 +- src/styles/_legacy-plots.scss | 8 +- 24 files changed, 1288 insertions(+), 430 deletions(-) create mode 100644 src/plugins/plot/inspector/StackedPlotsInspectorViewProvider.js create mode 100644 src/plugins/plot/stackedPlot/pluginSpec.js diff --git a/src/plugins/displayLayout/components/layout-frame.scss b/src/plugins/displayLayout/components/layout-frame.scss index d036814021..656a535c8f 100644 --- a/src/plugins/displayLayout/components/layout-frame.scss +++ b/src/plugins/displayLayout/components/layout-frame.scss @@ -28,7 +28,6 @@ &[s-selected] { // All frames selected while editing - border: $editFrameSelectedBorder; box-shadow: $editFrameSelectedShdw; .c-frame__move-bar { diff --git a/src/plugins/flexibleLayout/components/flexible-layout.scss b/src/plugins/flexibleLayout/components/flexible-layout.scss index ac44eb3d3c..6fe96a446b 100644 --- a/src/plugins/flexibleLayout/components/flexible-layout.scss +++ b/src/plugins/flexibleLayout/components/flexible-layout.scss @@ -141,6 +141,10 @@ } } } + + [s-selected].c-fl-frame__drag-wrapper { + border: $editFrameSelectedBorder; + } } /****** THEIR FRAMES */ diff --git a/src/plugins/plot/MctPlot.vue b/src/plugins/plot/MctPlot.vue index 8ae4f08bf5..c1ff233ac5 100644 --- a/src/plugins/plot/MctPlot.vue +++ b/src/plugins/plot/MctPlot.vue @@ -26,6 +26,7 @@ :class="[plotLegendExpandedStateClass, plotLegendPositionClass]" > pathObject.type === 'telemetry.plot.stacked'); + }, isFrozen() { return this.config.xAxis.get('frozen') === true && this.config.yAxis.get('frozen') === true; }, plotLegendPositionClass() { - return `plot-legend-${this.config.legend.get('position')}`; + 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 { @@ -292,6 +314,12 @@ export default { } }, watch: { + limitLineLabels: { + handler(limitLineLabels) { + this.legendHoverChanged(limitLineLabels); + }, + deep: true + }, initGridLines(newGridLines) { this.gridLines = newGridLines; }, @@ -310,6 +338,11 @@ export default { this.config = this.getConfig(); this.legend = this.config.legend; + if (this.isNestedWithinAStackedPlot) { + const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier); + this.$emit('configLoaded', configId); + } + this.listenTo(this.config.series, 'add', this.addSeries, this); this.listenTo(this.config.series, 'remove', this.removeSeries, this); @@ -375,6 +408,7 @@ export default { id: configId, domainObject: this.domainObject, openmct: this.openmct, + palette: this.colorPalette, callback: (data) => { this.data = data; } @@ -758,6 +792,8 @@ export default { }; }); } + + this.$emit('highlights', this.highlights); }, untrackMousePosition() { @@ -792,6 +828,7 @@ export default { if (this.isMouseClick()) { this.lockHighlightPoint = !this.lockHighlightPoint; + this.$emit('lockHighlightPoint', this.lockHighlightPoint); } if (this.pan) { diff --git a/src/plugins/plot/configuration/PlotConfigurationModel.js b/src/plugins/plot/configuration/PlotConfigurationModel.js index 0f6a56cd6f..ce0c6e532e 100644 --- a/src/plugins/plot/configuration/PlotConfigurationModel.js +++ b/src/plugins/plot/configuration/PlotConfigurationModel.js @@ -68,7 +68,8 @@ export default class PlotConfigurationModel extends Model { this.series = new SeriesCollection({ models: options.model.series, plot: this, - openmct: options.openmct + openmct: options.openmct, + palette: options.palette }); if (this.get('domainObject').type === 'telemetry.plot.overlay') { diff --git a/src/plugins/plot/configuration/SeriesCollection.js b/src/plugins/plot/configuration/SeriesCollection.js index 33160a8fa3..b5bb81dbbc 100644 --- a/src/plugins/plot/configuration/SeriesCollection.js +++ b/src/plugins/plot/configuration/SeriesCollection.js @@ -39,7 +39,7 @@ export default class SeriesCollection extends Collection { this.modelClass = PlotSeries; this.plot = options.plot; this.openmct = options.openmct; - this.palette = new ColorPalette(); + this.palette = options.palette || new ColorPalette(); this.listenTo(this, 'add', this.onSeriesAdd, this); this.listenTo(this, 'remove', this.onSeriesRemove, this); this.listenTo(this.plot, 'change:domainObject', this.trackPersistedConfig, this); diff --git a/src/plugins/plot/configuration/YAxisModel.js b/src/plugins/plot/configuration/YAxisModel.js index aaedcaae30..8c03631d6a 100644 --- a/src/plugins/plot/configuration/YAxisModel.js +++ b/src/plugins/plot/configuration/YAxisModel.js @@ -260,7 +260,7 @@ export default class YAxisModel extends Model { const plotModel = this.plot.get('domainObject'); const label = plotModel.configuration?.yAxis?.label; const sampleSeries = seriesCollection.first(); - if (!sampleSeries) { + if (!sampleSeries || !sampleSeries.metadata) { if (!label) { this.unset('label'); } diff --git a/src/plugins/plot/inspector/PlotOptionsBrowse.vue b/src/plugins/plot/inspector/PlotOptionsBrowse.vue index b85a2683f8..12ee36e7d8 100644 --- a/src/plugins/plot/inspector/PlotOptionsBrowse.vue +++ b/src/plugins/plot/inspector/PlotOptionsBrowse.vue @@ -24,7 +24,10 @@ v-if="loaded" class="js-plot-options-browse" > -
    +

      Plot Series

      -
        +

          Y Axis

        • {{ rangeMax }}
        -
          +

            Legend

          • pathObjIndex > 0 && pathObject.type === 'telemetry.plot.stacked'); + }, + isStackedPlotObject() { + return this.path.find((pathObject, pathObjIndex) => pathObjIndex === 0 && pathObject.type === 'telemetry.plot.stacked'); + } + }, mounted() { eventHelpers.extend(this); this.config = this.getConfig(); this.registerListeners(); this.initConfiguration(); this.loaded = true; + }, beforeDestroy() { this.stopListening(); diff --git a/src/plugins/plot/inspector/PlotOptionsEdit.vue b/src/plugins/plot/inspector/PlotOptionsEdit.vue index 77dc891988..234e30332e 100644 --- a/src/plugins/plot/inspector/PlotOptionsEdit.vue +++ b/src/plugins/plot/inspector/PlotOptionsEdit.vue @@ -24,21 +24,31 @@ v-if="loaded" class="js-plot-options-edit" > -
              +

                Plot Series

              • - +
              -
                +

                  Legend

                  pathObjIndex > 0 && pathObject.type === 'telemetry.plot.stacked'); + }, + isStackedPlotObject() { + return this.path.find((pathObject, pathObjIndex) => pathObjIndex === 0 && pathObject.type === 'telemetry.plot.stacked'); + } + }, mounted() { eventHelpers.extend(this); this.config = this.getConfig(); @@ -98,6 +116,24 @@ export default { resetAllSeries() { this.plotSeries = []; this.config.series.forEach(this.addSeries, this); + }, + + updateSeriesConfigForObject(config) { + const stackedPlotObject = this.path.find((pathObject) => pathObject.type === 'telemetry.plot.stacked'); + let index = stackedPlotObject.configuration.series.findIndex((seriesConfig) => { + return this.openmct.objects.areIdsEqual(seriesConfig.identifier, config.identifier); + }); + if (index < 0) { + index = stackedPlotObject.configuration.series.length; + } + + const configPath = `configuration.series[${index}].${config.path}`; + this.openmct.objects.mutate( + stackedPlotObject, + configPath, + config.value + ); + } } }; diff --git a/src/plugins/plot/inspector/PlotsInspectorViewProvider.js b/src/plugins/plot/inspector/PlotsInspectorViewProvider.js index 16b88412c5..aebacfa7eb 100644 --- a/src/plugins/plot/inspector/PlotsInspectorViewProvider.js +++ b/src/plugins/plot/inspector/PlotsInspectorViewProvider.js @@ -13,8 +13,10 @@ export default function PlotsInspectorViewProvider(openmct) { let object = selection[0][0].context.item; - return object - && object.type === 'telemetry.plot.overlay'; + const isOverlayPlotObject = object && object.type === 'telemetry.plot.overlay'; + const isStackedPlotObject = object && object.type === 'telemetry.plot.stacked'; + + return isStackedPlotObject || isOverlayPlotObject; }, view: function (selection) { let component; diff --git a/src/plugins/plot/inspector/StackedPlotsInspectorViewProvider.js b/src/plugins/plot/inspector/StackedPlotsInspectorViewProvider.js new file mode 100644 index 0000000000..8cd6bc78d2 --- /dev/null +++ b/src/plugins/plot/inspector/StackedPlotsInspectorViewProvider.js @@ -0,0 +1,59 @@ + +import PlotOptions from "./PlotOptions.vue"; +import Vue from 'vue'; + +export default function StackedPlotsInspectorViewProvider(openmct) { + return { + key: 'stacked-plots-inspector', + name: 'Stacked Plots Inspector View', + canView: function (selection) { + if (selection.length === 0 || selection[0].length === 0) { + return false; + } + + 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'; + + return !isOverlayPlotObject && isParentStackedPlotObject; + }, + view: function (selection) { + let component; + let objectPath; + + if (selection.length) { + objectPath = selection[0].map((selectionItem) => { + return selectionItem.context.item; + }); + } + + return { + show: function (element) { + component = new Vue({ + el: element, + components: { + PlotOptions: PlotOptions + }, + provide: { + openmct, + domainObject: selection[0][0].context.item, + path: objectPath + }, + template: '' + }); + }, + destroy: function () { + if (component) { + component.$destroy(); + component = undefined; + } + } + }; + }, + priority: function () { + return 1; + } + }; +} diff --git a/src/plugins/plot/inspector/forms/SeriesForm.vue b/src/plugins/plot/inspector/forms/SeriesForm.vue index 8434bd3497..2a7ff4d2b0 100644 --- a/src/plugins/plot/inspector/forms/SeriesForm.vue +++ b/src/plugins/plot/inspector/forms/SeriesForm.vue @@ -298,28 +298,45 @@ export default { this.series.set('color', color); - const getPath = this.dynamicPathForKey('color'); - const seriesColorPath = getPath(this.domainObject, this.series); + if (!this.domainObject.configuration || !this.domainObject.configuration.series) { + this.$emit('seriesUpdated', { + identifier: this.domainObject.identifier, + path: `series.color`, + value: color.asHexString() + }); + } else { + const getPath = this.dynamicPathForKey('color'); + const seriesColorPath = getPath(this.domainObject, this.series); - this.openmct.objects.mutate( - this.domainObject, - seriesColorPath, - color.asHexString() - ); + this.openmct.objects.mutate( + this.domainObject, + seriesColorPath, + color.asHexString() + ); + } if (otherSeriesWithColor) { otherSeriesWithColor.set('color', oldColor); - const otherSeriesColorPath = getPath( - this.domainObject, - otherSeriesWithColor - ); + if (!this.domainObject.configuration || !this.domainObject.configuration.series) { + this.$emit('seriesUpdated', { + identifier: this.domainObject.identifier, + path: `series.color`, + value: oldColor.asHexString() + }); + } else { + const getPath = this.dynamicPathForKey('color'); + const otherSeriesColorPath = getPath( + this.domainObject, + otherSeriesWithColor + ); - this.openmct.objects.mutate( - this.domainObject, - otherSeriesColorPath, - oldColor.asHexString() - ); + this.openmct.objects.mutate( + this.domainObject, + otherSeriesColorPath, + oldColor.asHexString() + ); + } } }, toggleExpanded() { @@ -343,11 +360,19 @@ export default { if (!_.isEqual(coerce(newVal, formField.coerce), coerce(oldVal, formField.coerce))) { this.series.set(formKey, coerce(newVal, formField.coerce)); if (path) { - this.openmct.objects.mutate( - this.domainObject, - path(this.domainObject, this.series), - coerce(newVal, formField.coerce) - ); + if (!this.domainObject.configuration || !this.domainObject.configuration.series) { + this.$emit('seriesUpdated', { + identifier: this.domainObject.identifier, + path: `series.${formKey}`, + value: coerce(newVal, formField.coerce) + }); + } else { + this.openmct.objects.mutate( + this.domainObject, + path(this.domainObject, this.series), + coerce(newVal, formField.coerce) + ); + } } } }, diff --git a/src/plugins/plot/inspector/forms/YAxisForm.vue b/src/plugins/plot/inspector/forms/YAxisForm.vue index bf85312302..c0dc5ec57a 100644 --- a/src/plugins/plot/inspector/forms/YAxisForm.vue +++ b/src/plugins/plot/inspector/forms/YAxisForm.vue @@ -230,11 +230,19 @@ export default { // TODO: Why do we mutate yAxis twice, once directly, once via objects.mutate? Or are they different objects? this.yAxis.set(formKey, newVal); if (path) { - this.openmct.objects.mutate( - this.domainObject, - path(this.domainObject, this.yAxis), - newVal - ); + if (!this.domainObject.configuration || !this.domainObject.configuration.series) { + this.$emit('seriesUpdated', { + identifier: this.domainObject.identifier, + path: `yAxis.${formKey}`, + value: newVal + }); + } else { + this.openmct.objects.mutate( + this.domainObject, + path(this.domainObject, this.yAxis), + newVal + ); + } } } } diff --git a/src/plugins/plot/legend/PlotLegend.vue b/src/plugins/plot/legend/PlotLegend.vue index e62fc5d995..1bdf4b3bb9 100644 --- a/src/plugins/plot/legend/PlotLegend.vue +++ b/src/plugins/plot/legend/PlotLegend.vue @@ -49,8 +49,8 @@ title="Cursor is point locked. Click anywhere in the plot to unlock." >
            {{ nameWithUnit }}
            diff --git a/src/plugins/plot/plugin.js b/src/plugins/plot/plugin.js index 89f6f005b7..efee6ca9aa 100644 --- a/src/plugins/plot/plugin.js +++ b/src/plugins/plot/plugin.js @@ -26,6 +26,7 @@ import PlotsInspectorViewProvider from './inspector/PlotsInspectorViewProvider'; import OverlayPlotCompositionPolicy from './overlayPlot/OverlayPlotCompositionPolicy'; import StackedPlotCompositionPolicy from './stackedPlot/StackedPlotCompositionPolicy'; import PlotViewActions from "./actions/ViewActions"; +import StackedPlotsInspectorViewProvider from "./inspector/StackedPlotsInspectorViewProvider"; export default function () { return function install(openmct) { @@ -39,9 +40,8 @@ export default function () { initialize: function (domainObject) { domainObject.composition = []; domainObject.configuration = { - series: [], - yAxis: {}, - xAxis: {} + //series is an array of objects of type: {identifier, series: {color...}, yAxis:{}} + series: [] }; }, priority: 891 @@ -55,7 +55,11 @@ export default function () { creatable: true, initialize: function (domainObject) { domainObject.composition = []; - domainObject.configuration = {}; + domainObject.configuration = { + series: [], + yAxis: {}, + xAxis: {} + }; }, priority: 890 }); @@ -65,6 +69,7 @@ export default function () { openmct.objectViews.addProvider(new PlotViewProvider(openmct)); openmct.inspectorViews.addProvider(new PlotsInspectorViewProvider(openmct)); + openmct.inspectorViews.addProvider(new StackedPlotsInspectorViewProvider(openmct)); openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow); openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow); diff --git a/src/plugins/plot/pluginSpec.js b/src/plugins/plot/pluginSpec.js index a78107ffee..36859a50d0 100644 --- a/src/plugins/plot/pluginSpec.js +++ b/src/plugins/plot/pluginSpec.js @@ -23,7 +23,6 @@ import {createMouseEvent, createOpenMct, resetApplicationState, spyOnBuiltins} from "utils/testing"; import PlotVuePlugin from "./plugin"; import Vue from "vue"; -import StackedPlot from "./stackedPlot/StackedPlot.vue"; import configStore from "./configuration/ConfigStore"; import EventEmitter from "EventEmitter"; import PlotOptions from "./inspector/PlotOptions.vue"; @@ -348,14 +347,20 @@ describe("the plugin", function () { } }; + openmct.router.path = [testTelemetryObject]; + applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath); plotViewProvider = applicableViews.find((viewProvider) => viewProvider.key === "plot-single"); - plotView = plotViewProvider.view(testTelemetryObject, [testTelemetryObject]); + plotView = plotViewProvider.view(testTelemetryObject, []); plotView.show(child, true); return Vue.nextTick(); }); + afterEach(() => { + openmct.router.path = null; + }); + it("Makes only one request for telemetry on load", () => { expect(openmct.telemetry.request).toHaveBeenCalledTimes(1); }); @@ -523,360 +528,6 @@ describe("the plugin", function () { }); }); - describe("The stacked plot view", () => { - let testTelemetryObject; - let testTelemetryObject2; - let config; - let stackedPlotObject; - let component; - let mockComposition; - let plotViewComponentObject; - - beforeEach(() => { - - stackedPlotObject = { - identifier: { - namespace: "", - key: "test-plot" - }, - type: "telemetry.plot.stacked", - name: "Test Stacked Plot" - }; - - testTelemetryObject = { - identifier: { - namespace: "", - key: "test-object" - }, - type: "test-object", - name: "Test Object", - telemetry: { - values: [{ - key: "utc", - format: "utc", - name: "Time", - hints: { - domain: 1 - } - }, { - key: "some-key", - name: "Some attribute", - hints: { - range: 1 - } - }, { - key: "some-other-key", - name: "Another attribute", - hints: { - range: 2 - } - }] - }, - configuration: { - objectStyles: { - staticStyle: { - style: { - backgroundColor: 'rgb(0, 200, 0)', - color: '', - border: '' - } - }, - conditionSetIdentifier: { - namespace: '', - key: 'testConditionSetId' - }, - selectedConditionId: 'conditionId1', - defaultConditionId: 'conditionId1', - styles: [ - { - conditionId: 'conditionId1', - style: { - backgroundColor: 'rgb(0, 155, 0)', - color: '', - output: '', - border: '' - } - } - ] - } - } - }; - - testTelemetryObject2 = { - identifier: { - namespace: "", - key: "test-object2" - }, - type: "test-object", - name: "Test Object2", - telemetry: { - values: [{ - key: "utc", - format: "utc", - name: "Time", - hints: { - domain: 1 - } - }, { - key: "some-key2", - name: "Some attribute2", - hints: { - range: 1 - } - }, { - key: "some-other-key2", - name: "Another attribute2", - hints: { - range: 2 - } - }] - } - }; - - mockComposition = new EventEmitter(); - mockComposition.load = () => { - mockComposition.emit('add', testTelemetryObject); - - return [testTelemetryObject]; - }; - - spyOn(openmct.composition, 'get').and.returnValue(mockComposition); - - let viewContainer = document.createElement("div"); - child.append(viewContainer); - component = new Vue({ - el: viewContainer, - components: { - StackedPlot - }, - provide: { - openmct: openmct, - domainObject: stackedPlotObject, - composition: openmct.composition.get(stackedPlotObject), - path: [stackedPlotObject] - }, - template: "" - }); - - return telemetryPromise - .then(Vue.nextTick()) - .then(() => { - plotViewComponentObject = component.$root.$children[0]; - const configId = openmct.objects.makeKeyString(testTelemetryObject.identifier); - config = configStore.get(configId); - }); - }); - - it("Renders a collapsed legend for every telemetry", () => { - let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name"); - expect(legend.length).toBe(1); - expect(legend[0].innerHTML).toEqual("Test Object"); - }); - - it("Renders an expanded legend for every telemetry", () => { - let legendControl = element.querySelector(".c-plot-legend__view-control.gl-plot-legend__view-control.c-disclosure-triangle"); - const clickEvent = createMouseEvent("click"); - - legendControl.dispatchEvent(clickEvent); - - let legend = element.querySelectorAll(".plot-wrapper-expanded-legend .plot-legend-item td"); - expect(legend.length).toBe(6); - }); - - it("Renders X-axis ticks for the telemetry object", (done) => { - let xAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-x .gl-plot-tick-wrapper"); - expect(xAxisElement.length).toBe(1); - - config.xAxis.set('displayRange', { - min: 0, - max: 4 - }); - - Vue.nextTick(() => { - let ticks = xAxisElement[0].querySelectorAll(".gl-plot-tick"); - expect(ticks.length).toBe(9); - - done(); - }); - }); - - it("Renders Y-axis ticks for the telemetry object", (done) => { - config.yAxis.set('displayRange', { - min: 10, - max: 20 - }); - Vue.nextTick(() => { - let yAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-y .gl-plot-tick-wrapper"); - expect(yAxisElement.length).toBe(1); - let ticks = yAxisElement[0].querySelectorAll(".gl-plot-tick"); - expect(ticks.length).toBe(6); - done(); - }); - }); - - it("Renders Y-axis options for the telemetry object", () => { - let yAxisElement = element.querySelectorAll(".gl-plot-axis-area.gl-plot-y .gl-plot-y-label__select"); - expect(yAxisElement.length).toBe(1); - let options = yAxisElement[0].querySelectorAll("option"); - expect(options.length).toBe(2); - expect(options[0].value).toBe("Some attribute"); - expect(options[1].value).toBe("Another attribute"); - }); - - it("turns on cursor Guides all telemetry objects", (done) => { - expect(plotViewComponentObject.$children[0].cursorGuide).toBeFalse(); - plotViewComponentObject.$children[0].cursorGuide = true; - Vue.nextTick(() => { - expect(plotViewComponentObject.$children[0].cursorGuide).toBeTrue(); - done(); - }); - }); - - it("shows grid lines for all telemetry objects", () => { - expect(plotViewComponentObject.$children[0].gridLines).toBeTrue(); - let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks"); - let visible = 0; - gridLinesContainer.forEach(el => { - if (el.style.display !== "none") { - visible++; - } - }); - expect(visible).toBe(2); - }); - - it("hides grid lines for all telemetry objects", (done) => { - expect(plotViewComponentObject.$children[0].gridLines).toBeTrue(); - plotViewComponentObject.$children[0].gridLines = false; - Vue.nextTick(() => { - expect(plotViewComponentObject.$children[0].gridLines).toBeFalse(); - let gridLinesContainer = element.querySelectorAll(".gl-plot-display-area .js-ticks"); - let visible = 0; - gridLinesContainer.forEach(el => { - if (el.style.display !== "none") { - visible++; - } - }); - expect(visible).toBe(0); - done(); - }); - }); - - it('plots a new series when a new telemetry object is added', (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('removes plots from series when a telemetry object is removed', (done) => { - mockComposition.emit('remove', testTelemetryObject.identifier); - Vue.nextTick(() => { - let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name"); - expect(legend.length).toBe(0); - done(); - }); - }); - - it("Changes the label of the y axis when the option changes", (done) => { - let selectEl = element.querySelector('.gl-plot-y-label__select'); - selectEl.value = 'Another attribute'; - selectEl.dispatchEvent(new Event("change")); - - Vue.nextTick(() => { - expect(config.yAxis.get('label')).toEqual('Another attribute'); - done(); - }); - }); - - 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({ - utc: 2, - 'some-key': 1, - 'some-other-key': 2 - }); - Vue.nextTick(() => { - const seriesData = config.series.models[0].getSeriesData(); - expect(seriesData.length).toEqual(originalLength + 1); - done(); - }); - }); - - it("updates the xscale", (done) => { - config.xAxis.set('displayRange', { - min: 0, - max: 10 - }); - Vue.nextTick(() => { - expect(plotViewComponentObject.$children[0].component.$children[0].xScale.domain()).toEqual({ - min: 0, - max: 10 - }); - done(); - }); - }); - - it("updates the yscale", (done) => { - config.yAxis.set('displayRange', { - min: 10, - max: 20 - }); - Vue.nextTick(() => { - expect(plotViewComponentObject.$children[0].component.$children[0].yScale.domain()).toEqual({ - min: 10, - max: 20 - }); - done(); - }); - }); - - it("shows styles for telemetry objects if available", (done) => { - Vue.nextTick(() => { - let conditionalStylesContainer = element.querySelectorAll(".c-plot--stacked-container .js-style-receiver"); - let hasStyles = 0; - conditionalStylesContainer.forEach(el => { - if (el.style.backgroundColor !== '') { - hasStyles++; - } - }); - expect(hasStyles).toBe(1); - done(); - }); - }); - - describe('limits', () => { - - it('lines are not displayed by default', () => { - let limitEl = element.querySelectorAll(".js-limit-area hr"); - expect(limitEl.length).toBe(0); - }); - - it('lines are displayed when configuration is set to true', (done) => { - config.series.models[0].set('limitLines', true); - - Vue.nextTick(() => { - let limitEl = element.querySelectorAll(".js-limit-area .js-limit-line"); - expect(limitEl.length).toBe(4); - done(); - }); - - }); - }); - }); - describe('the inspector view', () => { let component; let viewComponentObject; @@ -955,6 +606,7 @@ describe("the plugin", function () { ] ]; + openmct.router.path = [testTelemetryObject]; mockComposition = new EventEmitter(); mockComposition.load = () => { mockComposition.emit('add', testTelemetryObject); @@ -993,6 +645,10 @@ describe("the plugin", function () { }); }); + afterEach(() => { + openmct.router.path = null; + }); + describe('in view only mode', () => { let browseOptionsEl; let editOptionsEl; @@ -1096,5 +752,24 @@ describe("the plugin", function () { expect(colorSwatch).toBeDefined(); }); }); + + describe('limits', () => { + + it('lines are not displayed by default', () => { + let limitEl = element.querySelectorAll(".js-limit-area .js-limit-line"); + expect(limitEl.length).toBe(0); + }); + + xit('lines are displayed when configuration is set to true', (done) => { + config.series.models[0].set('limitLines', true); + + Vue.nextTick(() => { + let limitEl = element.querySelectorAll(".js-limit-area .js-limit-line"); + expect(limitEl.length).toBe(4); + done(); + }); + + }); + }); }); }); diff --git a/src/plugins/plot/stackedPlot/StackedPlot.vue b/src/plugins/plot/stackedPlot/StackedPlot.vue index 1d409d1990..da207d1500 100644 --- a/src/plugins/plot/stackedPlot/StackedPlot.vue +++ b/src/plugins/plot/stackedPlot/StackedPlot.vue @@ -21,21 +21,37 @@ -->