mirror of
https://github.com/nasa/openmct.git
synced 2025-01-18 02:39:56 +00:00
Plots limit lines (#3882)
This commit is contained in:
parent
5fafde5f23
commit
8274c23129
@ -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;
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -43,15 +43,15 @@ export default function LADTableSetViewProvider(openmct) {
|
||||
components: {
|
||||
LadTableSet: LadTableSet
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
objectPath
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
domainObject
|
||||
};
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
objectPath
|
||||
},
|
||||
template: '<lad-table-set :domain-object="domainObject"></lad-table-set>'
|
||||
});
|
||||
},
|
||||
|
@ -28,6 +28,7 @@
|
||||
:series="config.series.models"
|
||||
:highlights="highlights"
|
||||
:legend="config.legend"
|
||||
@legendHoverChanged="legendHoverChanged"
|
||||
/>
|
||||
<div class="plot-wrapper-axis-and-display-area flex-elem grows">
|
||||
<y-axis v-if="config.series.models.length > 0"
|
||||
@ -67,6 +68,7 @@
|
||||
>
|
||||
<mct-chart :rectangles="rectangles"
|
||||
:highlights="highlights"
|
||||
:show-limit-line-labels="showLimitLineLabels"
|
||||
@plotReinitializeCanvas="initCanvas"
|
||||
/>
|
||||
</div>
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
46
src/plugins/plot/chart/LimitLabel.vue
Normal file
46
src/plugins/plot/chart/LimitLabel.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div class="plot-series-limit-label"
|
||||
:style="styleObj"
|
||||
:class="limit.cssClass"
|
||||
>
|
||||
<span class="plot-series-limit-value">{{ limit.value }}</span>
|
||||
<span class="plot-series-color-swatch"
|
||||
:style="{ 'background-color': limit.color }"
|
||||
></span>
|
||||
<span class="plot-series-name">{{ limit.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
limit: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
point: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
styleObj() {
|
||||
const top = `${this.point.top - 10}px`;
|
||||
const left = `${this.point.left + 5}px`;
|
||||
|
||||
return {
|
||||
'position': 'absolute',
|
||||
'top': top,
|
||||
'left': left,
|
||||
'color': '#fff'
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
44
src/plugins/plot/chart/LimitLine.vue
Normal file
44
src/plugins/plot/chart/LimitLine.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<hr :style="styleObj"
|
||||
:class="cssWithoutUprLwr"
|
||||
>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
point: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
cssClass: {
|
||||
type: String,
|
||||
default() {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
styleObj() {
|
||||
const top = `${this.point.top}px`;
|
||||
const left = `${this.point.left}px`;
|
||||
|
||||
return {
|
||||
'position': 'absolute',
|
||||
'width': '100%',
|
||||
'top': top,
|
||||
'left': left
|
||||
};
|
||||
},
|
||||
cssWithoutUprLwr() {
|
||||
let cssClass = this.cssClass.replace(/is-limit--upr/gi, 'is-limit--line');
|
||||
cssClass = cssClass.replace(/is-limit--lwr/gi, 'is-limit--line');
|
||||
|
||||
return cssClass;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
105
src/plugins/plot/chart/MCTChartAlarmLineSet.js
Normal file
105
src/plugins/plot/chart/MCTChartAlarmLineSet.js
Normal file
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -23,6 +23,9 @@
|
||||
<div class="gl-plot-chart-area">
|
||||
<span v-html="canvasTemplate"></span>
|
||||
<span v-html="canvasTemplate"></span>
|
||||
<div ref="limitArea"
|
||||
class="js-limit-area"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -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() {
|
||||
|
@ -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) {
|
||||
|
@ -60,6 +60,14 @@
|
||||
{{ alarmMarkers ? "Enabled" : "Disabled" }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Display lines visually denoting alarm limits."
|
||||
>Limit lines</div>
|
||||
<div class="grid-cell value">
|
||||
{{ limitLines ? "Enabled" : "Disabled" }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="The plot line and marker color for this series."
|
||||
@ -135,6 +143,9 @@ export default {
|
||||
alarmMarkers() {
|
||||
return this.series.get('alarmMarkers');
|
||||
},
|
||||
limitLines() {
|
||||
return this.series.get('limitLines');
|
||||
},
|
||||
seriesHexColor() {
|
||||
return this.series.get('color').asHexString();
|
||||
}
|
||||
|
@ -91,6 +91,17 @@
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Display limit lines"
|
||||
>Limit lines</div>
|
||||
<div class="grid-cell value">
|
||||
<input v-model="limitLines"
|
||||
type="checkbox"
|
||||
@change="updateForm('limitLines')"
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
<li v-show="markers || alarmMarkers"
|
||||
class="grid-row"
|
||||
>
|
||||
@ -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')
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -48,7 +48,7 @@
|
||||
:highlights="highlights"
|
||||
:value-to-show-when-collapsed="legend.get('valueToShowWhenCollapsed')"
|
||||
:series-object="seriesObject"
|
||||
:closest="seriesObject.closest"
|
||||
@legendHoverChanged="legendHoverChanged"
|
||||
/>
|
||||
</div>
|
||||
<!-- EXPANDED PLOT LEGEND -->
|
||||
@ -89,6 +89,7 @@
|
||||
:series-object="seriesObject"
|
||||
:highlights="highlights"
|
||||
:legend="legend"
|
||||
@legendHoverChanged="legendHoverChanged"
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -160,6 +161,9 @@ export default {
|
||||
expandLegend() {
|
||||
this.isLegendExpanded = !this.isLegendExpanded;
|
||||
this.legend.set('expanded', this.isLegendExpanded);
|
||||
},
|
||||
legendHoverChanged(data) {
|
||||
this.$emit('legendHoverChanged', data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -24,6 +24,8 @@
|
||||
:class="{
|
||||
'is-status--missing': isMissing
|
||||
}"
|
||||
@mouseover="toggleHover(true)"
|
||||
@mouseleave="toggleHover(false)"
|
||||
>
|
||||
<div class="plot-series-swatch-and-name">
|
||||
<span class="plot-series-color-swatch"
|
||||
@ -121,6 +123,12 @@ export default {
|
||||
} else {
|
||||
this.formattedYValueFromStats = '';
|
||||
}
|
||||
},
|
||||
toggleHover(hover) {
|
||||
this.hover = hover;
|
||||
this.$emit('legendHoverChanged', {
|
||||
seriesKey: this.hover ? this.seriesObject.keyString : ''
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -25,6 +25,8 @@
|
||||
:class="{
|
||||
'is-status--missing': isMissing
|
||||
}"
|
||||
@mouseover="toggleHover(true)"
|
||||
@mouseleave="toggleHover(false)"
|
||||
>
|
||||
<td class="plot-series-swatch-and-name">
|
||||
<span class="plot-series-color-swatch"
|
||||
@ -160,6 +162,12 @@ export default {
|
||||
this.formattedMinY = '';
|
||||
this.formattedMaxY = '';
|
||||
}
|
||||
},
|
||||
toggleHover(hover) {
|
||||
this.hover = hover;
|
||||
this.$emit('legendHoverChanged', {
|
||||
seriesKey: this.hover ? this.seriesObject.keyString : ''
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -36,6 +36,7 @@ describe("the plugin", function () {
|
||||
let telemetryPromise;
|
||||
let cleanupFirst;
|
||||
let mockObjectPath;
|
||||
let telemetrylimitProvider;
|
||||
|
||||
beforeEach((done) => {
|
||||
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', () => {
|
||||
|
@ -83,9 +83,9 @@
|
||||
@update="timePopUpdate"
|
||||
/>
|
||||
<button
|
||||
@click="showTimePopupStart"
|
||||
class="c-button c-conductor__delta-button"
|
||||
ref="startOffset"
|
||||
class="c-button c-conductor__delta-button"
|
||||
@click="showTimePopupStart"
|
||||
>
|
||||
{{ offsets.start }}
|
||||
</button>
|
||||
@ -135,7 +135,7 @@
|
||||
class="c-button c-conductor__delta-button"
|
||||
@click="showTimePopupEnd"
|
||||
>
|
||||
{{offsets.end}}
|
||||
{{ offsets.end }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user