Plot options 4.1 (#2303)

* working crosshairs -- todo -- add toggle option

* add ability to toggle crosshair

* add zoom in by onscreen button to plot

* add zoom out functionality

* switch positions of zoom in and out buttons

* working zoom with mousewheel

* add better logic to storing plot history on mouse wheel zoom

* Local controls styling in plots and imagery

- WIP

* Plot local controls, cursor guides

- Local control classes much refined;
- Cursor guides styled, theme constants added;

* Fix local controls in imagery

- LC styles refined;
- New theme constant;

* Better approach to loading

- New .c-loading--overlay that doesn't block the cursor;
- Applied to plot views (telem, overlay and stacked plots);

* Plot styles, local controls refined

- Moved plot classes into their own scss file;
- More refinement on local control styles;
- Plot local controls layout finalized;
- Buttons smallified in layout frame context;

* Convert export buttons from <a> tags

* Stubbed in cursor guide buttons in templates

- WIP!

* add toggle-cursor-guide-button to stacked plots

* move cursor guide button to top left in all plots for consistency

* Plot local controls layout refined

- Also: global styling for *[disabled]

* Change c-button 'is-enabled' to 'is-active'

* Added check for if crosshairs enabled before tracking
This commit is contained in:
Deep Tailor
2019-03-21 13:57:41 -07:00
committed by Andrew Henry
parent df53af7b4d
commit 0e9319e97b
18 changed files with 833 additions and 574 deletions

View File

@ -136,7 +136,7 @@
<span class="t-object-alert t-alert-unsynced"
title="This plot is not currently displaying the latest data.
Reset Pan/zoom to return to view latest data."></span>
<div class="gl-plot-display-area">
<div class="gl-plot-display-area has-local-controls has-cursor-guides">
<mct-ticks axis="xAxis">
<div class="gl-plot-hash hash-v"
ng-repeat="tick in ticks track by tick.value"
@ -147,7 +147,6 @@
</div>
</mct-ticks>
<mct-ticks axis="yAxis">
<div class="gl-plot-hash hash-h"
ng-repeat="tick in ticks track by tick.value"
@ -155,7 +154,6 @@
</div>
</mct-ticks>
<mct-chart config="config"
series="series"
rectangles="rectangles"
@ -164,23 +162,37 @@
the-y-axis="yAxis">
</mct-chart>
<div class="h-local-controls h-local-controls-overlay-content"
ng-show="plotHistory.length">
<div class="l-btn-set">
<a class="s-button icon-arrow-left"
ng-click="plot.back()"
title="Restore previous pan/zoom">
</a>
<a class="s-button icon-reset"
ng-click="plot.clear()"
title="Reset pan/zoom">
</a>
<div class="gl-plot__local-controls h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover">
<div class="c-button-set c-button-set--strip-h">
<button class="c-button icon-minus"
ng-click="plot.zoom('out', 0.2)"
title="Zoom out">
</button>
<button class="c-button icon-plus"
ng-click="plot.zoom('in', 0.2)"
title="Zoom in">
</button>
</div>
<div class="c-button-set c-button-set--strip-h"
ng-disabled="!plotHistory.length">
<button class="c-button icon-arrow-left"
ng-click="plot.back()"
title="Restore previous pan/zoom">
</button>
<button class="c-button icon-reset"
ng-click="plot.clear()"
title="Reset pan/zoom">
</button>
</div>
</div>
<span class="t-wait-spinner loading" ng-show="plot.isRequestPending()">
</span>
<!--Cursor guides-->
<div class="c-cursor-guide--v js-cursor-guide--v"
ng-show="plot.cursorGuide">
</div>
<div class="c-cursor-guide--h js-cursor-guide--h"
ng-show="plot.cursorGuide">
</div>
</div>
<div class="gl-plot-axis-area gl-plot-x"

View File

@ -20,31 +20,34 @@
at runtime from the About dialog for additional information.
-->
<span ng-controller="PlotController as controller"
class="abs holder holder-plot has-control-bar"
ng-class="{
'loading': !!pending
}"
>
class="abs holder holder-plot has-control-bar">
<div class="l-control-bar" ng-show="!controller.hideExportButtons">
<span class="c-button-set c-button-set--strip">
<a class="c-button icon-download"
<span class="c-button-set c-button-set--strip-h">
<button class="c-button icon-download"
ng-click="controller.exportPNG()"
title="Export This View's Data as PNG">
<span class="c-button__label">PNG</span>
</a>
<a class="c-button"
</button>
<button class="c-button"
ng-click="controller.exportJPG()"
title="Export This View's Data as JPG">
<span class="c-button__label">JPG</span>
</a>
</button>
</span>
<button class="c-button icon-crosshair"
ng-class="{ 'is-active': controller.cursorGuide }"
ng-click="controller.toggleCursorGuide($event)"
title="Toggle cursor guides">
</button>
</div>
<div class="l-view-section">
<div class="c-loading--overlay loading"
ng-show="!!pending"></div>
<mct-plot config="controller.config"
series="series"
the-y-axis="yAxis"
the-x-axis="xAxis">
</mct-plot>
</mct-plot>
</div>
</span>

