From 8274c23129b360537d6fb8cf4bd6b12ab515c3a8 Mon Sep 17 00:00:00 2001 From: Shefali Joshi Date: Fri, 28 May 2021 14:51:29 -0700 Subject: [PATCH] Plots limit lines (#3882) --- example/generator/SinewaveLimitProvider.js | 31 ++++ src/adapter/runs/LegacyTelemetryProvider.js | 16 ++ src/api/telemetry/TelemetryAPI.js | 57 +++++++ .../LADTable/LADTableSetViewProvider.js | 8 +- src/plugins/plot/MctPlot.vue | 8 +- src/plugins/plot/chart/LimitLabel.vue | 46 ++++++ src/plugins/plot/chart/LimitLine.vue | 44 +++++ .../plot/chart/MCTChartAlarmLineSet.js | 105 ++++++++++++ src/plugins/plot/chart/MctChart.vue | 153 +++++++++++++++++- src/plugins/plot/configuration/PlotSeries.js | 10 +- .../plot/inspector/PlotOptionsItem.vue | 11 ++ .../plot/inspector/forms/SeriesForm.vue | 17 ++ src/plugins/plot/legend/PlotLegend.vue | 6 +- .../plot/legend/PlotLegendItemCollapsed.vue | 8 + .../plot/legend/PlotLegendItemExpanded.vue | 8 + src/plugins/plot/pluginSpec.js | 63 +++++++- src/plugins/timeConductor/Conductor.vue | 6 +- src/styles/_legacy-plots.scss | 2 +- src/styles/_status.scss | 6 + 19 files changed, 586 insertions(+), 19 deletions(-) create mode 100644 src/plugins/plot/chart/LimitLabel.vue create mode 100644 src/plugins/plot/chart/LimitLine.vue create mode 100644 src/plugins/plot/chart/MCTChartAlarmLineSet.js diff --git a/example/generator/SinewaveLimitProvider.js b/example/generator/SinewaveLimitProvider.js index 4bf6aca56f..7f0a344cfb 100644 --- a/example/generator/SinewaveLimitProvider.js +++ b/example/generator/SinewaveLimitProvider.js @@ -93,5 +93,36 @@ define([ }; }; + SinewaveLimitProvider.prototype.getLimits = function (domainObject) { + return { + limits: function () { + return { + WARNING: { + low: { + cssClass: "is-limit--lwr is-limit--yellow", + sin: -YELLOW.sin, + cos: -YELLOW.cos + }, + high: { + cssClass: "is-limit--upr is-limit--yellow", + ...YELLOW + } + }, + DISTRESS: { + low: { + cssClass: "is-limit--lwr is-limit--red", + sin: -RED.sin, + cos: -RED.cos + }, + high: { + cssClass: "is-limit--upr is-limit--red", + ...RED + } + } + }; + } + }; + }; + return SinewaveLimitProvider; }); diff --git a/src/adapter/runs/LegacyTelemetryProvider.js b/src/adapter/runs/LegacyTelemetryProvider.js index 9367aace24..8f976d4ec9 100644 --- a/src/adapter/runs/LegacyTelemetryProvider.js +++ b/src/adapter/runs/LegacyTelemetryProvider.js @@ -161,6 +161,22 @@ define([ evaluate: function (datum, property) { return limitEvaluator.evaluate(datum, property && property.key); } + + }; + }; + + LegacyTelemetryProvider.prototype.getLimits = function (domainObject) { + const oldObject = this.instantiate( + utils.toOldFormat(domainObject), + utils.makeKeyString(domainObject.identifier) + ); + const limitEvaluator = oldObject.getCapability("limit"); + + return { + limits: function () { + return limitEvaluator.limits(); + } + }; }; diff --git a/src/api/telemetry/TelemetryAPI.js b/src/api/telemetry/TelemetryAPI.js index 2fb7d6994a..be952466e4 100644 --- a/src/api/telemetry/TelemetryAPI.js +++ b/src/api/telemetry/TelemetryAPI.js @@ -504,6 +504,26 @@ define([ return this.getLimitEvaluator(domainObject); }; + /** + * Get a limits for this domain object. + * Limits help you display limits and alarms of + * telemetry for display purposes without having to interact directly + * with the Limit API. + * + * This method is optional. + * If a provider does not implement this method, it is presumed + * that no limits are defined for this domain object's telemetry. + * + * @param {module:openmct.DomainObject} domainObject the domain + * object for which to get limits + * @returns {module:openmct.TelemetryAPI~LimitEvaluator} + * @method limits + * @memberof module:openmct.TelemetryAPI~TelemetryProvider# + */ + TelemetryAPI.prototype.limitDefinition = function (domainObject) { + return this.getLimits(domainObject); + }; + /** * Get a limit evaluator for this domain object. * Limit Evaluators help you evaluate limit and alarm status of individual @@ -531,5 +551,42 @@ define([ return provider.getLimitEvaluator(domainObject); }; + /** + * Get a limit definitions for this domain object. + * Limit Definitions help you indicate limits and alarms of + * telemetry for display purposes without having to interact directly + * with the Limit API. + * + * This method is optional. + * If a provider does not implement this method, it is presumed + * that no limits are defined for this domain object's telemetry. + * + * @param {module:openmct.DomainObject} domainObject the domain + * object for which to display limits + * @returns {module:openmct.TelemetryAPI~LimitEvaluator} + * @method limits returns a limits object of + * type { + * level1: { + * low: { key1: value1, key2: value2 }, + * high: { key1: value1, key2: value2 } + * }, + * level2: { + * low: { key1: value1, key2: value2 }, + * high: { key1: value1, key2: value2 } + * } + * } + * @memberof module:openmct.TelemetryAPI~TelemetryProvider# + */ + TelemetryAPI.prototype.getLimits = function (domainObject) { + const provider = this.findLimitEvaluator(domainObject); + if (!provider) { + return { + limits: function () {} + }; + } + + return provider.getLimits(domainObject); + }; + return TelemetryAPI; }); diff --git a/src/plugins/LADTable/LADTableSetViewProvider.js b/src/plugins/LADTable/LADTableSetViewProvider.js index 6e19c7066a..2a47e4f4c6 100644 --- a/src/plugins/LADTable/LADTableSetViewProvider.js +++ b/src/plugins/LADTable/LADTableSetViewProvider.js @@ -43,15 +43,15 @@ export default function LADTableSetViewProvider(openmct) { components: { LadTableSet: LadTableSet }, + provide: { + openmct, + objectPath + }, data() { return { domainObject }; }, - provide: { - openmct, - objectPath - }, template: '' }); }, diff --git a/src/plugins/plot/MctPlot.vue b/src/plugins/plot/MctPlot.vue index 9f26ddcb84..0033065b37 100644 --- a/src/plugins/plot/MctPlot.vue +++ b/src/plugins/plot/MctPlot.vue @@ -28,6 +28,7 @@ :series="config.series.models" :highlights="highlights" :legend="config.legend" + @legendHoverChanged="legendHoverChanged" />
@@ -213,7 +215,8 @@ export default { pending: 0, isRealTime: this.openmct.time.clock() !== undefined, loaded: false, - isTimeOutOfSync: false + isTimeOutOfSync: false, + showLimitLineLabels: undefined }; }, computed: { @@ -1018,6 +1021,9 @@ export default { this.offsetWidth = this.$parent.$refs.plotWrapper.offsetWidth; this.config.series.models.forEach(this.loadSeriesData, this); } + }, + legendHoverChanged(data) { + this.showLimitLineLabels = data; } } }; diff --git a/src/plugins/plot/chart/LimitLabel.vue b/src/plugins/plot/chart/LimitLabel.vue new file mode 100644 index 0000000000..73948cf4fe --- /dev/null +++ b/src/plugins/plot/chart/LimitLabel.vue @@ -0,0 +1,46 @@ + + + diff --git a/src/plugins/plot/chart/LimitLine.vue b/src/plugins/plot/chart/LimitLine.vue new file mode 100644 index 0000000000..c2e682784e --- /dev/null +++ b/src/plugins/plot/chart/LimitLine.vue @@ -0,0 +1,44 @@ + + + diff --git a/src/plugins/plot/chart/MCTChartAlarmLineSet.js b/src/plugins/plot/chart/MCTChartAlarmLineSet.js new file mode 100644 index 0000000000..c7549461eb --- /dev/null +++ b/src/plugins/plot/chart/MCTChartAlarmLineSet.js @@ -0,0 +1,105 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, 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 eventHelpers from '../lib/eventHelpers'; + +export default class MCTChartAlarmLineSet { + constructor(series, chart, offset, bounds) { + this.series = series; + this.chart = chart; + this.offset = offset; + this.bounds = bounds; + this.limits = []; + + eventHelpers.extend(this); + this.listenTo(series, 'limitBounds', this.updateBounds, this); + this.listenTo(series, 'change:xKey', this.getLimitPoints, this); + + if (series.limits) { + this.getLimitPoints(series); + } + } + + updateBounds(bounds) { + this.bounds = bounds; + this.getLimitPoints(this.series); + } + + color() { + return this.series.get('color'); + } + + name() { + return this.series.get('name'); + } + + makePoint(point, series) { + if (!this.offset.xVal) { + this.chart.setOffset(point, undefined, series); + } + + return { + x: this.offset.xVal(point, series), + y: this.offset.yVal(point, series) + }; + } + + getLimitPoints(series) { + this.limits = []; + let xKey = series.get('xKey'); + Object.keys(series.limits).forEach((key) => { + const limitForLevel = series.limits[key]; + if (limitForLevel.high) { + const point = this.makePoint(Object.assign({ [xKey]: this.bounds.start }, limitForLevel.high), series); + this.limits.push({ + seriesKey: series.keyString, + value: series.getYVal(limitForLevel.high), + color: this.color().asHexString(), + name: this.name(), + point, + cssClass: limitForLevel.high.cssClass + }); + } + + if (limitForLevel.low) { + const point = this.makePoint(Object.assign({ [xKey]: this.bounds.start }, limitForLevel.low), series); + this.limits.push({ + seriesKey: series.keyString, + value: series.getYVal(limitForLevel.low), + color: this.color().asHexString(), + name: this.name(), + point, + cssClass: limitForLevel.low.cssClass + }); + } + }, this); + } + + reset() { + this.limits = []; + } + + destroy() { + this.stopListening(); + } + +} diff --git a/src/plugins/plot/chart/MctChart.vue b/src/plugins/plot/chart/MctChart.vue index c991357385..a303e707f8 100644 --- a/src/plugins/plot/chart/MctChart.vue +++ b/src/plugins/plot/chart/MctChart.vue @@ -23,6 +23,9 @@
+
@@ -34,8 +37,12 @@ import MCTChartLineLinear from './MCTChartLineLinear'; import MCTChartLineStepAfter from './MCTChartLineStepAfter'; import MCTChartPointSet from './MCTChartPointSet'; import MCTChartAlarmPointSet from './MCTChartAlarmPointSet'; +import MCTChartAlarmLineSet from "./MCTChartAlarmLineSet"; import configStore from "../configuration/configStore"; import PlotConfigurationModel from "../configuration/PlotConfigurationModel"; +import LimitLine from "./LimitLine.vue"; +import LimitLabel from "./LimitLabel.vue"; +import Vue from 'vue'; const MARKER_SIZE = 6.0; const HIGHLIGHT_SIZE = MARKER_SIZE * 2.0; @@ -54,6 +61,12 @@ export default { default() { return []; } + }, + showLimitLineLabels: { + type: Object, + default() { + return {}; + } } }, data() { @@ -67,18 +80,22 @@ export default { }, rectangles() { this.scheduleDraw(); + }, + showLimitLineLabels() { + this.drawLimitLines(); } }, mounted() { eventHelpers.extend(this); - this.config = this.getConfig(); this.isDestroyed = false; this.lines = []; + this.limitLines = []; this.pointSets = []; this.alarmSets = []; this.offset = {}; this.seriesElements = new WeakMap(); + this.seriesLimits = new WeakMap(); let canvasEls = this.$parent.$refs.chartContainer.querySelectorAll("canvas"); const mainCanvas = canvasEls[1]; @@ -90,8 +107,8 @@ export default { this.listenTo(this.config.series, 'add', this.onSeriesAdd, this); this.listenTo(this.config.series, 'remove', this.onSeriesRemove, this); this.listenTo(this.config.yAxis, 'change:key', this.clearOffset, this); - this.listenTo(this.config.yAxis, 'change', this.scheduleDraw); - this.listenTo(this.config.xAxis, 'change', this.scheduleDraw); + this.listenTo(this.config.yAxis, 'change', this.updateLimitsAndDraw); + this.listenTo(this.config.xAxis, 'change', this.updateLimitsAndDraw); this.config.series.forEach(this.onSeriesAdd, this); }, beforeDestroy() { @@ -116,15 +133,18 @@ export default { this.changeInterpolate(mode, o, series); this.changeMarkers(mode, o, series); this.changeAlarmMarkers(mode, o, series); + this.changeLimitLines(mode, o, series); }, onSeriesAdd(series) { this.listenTo(series, 'change:xKey', this.reDraw, this); this.listenTo(series, 'change:interpolate', this.changeInterpolate, this); this.listenTo(series, 'change:markers', this.changeMarkers, this); this.listenTo(series, 'change:alarmMarkers', this.changeAlarmMarkers, this); + this.listenTo(series, 'change:limitLines', this.changeLimitLines, this); this.listenTo(series, 'change', this.scheduleDraw); this.listenTo(series, 'add', this.scheduleDraw); this.makeChartElement(series); + this.makeLimitLines(series); }, changeInterpolate(mode, o, series) { if (mode === o) { @@ -178,6 +198,14 @@ export default { this.pointSets.push(pointSet); } }, + changeLimitLines(mode, o, series) { + if (mode === o) { + return; + } + + this.makeLimitLines(series); + this.updateLimitsAndDraw(); + }, onSeriesRemove(series) { this.stopListening(series); this.removeChartElement(series); @@ -187,6 +215,7 @@ export default { this.isDestroyed = true; this.stopListening(); this.lines.forEach(line => line.destroy()); + this.limitLines.forEach(line => line.destroy()); DrawLoader.releaseDrawAPI(this.drawAPI); }, clearOffset() { @@ -199,6 +228,9 @@ export default { this.lines.forEach(function (line) { line.reset(); }); + this.limitLines.forEach(function (line) { + line.reset(); + }); this.pointSets.forEach(function (pointSet) { pointSet.reset(); }); @@ -269,6 +301,8 @@ export default { } this.seriesElements.delete(series); + + this.clearLimitLines(series); }, lineForSeries(series) { if (series.get('interpolate') === 'linear') { @@ -287,6 +321,14 @@ export default { ); } }, + limitLineForSeries(series) { + return new MCTChartAlarmLineSet( + series, + this, + this.offset, + this.openmct.time.bounds() + ); + }, pointSetForSeries(series) { if (series.get('markers')) { return new MCTChartPointSet( @@ -308,7 +350,8 @@ export default { makeChartElement(series) { const elements = { lines: [], - pointSets: [] + pointSets: [], + limitLines: [] }; const line = this.lineForSeries(series); @@ -330,6 +373,37 @@ export default { this.seriesElements.set(series, elements); }, + makeLimitLines(series) { + this.clearLimitLines(series); + + if (!series.get('limitLines')) { + return; + } + + const limitElements = { + limitLines: [] + }; + + const limitLine = this.limitLineForSeries(series); + if (limitLine) { + limitElements.limitLines.push(limitLine); + this.limitLines.push(limitLine); + } + + this.seriesLimits.set(series, limitElements); + }, + clearLimitLines(series) { + const seriesLimits = this.seriesLimits.get(series); + + if (seriesLimits) { + seriesLimits.limitLines.forEach(function (line) { + this.limitLines.splice(this.limitLines.indexOf(line), 1); + line.destroy(); + }, this); + + this.seriesLimits.delete(series); + } + }, canDraw() { if (!this.offset.x || !this.offset.y) { return false; @@ -337,6 +411,10 @@ export default { return true; }, + updateLimitsAndDraw() { + this.drawLimitLines(); + this.scheduleDraw(); + }, scheduleDraw() { if (!this.drawScheduled) { requestAnimationFrame(this.draw); @@ -385,6 +463,68 @@ export default { this.pointSets.forEach(this.drawPoints, this); this.alarmSets.forEach(this.drawAlarmPoints, this); }, + drawLimitLines() { + if (this.canDraw()) { + this.updateViewport(); + + if (!this.drawAPI.origin) { + return; + } + + Array.from(this.$refs.limitArea.children).forEach((el) => el.remove()); + + this.limitLines.forEach((limitLine) => { + let limitContainerEl = this.$refs.limitArea; + limitLine.limits.forEach((limit) => { + const showLabels = this.showLabels(limit.seriesKey); + if (showLabels) { + let limitLabelEl = this.getLimitLabel(limit); + limitContainerEl.appendChild(limitLabelEl); + } + + let limitEl = this.getLimitElement(limit); + limitContainerEl.appendChild(limitEl); + + }, this); + }); + } + }, + showLabels(seriesKey) { + return this.showLimitLineLabels.seriesKey + && (this.showLimitLineLabels.seriesKey === seriesKey); + }, + getLimitElement(limit) { + let point = { + left: 0, + top: this.drawAPI.y(limit.point.y) + }; + let LimitLineClass = Vue.extend(LimitLine); + const component = new LimitLineClass({ + propsData: { + point, + cssClass: limit.cssClass + } + }); + component.$mount(); + + return component.$el; + }, + getLimitLabel(limit) { + let point = { + left: 0, + top: this.drawAPI.y(limit.point.y) + }; + let LimitLabelClass = Vue.extend(LimitLabel); + const component = new LimitLabelClass({ + propsData: { + limit, + point + } + }); + component.$mount(); + + return component.$el; + }, drawAlarmPoints(alarmSet) { this.drawAPI.drawLimitPoints( alarmSet.points, @@ -401,11 +541,12 @@ export default { chartElement.series.get('markerShape') ); }, - drawLine(chartElement) { + drawLine(chartElement, disconnected) { this.drawAPI.drawLine( chartElement.getBuffer(), chartElement.color().asRGBAArray(), - chartElement.count + chartElement.count, + disconnected ); }, drawHighlights() { diff --git a/src/plugins/plot/configuration/PlotSeries.js b/src/plugins/plot/configuration/PlotSeries.js index 0d594ec939..8dd072da02 100644 --- a/src/plugins/plot/configuration/PlotSeries.js +++ b/src/plugins/plot/configuration/PlotSeries.js @@ -97,7 +97,8 @@ export default class PlotSeries extends Model { markers: true, markerShape: 'point', markerSize: 2.0, - alarmMarkers: true + alarmMarkers: true, + limitLines: false }; } @@ -115,9 +116,16 @@ export default class PlotSeries extends Model { this.domainObject = options.domainObject; this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier); this.limitEvaluator = this.openmct.telemetry.limitEvaluator(options.domainObject); + this.limitDefinition = this.openmct.telemetry.limitDefinition(options.domainObject); + this.limits = this.limitDefinition.limits(); + this.openmct.time.on('bounds', this.updateLimits); this.on('destroy', this.onDestroy, this); } + updateLimits(bounds) { + this.emit('limitBounds', bounds); + } + locateOldObject(oldStyleParent) { return oldStyleParent.useCapability('composition') .then(function (children) { diff --git a/src/plugins/plot/inspector/PlotOptionsItem.vue b/src/plugins/plot/inspector/PlotOptionsItem.vue index fc60309b7c..42684ae9d4 100644 --- a/src/plugins/plot/inspector/PlotOptionsItem.vue +++ b/src/plugins/plot/inspector/PlotOptionsItem.vue @@ -60,6 +60,14 @@ {{ alarmMarkers ? "Enabled" : "Disabled" }} +
  • +
    Limit lines
    +
    + {{ limitLines ? "Enabled" : "Disabled" }} +
    +
  • +
  • +
    Limit lines
    +
    + +
    +
  • @@ -168,6 +179,7 @@ export default { markers: this.series.get('markers'), markerShape: this.series.get('markerShape'), alarmMarkers: this.series.get('alarmMarkers'), + limitLines: this.series.get('limitLines'), markerSize: this.series.get('markerSize'), validation: {}, swatchActive: false @@ -240,6 +252,11 @@ export default { modelProp: 'alarmMarkers', coerce: Boolean, objectPath: this.dynamicPathForKey('alarmMarkers') + }, + { + modelProp: 'limitLines', + coerce: Boolean, + objectPath: this.dynamicPathForKey('limitLines') } ]; diff --git a/src/plugins/plot/legend/PlotLegend.vue b/src/plugins/plot/legend/PlotLegend.vue index 2e70b53f80..2189f23c64 100644 --- a/src/plugins/plot/legend/PlotLegend.vue +++ b/src/plugins/plot/legend/PlotLegend.vue @@ -48,7 +48,7 @@ :highlights="highlights" :value-to-show-when-collapsed="legend.get('valueToShowWhenCollapsed')" :series-object="seriesObject" - :closest="seriesObject.closest" + @legendHoverChanged="legendHoverChanged" /> @@ -89,6 +89,7 @@ :series-object="seriesObject" :highlights="highlights" :legend="legend" + @legendHoverChanged="legendHoverChanged" /> @@ -160,6 +161,9 @@ export default { expandLegend() { this.isLegendExpanded = !this.isLegendExpanded; this.legend.set('expanded', this.isLegendExpanded); + }, + legendHoverChanged(data) { + this.$emit('legendHoverChanged', data); } } }; diff --git a/src/plugins/plot/legend/PlotLegendItemCollapsed.vue b/src/plugins/plot/legend/PlotLegendItemCollapsed.vue index 01645ded1a..c8b98bb4b6 100644 --- a/src/plugins/plot/legend/PlotLegendItemCollapsed.vue +++ b/src/plugins/plot/legend/PlotLegendItemCollapsed.vue @@ -24,6 +24,8 @@ :class="{ 'is-status--missing': isMissing }" + @mouseover="toggleHover(true)" + @mouseleave="toggleHover(false)" >
    { mockObjectPath = [ @@ -88,6 +89,45 @@ describe("the plugin", function () { return telemetryPromise; }); + telemetrylimitProvider = jasmine.createSpyObj('telemetrylimitProvider', [ + 'supportsLimits', + 'getLimits', + 'getLimitEvaluator' + ]); + telemetrylimitProvider.supportsLimits.and.returnValue(true); + telemetrylimitProvider.getLimits.and.returnValue({ + limits: function () { + return { + WARNING: { + low: { + cssClass: "is-limit--lwr is-limit--yellow", + 'some-key': -0.5 + }, + high: { + cssClass: "is-limit--upr is-limit--yellow", + 'some-key': 0.5 + } + }, + DISTRESS: { + low: { + cssClass: "is-limit--lwr is-limit--red", + 'some-key': -0.9 + }, + high: { + cssClass: "is-limit--upr is-limit--red", + 'some-key': 0.9 + } + } + }; + } + }); + telemetrylimitProvider.getLimitEvaluator.and.returnValue({ + evaluate: function () { + return {}; + } + }); + openmct.telemetry.addProvider(telemetrylimitProvider); + openmct.install(new PlotVuePlugin()); element = document.createElement("div"); @@ -657,6 +697,25 @@ describe("the plugin", function () { 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 hr"); + expect(limitEl.length).toBe(4); + done(); + }); + + }); + }); }); describe('the inspector view', () => { @@ -803,7 +862,7 @@ describe("the plugin", function () { expandControl.dispatchEvent(clickEvent); const plotOptionsProperties = browseOptionsEl.querySelectorAll('.js-plot-options-browse-properties .grid-row'); - expect(plotOptionsProperties.length).toEqual(5); + expect(plotOptionsProperties.length).toEqual(6); }); }); @@ -845,7 +904,7 @@ describe("the plugin", function () { expandControl.dispatchEvent(clickEvent); const plotOptionsProperties = editOptionsEl.querySelectorAll(".js-plot-options-edit-properties .grid-row"); - expect(plotOptionsProperties.length).toEqual(6); + expect(plotOptionsProperties.length).toEqual(7); }); it('shows yKeyOptions', () => { diff --git a/src/plugins/timeConductor/Conductor.vue b/src/plugins/timeConductor/Conductor.vue index 27039b80e2..5e4ddb3cc5 100644 --- a/src/plugins/timeConductor/Conductor.vue +++ b/src/plugins/timeConductor/Conductor.vue @@ -83,9 +83,9 @@ @update="timePopUpdate" /> @@ -135,7 +135,7 @@ class="c-button c-conductor__delta-button" @click="showTimePopupEnd" > - {{offsets.end}} + {{ offsets.end }}
    diff --git a/src/styles/_legacy-plots.scss b/src/styles/_legacy-plots.scss index da5b2f289c..ca856f768d 100644 --- a/src/styles/_legacy-plots.scss +++ b/src/styles/_legacy-plots.scss @@ -531,7 +531,7 @@ mct-plot { } /***************** GENERAL STYLES, ALL STATES */ -.plot-legend-item { +.plot-legend-item, .plot-series-limit-label { // General styles for legend items, both expanded and collapsed legend states > * + * { margin-left: $interiorMarginSm; diff --git a/src/styles/_status.scss b/src/styles/_status.scss index e1a659bace..2f3829d707 100644 --- a/src/styles/_status.scss +++ b/src/styles/_status.scss @@ -70,6 +70,10 @@ &.is-limit--lwr:before { content: $glyph-icon-arrow-down !important; } } +@mixin andLine { + &.is-limit--line:before { content: '' !important; } +} + @mixin uIndicator($bg, $fg, $glyph) { background: $bg; color: $fg; @@ -100,12 +104,14 @@ @include statusStyle($colorLimitYellowBg, $colorLimitYellowFg, true); @include statusIcon($colorLimitYellowIc, $glyph-icon-alert-rect); @include andUprLwr(); + @include andLine(); } &.is-limit--red { @include statusStyle($colorLimitRedBg, $colorLimitRedFg, true); @include statusIcon($colorLimitRedIc, $glyph-icon-alert-triangle); @include andUprLwr(); + @include andLine(); } }