diff --git a/platform/features/conductor-v2/conductor/bundle.js b/platform/features/conductor-v2/conductor/bundle.js index 438cb33715..1fbeebdea7 100644 --- a/platform/features/conductor-v2/conductor/bundle.js +++ b/platform/features/conductor-v2/conductor/bundle.js @@ -24,16 +24,18 @@ define([ "./src/ui/TimeConductorViewService", "./src/ui/TimeConductorController", "./src/TimeConductor", + "./src/ui/ConductorAxisController", "./src/ui/MctConductorAxis", "./src/ui/NumberFormat", "text!./res/templates/time-conductor.html", "text!./res/templates/mode-selector/mode-selector.html", "text!./res/templates/mode-selector/mode-menu.html", - 'legacyRegistry' + "legacyRegistry" ], function ( TimeConductorViewService, TimeConductorController, TimeConductor, + ConductorAxisController, MCTConductorAxis, NumberFormat, timeConductorTemplate, @@ -69,6 +71,14 @@ define([ "timeConductorViewService", "timeSystems[]" ] + }, + { + "key": "ConductorAxisController", + "implementation": ConductorAxisController, + "depends": [ + "timeConductor", + "formatService" + ] } ], "directives": [ diff --git a/platform/features/conductor-v2/conductor/res/sass/_time-conductor-base.scss b/platform/features/conductor-v2/conductor/res/sass/_time-conductor-base.scss index e20c0ef4cd..5beaf916d3 100644 --- a/platform/features/conductor-v2/conductor/res/sass/_time-conductor-base.scss +++ b/platform/features/conductor-v2/conductor/res/sass/_time-conductor-base.scss @@ -136,6 +136,7 @@ bottom: 0; left: 0; z-index: 1; + pointer-events: none; .l-time-range-w { // Wraps a datetime text input field height: 100%; @@ -159,6 +160,9 @@ content: 'End'; } } + .l-time-conductor-inputs { + pointer-events: auto; + } input[type="text"] { @include trans-prop-nice(padding, 250ms); } diff --git a/platform/features/conductor-v2/conductor/res/templates/time-conductor.html b/platform/features/conductor-v2/conductor/res/templates/time-conductor.html index 19c86b2b74..86dcd14ec2 100644 --- a/platform/features/conductor-v2/conductor/res/templates/time-conductor.html +++ b/platform/features/conductor-v2/conductor/res/templates/time-conductor.html @@ -1,6 +1,18 @@ +
+ class="holder grows flex-elem l-flex-row l-time-conductor {{modeModel.selectedKey}}-mode {{timeSystemModel.selected.metadata.key}}-time-system" + ng-class="{'status-panning': panning}">
@@ -13,63 +25,67 @@
- - - - - - - - - - + + + + + + + + - + + + - - - - - - - + - - + + + + + + + + + + + + diff --git a/platform/features/conductor-v2/conductor/src/ui/ConductorAxisController.js b/platform/features/conductor-v2/conductor/src/ui/ConductorAxisController.js new file mode 100644 index 0000000000..b88177181d --- /dev/null +++ b/platform/features/conductor-v2/conductor/src/ui/ConductorAxisController.js @@ -0,0 +1,169 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2014-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ + +define( + [ + "d3" + ], + function (d3) { + var PADDING = 1; + + /** + * The mct-conductor-axis renders a horizontal axis with regular + * labelled 'ticks'. It requires 'start' and 'end' integer values to + * be specified as attributes. + */ + function ConductorAxisController(conductor, formatService) { + // Dependencies + this.d3 = d3; + this.formatService = formatService; + this.conductor = conductor; + + // Runtime properties (set by 'link' function) + this.target = undefined; + this.xScale = undefined; + this.xAxis = undefined; + this.axisElement = undefined; + this.initialized = false; + this.msPerPixel = undefined; + + this.setScale = this.setScale.bind(this); + this.changeBounds = this.changeBounds.bind(this); + this.changeTimeSystem = this.changeTimeSystem.bind(this); + + this.bounds = conductor.bounds(); + this.timeSystem = conductor.timeSystem(); + } + + ConductorAxisController.prototype.changeBounds = function (bounds) { + this.bounds = bounds; + if (this.initialized) { + this.setScale(); + } + }; + + ConductorAxisController.prototype.setScale = function () { + var width = this.target.offsetWidth; + var timeSystem = this.conductor.timeSystem(); + var bounds = this.bounds; + + if (timeSystem.isUTCBased()) { + this.xScale = this.xScale || this.d3.scaleUtc(); + this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]); + } else { + this.xScale = this.xScale || this.d3.scaleLinear(); + this.xScale.domain([bounds.start, bounds.end]); + } + + this.xScale.range([PADDING, width - PADDING * 2]); + this.axisElement.call(this.xAxis); + + this.msPerPixel = (bounds.end - bounds.start) / width; + }; + + ConductorAxisController.prototype.changeTimeSystem = function (timeSystem) { + this.timeSystem = timeSystem; + + var key = timeSystem.formats()[0]; + if (this.initialized && key !== undefined) { + var format = this.formatService.getFormat(key); + var bounds = this.conductor.bounds(); + + if (timeSystem.isUTCBased()) { + this.xScale = this.d3.scaleUtc(); + } else { + this.xScale = this.d3.scaleLinear(); + } + + this.xAxis.scale(this.xScale); + //Define a custom format function + this.xAxis.tickFormat(function (tickValue) { + // Normalize date representations to numbers + if (tickValue instanceof Date) { + tickValue = tickValue.getTime(); + } + return format.format(tickValue, { + min: bounds.start, + max: bounds.end + }); + }); + this.axisElement.call(this.xAxis); + } + }; + + ConductorAxisController.prototype.link = function (scope, element) { + this.target = element[0].firstChild; + this.scope = scope; + var height = this.target.offsetHeight; + var vis = this.d3.select(this.target) + .append("svg:svg") + .attr("width", "100%") + .attr("height", height); + + this.xAxis = this.d3.axisTop(); + + // draw x axis with labels and move to the bottom of the chart area + this.axisElement = vis.append("g") + .attr("transform", "translate(0," + (height - PADDING) + ")"); + + this.initialized = true; + + if (this.timeSystem !== undefined) { + this.changeTimeSystem(this.timeSystem); + this.setScale(this.bounds); + } + + //Respond to changes in conductor + this.conductor.on("timeSystem", this.changeTimeSystem); + this.conductor.on("bounds", this.changeBounds); + }; + + ConductorAxisController.prototype.panEnd = function () { + //resync view bounds with time conductor bounds + this.conductor.bounds(this.bounds); + this.scope.$emit("pan-stop"); + }; + + ConductorAxisController.prototype.pan = function (delta) { + if (!this.conductor.follow()) { + var deltaInMs = delta[0] * this.msPerPixel; + var bounds = this.conductor.bounds(); + var start = Math.floor((bounds.start - deltaInMs) / 1000) * 1000; + var end = Math.floor((bounds.end - deltaInMs) / 1000) * 1000; + this.bounds = { + start: start, + end: end + }; + this.setScale(); + this.scope.$emit("pan", this.bounds); + } + }; + + ConductorAxisController.prototype.resize = function () { + if (this.initialized) { + this.setScale(); + } + }; + + return ConductorAxisController; + } +); diff --git a/platform/features/conductor-v2/conductor/src/ui/MctConductorAxis.js b/platform/features/conductor-v2/conductor/src/ui/MctConductorAxis.js index 58cb60befc..8b874badf2 100644 --- a/platform/features/conductor-v2/conductor/src/ui/MctConductorAxis.js +++ b/platform/features/conductor-v2/conductor/src/ui/MctConductorAxis.js @@ -20,127 +20,33 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -define( - [ - "d3" - ], - function (d3) { - var PADDING = 1; +define([], function () { - /** - * The mct-conductor-axis renders a horizontal axis with regular - * labelled 'ticks'. It requires 'start' and 'end' integer values to - * be specified as attributes. - */ - function MCTConductorAxis(conductor, formatService) { - // Dependencies - this.d3 = d3; - this.conductor = conductor; - this.formatService = formatService; + function MctConductorAxis() { + /** + * The mct-conductor-axis renders a horizontal axis with regular + * labelled 'ticks'. It requires 'start' and 'end' integer values to + * be specified as attributes. + */ - // Runtime properties (set by 'link' function) - this.target = undefined; - this.xScale = undefined; - this.xAxis = undefined; - this.axisElement = undefined; + return { + controller: 'ConductorAxisController', + controllerAs: 'axis', + link: function(scope, element, attrs, controller){ + controller.link(scope, element); + }, - // Angular Directive interface - this.link = this.link.bind(this); - this.restrict = "E"; - this.template = - "
"; - this.priority = 1000; + restrict: 'E', + priority: 1000, - //Bind all class functions to 'this' - Object.keys(MCTConductorAxis.prototype).filter(function (key) { - return typeof MCTConductorAxis.prototype[key] === 'function'; - }).forEach(function (key) { - this[key] = this[key].bind(this); - }.bind(this)); + template: '
' + } } - MCTConductorAxis.prototype.setScale = function () { - var width = this.target.offsetWidth; - var timeSystem = this.conductor.timeSystem(); - var bounds = this.conductor.bounds(); - - if (timeSystem.isUTCBased()) { - this.xScale = this.xScale || this.d3.scaleUtc(); - this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]); - } else { - this.xScale = this.xScale || this.d3.scaleLinear(); - this.xScale.domain([bounds.start, bounds.end]); - } - - this.xScale.range([PADDING, width - PADDING * 2]); - this.axisElement.call(this.xAxis); - }; - - MCTConductorAxis.prototype.changeTimeSystem = function (timeSystem) { - var key = timeSystem.formats()[0]; - if (key !== undefined) { - var format = this.formatService.getFormat(key); - var bounds = this.conductor.bounds(); - - if (timeSystem.isUTCBased()) { - this.xScale = this.d3.scaleUtc(); - } else { - this.xScale = this.d3.scaleLinear(); - } - - this.xAxis.scale(this.xScale); - //Define a custom format function - this.xAxis.tickFormat(function (tickValue) { - // Normalize date representations to numbers - if (tickValue instanceof Date) { - tickValue = tickValue.getTime(); - } - return format.format(tickValue, { - min: bounds.start, - max: bounds.end - }); - }); - this.axisElement.call(this.xAxis); - } - }; - - MCTConductorAxis.prototype.destroy = function () { - this.conductor.off('timeSystem', this.changeTimeSystem); - this.conductor.off('bounds', this.setScale); - }; - - MCTConductorAxis.prototype.link = function (scope, element) { - var conductor = this.conductor; - this.target = element[0].firstChild; - var height = this.target.offsetHeight; - var vis = this.d3.select(this.target) - .append('svg:svg') - .attr('width', '100%') - .attr('height', height); - - this.xAxis = this.d3.axisTop(); - - // draw x axis with labels and move to the bottom of the chart area - this.axisElement = vis.append("g") - .attr("transform", "translate(0," + (height - PADDING) + ")"); - - scope.resize = this.setScale; - - conductor.on('timeSystem', this.changeTimeSystem); - - //On conductor bounds changes, redraw ticks - conductor.on('bounds', this.setScale); - - scope.$on("$destroy", this.destroy); - - if (conductor.timeSystem() !== undefined) { - this.changeTimeSystem(conductor.timeSystem()); - this.setScale(); - } - }; - - return function (conductor, formatService) { - return new MCTConductorAxis(conductor, formatService); - }; + return MctConductorAxis; } ); diff --git a/platform/features/conductor-v2/conductor/src/ui/TimeConductorController.js b/platform/features/conductor-v2/conductor/src/ui/TimeConductorController.js index 83bc0558c6..21040eea17 100644 --- a/platform/features/conductor-v2/conductor/src/ui/TimeConductorController.js +++ b/platform/features/conductor-v2/conductor/src/ui/TimeConductorController.js @@ -97,6 +97,14 @@ define( // Watch scope for selection of mode or time system by user this.$scope.$watch('modeModel.selectedKey', this.setMode); + this.$scope.$on('pan', function (e, bounds) { + this.$scope.panning = true; + this.setFormFromBounds(bounds); + }.bind(this)); + + this.$scope.$on('pan-stop', function () { + this.$scope.panning = false; + }.bind(this)); this.$scope.$on('$destroy', this.destroy); };