View File

@ -20,26 +20,29 @@
at runtime from the About dialog for additional information.
-->
<span ng-controller="StackedPlotController as stackedPlot"
class="abs holder holder-plot has-control-bar t-plot-stacked"
ng-class="{
'loading': !!currentRequest.pending
}">
class="abs holder holder-plot has-control-bar t-plot-stacked">
<div class="l-control-bar" ng-show="!stackedPlot.hideExportButtons">
<span class="c-button-set c-button-set--strip">
<a class="c-button icon-download"
<span class="c-button-set c-button-set--strip-h">
<button class="c-button icon-download"
ng-click="stackedPlot.exportPNG()"
title="Export This View's Data as PNG">
<span class="c-button__label">PNG</span>
</a>
<a class="c-button"
</button>
<button class="c-button"
ng-click="stackedPlot.exportJPG()"
title="Export This View's Data as JPG">
<span class="c-button__label">JPG</span>
</a>
</span>
</button>
</span>
<button class="c-button icon-crosshair"
ng-class="{ 'is-active': stackedPlot.cursorGuide }"
ng-click="stackedPlot.toggleCursorGuide($event)"
title="Toggle cursor guides">
</button>
</div>
<div class="l-view-section">
<div class="c-loading--overlay loading"
ng-show="!!currentRequest.pending"></div>
<div class="gl-plot child-frame"
ng-repeat="telemetryObject in telemetryObjects"
ng-class="{

View File

