2015-09-02 23:31:58 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
* 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.
|
|
|
|
*****************************************************************************/
|
|
|
|
/*global define,Promise*/
|
|
|
|
|
|
|
|
define(
|
2015-09-02 23:53:10 +00:00
|
|
|
['moment'],
|
|
|
|
function (moment) {
|
2015-09-02 23:31:58 +00:00
|
|
|
"use strict";
|
|
|
|
|
2015-09-02 23:53:10 +00:00
|
|
|
var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss";
|
|
|
|
|
2015-09-02 23:31:58 +00:00
|
|
|
/**
|
|
|
|
* @memberof platform/commonUI/general
|
|
|
|
* @constructor
|
|
|
|
*/
|
2015-09-02 23:53:10 +00:00
|
|
|
function TimeConductorController($scope, now) {
|
2015-09-03 00:19:20 +00:00
|
|
|
var tickCount = 2,
|
|
|
|
initialDragValue;
|
|
|
|
|
2015-09-02 23:53:10 +00:00
|
|
|
function formatTimestamp(ts) {
|
|
|
|
return moment.utc(ts).format(DATE_FORMAT);
|
|
|
|
}
|
2015-09-02 23:31:58 +00:00
|
|
|
|
2015-09-03 18:03:17 +00:00
|
|
|
function parseTimestamp(text, fallback) {
|
|
|
|
var m = moment.utc(text, DATE_FORMAT);
|
|
|
|
return m.isValid() ? m.valueOf() : fallback;
|
|
|
|
}
|
|
|
|
|
2015-09-02 23:53:10 +00:00
|
|
|
// From 0.0-1.0 to "0%"-"1%"
|
|
|
|
function toPercent(p) {
|
|
|
|
return (100 * p) + "%";
|
|
|
|
}
|
2015-09-02 23:31:58 +00:00
|
|
|
|
|
|
|
function updateTicks() {
|
2015-09-02 23:53:10 +00:00
|
|
|
var i, p, ts, start, end, span;
|
2015-09-10 17:54:44 +00:00
|
|
|
end = $scope.ngModel.outer.end;
|
|
|
|
start = $scope.ngModel.outer.start;
|
2015-09-02 23:53:10 +00:00
|
|
|
span = end - start;
|
2015-09-02 23:31:58 +00:00
|
|
|
$scope.ticks = [];
|
|
|
|
for (i = 0; i < tickCount; i += 1) {
|
2015-09-02 23:53:10 +00:00
|
|
|
p = i / (tickCount - 1);
|
|
|
|
ts = p * span + start;
|
|
|
|
$scope.ticks.push(formatTimestamp(ts));
|
2015-09-02 23:31:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateSpanWidth(w) {
|
|
|
|
// Space about 100px apart
|
|
|
|
tickCount = Math.max(Math.floor(w / 100), 2);
|
|
|
|
updateTicks();
|
|
|
|
}
|
|
|
|
|
2015-09-04 22:15:09 +00:00
|
|
|
function updateViewForInnerSpanFromModel(ngModel) {
|
2015-09-10 17:54:44 +00:00
|
|
|
var span = ngModel.outer.end - ngModel.outer.start;
|
2015-09-04 22:15:09 +00:00
|
|
|
|
|
|
|
// Expose readable dates for the knobs
|
2015-09-10 17:54:44 +00:00
|
|
|
$scope.startInnerText = formatTimestamp(ngModel.inner.start);
|
|
|
|
$scope.endInnerText = formatTimestamp(ngModel.inner.end);
|
2015-09-04 22:15:09 +00:00
|
|
|
|
|
|
|
// And positions for the knobs
|
|
|
|
$scope.startInnerPct =
|
2015-09-10 17:54:44 +00:00
|
|
|
toPercent((ngModel.inner.start - ngModel.outer.start) / span);
|
2015-09-04 22:15:09 +00:00
|
|
|
$scope.endInnerPct =
|
2015-09-10 17:54:44 +00:00
|
|
|
toPercent((ngModel.outer.end - ngModel.inner.end) / span);
|
|
|
|
}
|
|
|
|
|
|
|
|
function defaultBounds() {
|
|
|
|
var t = now();
|
|
|
|
return {
|
|
|
|
start: t - 24 * 3600 * 1000, // One day
|
|
|
|
end: t
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function copyBounds(bounds) {
|
|
|
|
return { start: bounds.start, end: bounds.end };
|
2015-09-04 22:15:09 +00:00
|
|
|
}
|
|
|
|
|
2015-09-03 18:03:17 +00:00
|
|
|
function updateViewFromModel(ngModel) {
|
2015-09-04 22:15:09 +00:00
|
|
|
var t = now();
|
2015-09-02 23:53:10 +00:00
|
|
|
|
2015-09-03 18:03:17 +00:00
|
|
|
ngModel = ngModel || {};
|
2015-09-10 17:54:44 +00:00
|
|
|
ngModel.outer = ngModel.outer || defaultBounds();
|
|
|
|
ngModel.inner = ngModel.inner || copyBounds(ngModel.outer);
|
2015-09-02 23:53:10 +00:00
|
|
|
|
|
|
|
// First, dates for the date pickers for outer bounds
|
2015-09-10 17:54:44 +00:00
|
|
|
$scope.startOuterDate = formatTimestamp(ngModel.outer.start);
|
|
|
|
$scope.endOuterDate = formatTimestamp(ngModel.outer.end);
|
2015-09-02 23:53:10 +00:00
|
|
|
|
2015-09-04 22:15:09 +00:00
|
|
|
// Then various updates for the inner span
|
|
|
|
updateViewForInnerSpanFromModel(ngModel);
|
2015-09-02 23:53:10 +00:00
|
|
|
|
|
|
|
// Stick it back is scope (in case we just set defaults)
|
|
|
|
$scope.ngModel = ngModel;
|
|
|
|
|
|
|
|
updateTicks();
|
|
|
|
}
|
|
|
|
|
2015-09-03 00:19:20 +00:00
|
|
|
function startLeftDrag() {
|
2015-09-10 17:54:44 +00:00
|
|
|
initialDragValue = $scope.ngModel.inner.start;
|
2015-09-03 00:19:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function startRightDrag() {
|
2015-09-10 17:54:44 +00:00
|
|
|
initialDragValue = $scope.ngModel.inner.end;
|
2015-09-03 00:19:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function startMiddleDrag() {
|
2015-09-10 18:34:31 +00:00
|
|
|
initialDragValue = {
|
|
|
|
start: $scope.ngModel.inner.start,
|
|
|
|
end: $scope.ngModel.inner.end
|
|
|
|
};
|
2015-09-03 00:19:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function toMillis(pixels) {
|
2015-09-10 17:54:44 +00:00
|
|
|
var span = $scope.ngModel.outer.end - $scope.ngModel.outer.start;
|
2015-09-03 00:19:20 +00:00
|
|
|
return (pixels / $scope.spanWidth) * span;
|
|
|
|
}
|
|
|
|
|
|
|
|
function clamp(value, low, high) {
|
|
|
|
return Math.max(low, Math.min(high, value));
|
|
|
|
}
|
|
|
|
|
|
|
|
function leftDrag(pixels) {
|
|
|
|
var delta = toMillis(pixels);
|
2015-09-10 17:54:44 +00:00
|
|
|
$scope.ngModel.inner.start = clamp(
|
2015-09-03 00:19:20 +00:00
|
|
|
initialDragValue + delta,
|
2015-09-10 17:54:44 +00:00
|
|
|
$scope.ngModel.outer.start,
|
|
|
|
$scope.ngModel.inner.end
|
2015-09-03 00:19:20 +00:00
|
|
|
);
|
2015-09-03 18:03:17 +00:00
|
|
|
updateViewFromModel($scope.ngModel);
|
2015-09-03 00:19:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function rightDrag(pixels) {
|
|
|
|
var delta = toMillis(pixels);
|
2015-09-10 17:54:44 +00:00
|
|
|
$scope.ngModel.inner.end = clamp(
|
2015-09-03 00:19:20 +00:00
|
|
|
initialDragValue + delta,
|
2015-09-10 17:54:44 +00:00
|
|
|
$scope.ngModel.inner.start,
|
|
|
|
$scope.ngModel.outer.end
|
2015-09-03 00:19:20 +00:00
|
|
|
);
|
2015-09-03 18:03:17 +00:00
|
|
|
updateViewFromModel($scope.ngModel);
|
2015-09-03 00:19:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function middleDrag(pixels) {
|
|
|
|
var delta = toMillis(pixels),
|
2015-09-10 17:54:44 +00:00
|
|
|
edge = delta < 0 ? 'start' : 'end',
|
|
|
|
opposite = delta < 0 ? 'end' : 'start';
|
2015-09-03 00:19:20 +00:00
|
|
|
|
2015-09-03 00:25:41 +00:00
|
|
|
// Adjust the position of the edge in the direction of drag
|
2015-09-10 17:54:44 +00:00
|
|
|
$scope.ngModel.inner[edge] = clamp(
|
|
|
|
initialDragValue[edge] + delta,
|
|
|
|
$scope.ngModel.outer.start,
|
|
|
|
$scope.ngModel.outer.end
|
2015-09-03 00:19:20 +00:00
|
|
|
);
|
2015-09-03 00:25:41 +00:00
|
|
|
// Adjust opposite knob to maintain span
|
2015-09-10 17:54:44 +00:00
|
|
|
$scope.ngModel.inner[opposite] = $scope.ngModel.inner[edge] +
|
|
|
|
initialDragValue[opposite] - initialDragValue[edge];
|
2015-09-03 00:25:41 +00:00
|
|
|
|
2015-09-03 18:03:17 +00:00
|
|
|
updateViewFromModel($scope.ngModel);
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateOuterStart(text) {
|
|
|
|
var ngModel = $scope.ngModel;
|
2015-09-10 17:54:44 +00:00
|
|
|
ngModel.outer.start =
|
|
|
|
parseTimestamp(text, ngModel.outer.start);
|
|
|
|
ngModel.outer.end =
|
|
|
|
Math.max(ngModel.outer.start, ngModel.outer.end);
|
|
|
|
ngModel.inner.start =
|
|
|
|
Math.max(ngModel.outer.start, ngModel.inner.start);
|
|
|
|
ngModel.inner.end =
|
2015-09-10 20:24:50 +00:00
|
|
|
Math.max(ngModel.outer.start, ngModel.inner.end);
|
2015-09-04 22:15:09 +00:00
|
|
|
updateViewForInnerSpanFromModel(ngModel);
|
2015-09-03 18:03:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function updateOuterEnd(text) {
|
|
|
|
var ngModel = $scope.ngModel;
|
2015-09-10 17:54:44 +00:00
|
|
|
ngModel.outer.end =
|
|
|
|
parseTimestamp(text, ngModel.outer.end);
|
|
|
|
ngModel.outer.start =
|
|
|
|
Math.min(ngModel.outer.end, ngModel.outer.start);
|
|
|
|
ngModel.inner.start =
|
|
|
|
Math.min(ngModel.outer.end, ngModel.inner.start);
|
|
|
|
ngModel.inner.end =
|
|
|
|
Math.min(ngModel.outer.end, ngModel.inner.end);
|
2015-09-04 22:15:09 +00:00
|
|
|
updateViewForInnerSpanFromModel(ngModel);
|
2015-09-03 00:19:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$scope.startLeftDrag = startLeftDrag;
|
|
|
|
$scope.startRightDrag = startRightDrag;
|
2015-09-03 00:25:41 +00:00
|
|
|
$scope.startMiddleDrag = startMiddleDrag;
|
2015-09-03 00:19:20 +00:00
|
|
|
$scope.leftDrag = leftDrag;
|
|
|
|
$scope.rightDrag = rightDrag;
|
2015-09-03 00:25:41 +00:00
|
|
|
$scope.middleDrag = middleDrag;
|
2015-09-03 00:19:20 +00:00
|
|
|
|
|
|
|
$scope.state = false;
|
|
|
|
$scope.ticks = [];
|
|
|
|
|
2015-09-02 23:53:10 +00:00
|
|
|
// Initialize scope to defaults
|
2015-09-03 18:03:17 +00:00
|
|
|
updateViewFromModel($scope.ngModel);
|
2015-09-02 23:53:10 +00:00
|
|
|
|
2015-09-03 18:03:17 +00:00
|
|
|
$scope.$watchCollection("ngModel", updateViewFromModel);
|
2015-09-02 23:31:58 +00:00
|
|
|
$scope.$watch("spanWidth", updateSpanWidth);
|
2015-09-03 18:03:17 +00:00
|
|
|
$scope.$watch("startOuterDate", updateOuterStart);
|
|
|
|
$scope.$watch("endOuterDate", updateOuterEnd);
|
2015-09-02 23:31:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return TimeConductorController;
|
|
|
|
}
|
|
|
|
);
|