diff --git a/src/plugins/plot/res/templates/mct-plot.html b/src/plugins/plot/res/templates/mct-plot.html
index 2f275a9cb8..f0d9e4a616 100644
--- a/src/plugins/plot/res/templates/mct-plot.html
+++ b/src/plugins/plot/res/templates/mct-plot.html
@@ -240,9 +240,9 @@
-
+
-
+
{{ xAxis.get('label') }}
+
+
diff --git a/src/plugins/plot/src/chart/MCTChartController.js b/src/plugins/plot/src/chart/MCTChartController.js
index 096af92aa8..c7899311bc 100644
--- a/src/plugins/plot/src/chart/MCTChartController.js
+++ b/src/plugins/plot/src/chart/MCTChartController.js
@@ -66,7 +66,6 @@ function (
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.xAxis, 'change:key', this.clearOffset, this);
this.listenTo(this.config.yAxis, 'change', this.scheduleDraw);
this.listenTo(this.config.xAxis, 'change', this.scheduleDraw);
this.$scope.$watch('highlights', this.scheduleDraw);
@@ -79,7 +78,14 @@ function (
MCTChartController.$inject = ['$scope'];
+ MCTChartController.prototype.reDraw = function (mode, o, series) {
+ this.changeInterpolate(mode, o, series);
+ this.changeMarkers(mode, o, series);
+ this.changeAlarmMarkers(mode, o, series);
+ };
+
MCTChartController.prototype.onSeriesAdd = function (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);
diff --git a/src/plugins/plot/src/configuration/PlotSeries.js b/src/plugins/plot/src/configuration/PlotSeries.js
index 4225a695fb..ab52dd11d3 100644
--- a/src/plugins/plot/src/configuration/PlotSeries.js
+++ b/src/plugins/plot/src/configuration/PlotSeries.js
@@ -428,6 +428,19 @@ define([
this.filters = deepCopiedFilters;
}
},
+ getDisplayRange: function (xKey) {
+ const unsortedData = this.data;
+ this.data = [];
+ unsortedData.forEach(point => this.add(point, false));
+
+ const minValue = this.getXVal(this.data[0]);
+ const maxValue = this.getXVal(this.data[this.data.length - 1]);
+
+ return {
+ min: minValue,
+ max: maxValue
+ };
+ },
markerOptionsDisplayText: function () {
const showMarkers = this.get('markers');
if (!showMarkers) {
diff --git a/src/plugins/plot/src/configuration/XAxisModel.js b/src/plugins/plot/src/configuration/XAxisModel.js
index bbd99aff30..ccdfdde252 100644
--- a/src/plugins/plot/src/configuration/XAxisModel.js
+++ b/src/plugins/plot/src/configuration/XAxisModel.js
@@ -49,6 +49,7 @@ define([
}
this.listenTo(this, 'change:key', this.changeKey, this);
+ this.listenTo(this, 'resetSeries', this.resetSeries, this);
},
changeKey: function (newKey) {
const series = this.plot.series.first();
@@ -66,6 +67,10 @@ define([
this.plot.series.forEach(function (plotSeries) {
plotSeries.set('xKey', newKey);
+ });
+ },
+ resetSeries: function () {
+ this.plot.series.forEach(function (plotSeries) {
plotSeries.reset();
});
},
diff --git a/src/plugins/plot/src/plot/MCTPlotController.js b/src/plugins/plot/src/plot/MCTPlotController.js
index 904c27ee9b..5f66e0b3eb 100644
--- a/src/plugins/plot/src/plot/MCTPlotController.js
+++ b/src/plugins/plot/src/plot/MCTPlotController.js
@@ -102,12 +102,32 @@ define([
this.listenTo(this.$scope, 'plot:tickWidth', this.onTickWidthChange, this);
this.listenTo(this.$scope, 'plot:highlight:set', this.onPlotHighlightSet, this);
this.listenTo(this.$scope, 'plot:reinitializeCanvas', this.initCanvas, this);
+ this.listenTo(this.config.xAxis, 'resetSeries', this.setUpXAxisOptions, this);
this.listenTo(this.config.xAxis, 'change:displayRange', this.onXAxisChange, this);
this.listenTo(this.config.yAxis, 'change:displayRange', this.onYAxisChange, this);
+ this.setUpXAxisOptions();
this.setUpYAxisOptions();
};
+ MCTPlotController.prototype.setUpXAxisOptions = function () {
+ const xAxisKey = this.config.xAxis.get('key');
+
+ if (this.$scope.series.length === 1) {
+ let metadata = this.$scope.series[0].metadata;
+
+ this.$scope.xKeyOptions = metadata
+ .valuesForHints(['domain'])
+ .map(function (o) {
+ return {
+ name: o.name,
+ key: o.key
+ };
+ });
+ this.$scope.selectedXKeyOption = this.getXKeyOption(xAxisKey);
+ }
+ };
+
MCTPlotController.prototype.setUpYAxisOptions = function () {
if (this.$scope.series.length === 1) {
let metadata = this.$scope.series[0].metadata;
@@ -534,6 +554,32 @@ define([
this.cursorGuide = !this.cursorGuide;
};
+ MCTPlotController.prototype.getXKeyOption = function (key) {
+ return this.$scope.xKeyOptions.find(option => option.key === key);
+ };
+
+ MCTPlotController.prototype.isEnabledXKeyToggle = function () {
+ const isSinglePlot = this.$scope.xKeyOptions && this.$scope.xKeyOptions.length > 1 && this.$scope.series.length === 1;
+ const isFrozen = this.config.xAxis.get('frozen');
+ const inRealTimeMode = this.config.openmct.time.clock();
+
+ return isSinglePlot && !isFrozen && !inRealTimeMode;
+ };
+
+ MCTPlotController.prototype.toggleXKeyOption = function (lastXKey, series) {
+ const selectedXKey = this.$scope.selectedXKeyOption.key;
+ const dataForSelectedXKey = series.data
+ ? series.data[0][selectedXKey]
+ : undefined;
+
+ if (dataForSelectedXKey !== undefined) {
+ this.config.xAxis.set('key', selectedXKey);
+ } else {
+ this.config.openmct.notifications.error('Cannot change x-axis view as no data exists for this view type.');
+ this.$scope.selectedXKeyOption.key = lastXKey;
+ }
+ };
+
MCTPlotController.prototype.toggleYAxisLabel = function (label, options, series) {
let yAxisObject = options.filter(o => o.name === label)[0];
diff --git a/src/plugins/plot/src/plot/MCTTicksController.js b/src/plugins/plot/src/plot/MCTTicksController.js
index 31258158ae..ffcb0ce935 100644
--- a/src/plugins/plot/src/plot/MCTTicksController.js
+++ b/src/plugins/plot/src/plot/MCTTicksController.js
@@ -126,6 +126,7 @@ define([
this.tickUpdate = false;
this.listenTo(this.axis, 'change:displayRange', this.updateTicks, this);
this.listenTo(this.axis, 'change:format', this.updateTicks, this);
+ this.listenTo(this.axis, 'change:key', this.updateTicksForceRegeneration, this);
this.listenTo(this.$scope, '$destroy', this.stopListening, this);
this.updateTicks();
};
@@ -137,12 +138,19 @@ define([
/**
* Determine whether ticks should be regenerated for a given range.
- * Ticks are updated a) if they don't exist, b) if the existing ticks are
- * outside of given range, or c) if the range exceeds the size of the tick
- * range by more than one tick step.
+ * Ticks are updated
+ * a) if they don't exist,
+ * b) if existing ticks are outside of given range,
+ * c) if range exceeds size of tick range by more than one tick step,
+ * d) if forced to regenerate (ex. changing x-axis metadata).
+ *
* @private
*/
- MCTTicksController.prototype.shouldRegenerateTicks = function (range) {
+ MCTTicksController.prototype.shouldRegenerateTicks = function (range, forceRegeneration) {
+ if (forceRegeneration) {
+ return true;
+ }
+
if (!this.tickRange || !this.$scope.ticks || !this.$scope.ticks.length) {
return true;
}
@@ -175,7 +183,11 @@ define([
return ticks(range.min, range.max, number);
};
- MCTTicksController.prototype.updateTicks = function () {
+ MCTTicksController.prototype.updateTicksForceRegeneration = function () {
+ this.updateTicks(true);
+ };
+
+ MCTTicksController.prototype.updateTicks = function (forceRegeneration = false) {
const range = this.axis.get('displayRange');
if (!range) {
delete this.$scope.min;
@@ -196,7 +208,7 @@ define([
this.$scope.min = range.min;
this.$scope.max = range.max;
this.$scope.interval = Math.abs(range.min - range.max);
- if (this.shouldRegenerateTicks(range)) {
+ if (this.shouldRegenerateTicks(range, forceRegeneration)) {
let newTicks = this.getTicks();
this.tickRange = {
min: Math.min.apply(Math, newTicks),
diff --git a/src/plugins/plot/src/telemetry/PlotController.js b/src/plugins/plot/src/telemetry/PlotController.js
index 2981275aa4..3536f82434 100644
--- a/src/plugins/plot/src/telemetry/PlotController.js
+++ b/src/plugins/plot/src/telemetry/PlotController.js
@@ -90,7 +90,7 @@ define([
PlotController.prototype.followTimeConductor = function () {
this.listenTo(this.openmct.time, 'bounds', this.updateDisplayBounds, this);
- this.listenTo(this.openmct.time, 'timeSystem', this.onTimeSystemChange, this);
+ this.listenTo(this.openmct.time, 'timeSystem', this.syncXAxisToTimeSystem, this);
this.synchronized(true);
};
@@ -134,6 +134,9 @@ define([
};
PlotController.prototype.addSeries = function (series) {
+ this.listenTo(series, 'change:xKey', (xKey) => {
+ this.setDisplayRange(series, xKey);
+ }, this);
this.listenTo(series, 'change:yKey', () => {
this.loadSeriesData(series);
}, this);
@@ -145,6 +148,15 @@ define([
this.loadSeriesData(series);
};
+ PlotController.prototype.setDisplayRange = function (series, xKey) {
+ if (this.config.series.models.length !== 1) {
+ return;
+ }
+
+ const displayRange = series.getDisplayRange(xKey);
+ this.config.xAxis.set('range', displayRange);
+ };
+
PlotController.prototype.removeSeries = function (plotSeries) {
this.stopListening(plotSeries);
};
@@ -165,8 +177,9 @@ define([
return config;
};
- PlotController.prototype.onTimeSystemChange = function (timeSystem) {
+ PlotController.prototype.syncXAxisToTimeSystem = function (timeSystem) {
this.config.xAxis.set('key', timeSystem.key);
+ this.config.xAxis.emit('resetSeries');
};
PlotController.prototype.destroy = function () {
@@ -189,7 +202,8 @@ define([
plotSeries.load({
size: this.$element[0].offsetWidth,
start: range.min,
- end: range.max
+ end: range.max,
+ domain: this.config.xAxis.get('key')
})
.then(this.stopLoading());
if (purge) {
@@ -202,10 +216,18 @@ define([
* Track latest display bounds. Forces update when not receiving ticks.
*/
PlotController.prototype.updateDisplayBounds = function (bounds, isTick) {
+
+ const xAxisKey = this.config.xAxis.get('key');
+ const timeSystem = this.openmct.time.timeSystem();
const newRange = {
min: bounds.start,
max: bounds.end
};
+
+ if (xAxisKey !== timeSystem.key) {
+ this.syncXAxisToTimeSystem(timeSystem);
+ }
+
this.config.xAxis.set('range', newRange);
if (!isTick) {
this.skipReloadOnInteraction = true;
diff --git a/src/styles/_legacy-plots.scss b/src/styles/_legacy-plots.scss
index 8b28ec8bcb..9986c5bfc5 100644
--- a/src/styles/_legacy-plots.scss
+++ b/src/styles/_legacy-plots.scss
@@ -27,7 +27,7 @@ mct-plot {
/*********************** STACKED PLOT LAYOUT */
.is-editing {
.gl-plot.child-frame {
- &:hover {
+ @include hover {
background: rgba($editUIColorBg, 0.1);
box-shadow: inset rgba($editUIColorBg, 0.3) 0 0 0 1px;
}
@@ -52,6 +52,7 @@ mct-plot {
.c-control-bar {
display: none;
}
+ .gl-plot-x-label__select,
.gl-plot-y-label__select {
display: none;
}
@@ -172,6 +173,14 @@ mct-plot {
}
}
}
+
+ &.gl-plot-x {
+ @include hover {
+ .gl-plot-x-label__select {
+ display: block;
+ }
+ }
+ }
}
.gl-plot-coords {
@@ -217,11 +226,19 @@ mct-plot {
}
}
+ .gl-plot-x-label__select {
+ position: absolute;
+ left: 50%;
+ bottom: 0;
+ transform: translateX(-50%);
+ z-index: 10;
+ }
+
.gl-plot-y-label__select {
position: absolute;
top: 50%;
transform: translateY(-50%);
- left: 20px;
+ left: 0;
z-index: 10;
}