@ -78,6 +78,7 @@ define([
this.listenTo(this.$canvas, 'mousemove', this.trackMousePosition, this);
this.listenTo(this.$canvas, 'mouseleave', this.untrackMousePosition, this);
this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this);
this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this);
this.watchForMarquee();
@ -92,6 +93,12 @@ define([
this.$scope.series = this.config.series.models;
this.$scope.legend = this.config.legend;
this.cursorGuideVertical = this.$element[0].querySelector('.js-cursor-guide--v');
this.cursorGuideHorizontal = this.$element[0].querySelector('.js-cursor-guide--h');
this.cursorGuide = false;
this.listenTo(this.$scope, 'cursorguide', this.toggleCursorGuide, this);
this.listenTo(this.$scope, '$destroy', this.destroy, this);
this.listenTo(this.$scope, 'plot:tickWidth', this.onTickWidthChange, this);
this.listenTo(this.$scope, 'plot:highlight:set', this.onPlotHighlightSet, this);
@ -143,6 +150,9 @@ define([
y: this.yScale.invert(this.positionOverElement.y)
};
if (this.cursorGuide) {
this.updateCrosshairs($event);
}
this.highlightValues(this.positionOverPlot.x);
this.updateMarquee();
this.updatePan();
@ -150,6 +160,11 @@ define([
$event.preventDefault();
};
MCTPlotController.prototype.updateCrosshairs = function ($event) {
this.cursorGuideVertical.style.left = ($event.clientX - this.chartElementBounds.x) + 'px';
this.cursorGuideHorizontal.style.top = ($event.clientY - this.chartElementBounds.y) + 'px';
};
MCTPlotController.prototype.trackChartElementBounds = function ($event) {
if ($event.target === this.$canvas[1]) {
this.chartElementBounds = $event.target.getBoundingClientRect();
@ -266,6 +281,102 @@ define([
this.marquee = undefined;
};
MCTPlotController.prototype.zoom = function (zoomDirection, zoomFactor) {
this.freeze();
this.trackHistory();
var currentXaxis = this.$scope.xAxis.get('displayRange'),
currentYaxis = this.$scope.yAxis.get('displayRange'),
xAxisDist= (currentXaxis.max - currentXaxis.min) * zoomFactor,
yAxisDist = (currentYaxis.max - currentYaxis.min) * zoomFactor;
if (zoomDirection === 'in') {
this.$scope.xAxis.set('displayRange', {
min: currentXaxis.min + xAxisDist,
max: currentXaxis.max - xAxisDist
});
this.$scope.yAxis.set('displayRange', {
min: currentYaxis.min + yAxisDist,
max: currentYaxis.max - yAxisDist
});
} else if (zoomDirection === 'out') {
this.$scope.xAxis.set('displayRange', {
min: currentXaxis.min - xAxisDist,
max: currentXaxis.max + xAxisDist
});
this.$scope.yAxis.set('displayRange', {
min: currentYaxis.min - yAxisDist,
max: currentYaxis.max + yAxisDist
});
}
this.$scope.$emit('user:viewport:change:end');
};
MCTPlotController.prototype.wheelZoom = function (event) {
event.preventDefault();
if (!this.positionOverPlot) {
return;
}
this.freeze();
window.clearTimeout(this.stillZooming);
let xDisplayRange = this.$scope.xAxis.get('displayRange'),
yDisplayRange = this.$scope.yAxis.get('displayRange'),
xAxisDist = (xDisplayRange.max - xDisplayRange.min),
yAxisDist = (yDisplayRange.max - yDisplayRange.min),
xDistMouseToMax = xDisplayRange.max - this.positionOverPlot.x,
xDistMouseToMin = this.positionOverPlot.x - xDisplayRange.min,
yDistMouseToMax = yDisplayRange.max - this.positionOverPlot.y,
yDistMouseToMin = this.positionOverPlot.y - yDisplayRange.min,
xAxisMaxDist = xDistMouseToMax / xAxisDist,
xAxisMinDist = xDistMouseToMin / xAxisDist,
yAxisMaxDist = yDistMouseToMax / yAxisDist,
yAxisMinDist = yDistMouseToMin / yAxisDist;
let plotHistoryStep;
if (!plotHistoryStep) {
plotHistoryStep = {
x: xDisplayRange,
y: yDisplayRange
};
}
if (event.wheelDelta < 0) {
this.$scope.xAxis.set('displayRange', {
min: xDisplayRange.min + ((xAxisDist * 0.01) * xAxisMinDist),
max: xDisplayRange.max - ((xAxisDist * 0.01) * xAxisMaxDist)
});
this.$scope.yAxis.set('displayRange', {
min: yDisplayRange.min + ((yAxisDist * 0.01) * yAxisMinDist),
max: yDisplayRange.max - ((yAxisDist * 0.01) * yAxisMaxDist)
});
} else if (event.wheelDelta >= 0) {
this.$scope.xAxis.set('displayRange', {
min: xDisplayRange.min - ((xAxisDist * 0.01) * xAxisMinDist),
max: xDisplayRange.max + ((xAxisDist * 0.01) * xAxisMaxDist)
});
this.$scope.yAxis.set('displayRange', {
min: yDisplayRange.min - ((yAxisDist * 0.01) * yAxisMinDist),
max: yDisplayRange.max + ((yAxisDist * 0.01) * yAxisMaxDist)
});
}
this.stillZooming = window.setTimeout(function () {
this.plotHistory.push(plotHistoryStep);
plotHistoryStep = undefined;
this.$scope.$emit('user:viewport:change:end');
}.bind(this), 250);
};
MCTPlotController.prototype.startPan = function ($event) {
this.trackMousePosition($event);
this.freeze();
@ -362,5 +473,9 @@ define([
this.stopListening();
};
MCTPlotController.prototype.toggleCursorGuide = function ($event) {
this.cursorGuide = !this.cursorGuide;
};
return MCTPlotController;
});

View File

@ -59,6 +59,7 @@ define([
this.openmct = openmct;
this.objectService = objectService;
this.exportImageService = exportImageService;
this.cursorGuide = false;
$scope.pending = 0;
@ -258,8 +259,8 @@ define([
PlotController.prototype.updateFiltersAndResubscribe = function (updatedFilters) {
this.config.series.forEach(function (series) {
series.updateFiltersAndRefresh(updatedFilters[series.keyString]);
})
}
});
};
/**
* Export view as JPG.
@ -283,6 +284,11 @@ define([
}.bind(this));
};
PlotController.prototype.toggleCursorGuide = function ($event) {
this.cursorGuide = !this.cursorGuide;
this.$scope.$broadcast('cursorguide', $event);
};
return PlotController;
});

View File

@ -35,6 +35,8 @@ define([
this.$element = $element;
this.exportImageService = exportImageService;
this.$scope = $scope;
this.cursorGuide = false;
$scope.telemetryObjects = [];
@ -145,5 +147,10 @@ define([
}.bind(this));
};
StackedPlotController.prototype.toggleCursorGuide = function ($event) {
this.cursorGuide = !this.cursorGuide;
this.$scope.$broadcast('cursorguide', $event);
};
return StackedPlotController;
});