Skip to content

Commit 7fcafb6

Browse files
committed
[Time Conductor] Added pan to Time Conductor
1 parent d77922d commit 7fcafb6

File tree

6 files changed

+289
-176
lines changed

6 files changed

+289
-176
lines changed

platform/features/conductor-v2/conductor/bundle.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ define([
2424
"./src/ui/TimeConductorViewService",
2525
"./src/ui/TimeConductorController",
2626
"./src/TimeConductor",
27+
"./src/ui/ConductorAxisController",
2728
"./src/ui/MctConductorAxis",
2829
"./src/ui/NumberFormat",
2930
"text!./res/templates/time-conductor.html",
3031
"text!./res/templates/mode-selector/mode-selector.html",
3132
"text!./res/templates/mode-selector/mode-menu.html",
32-
'legacyRegistry'
33+
"legacyRegistry"
3334
], function (
3435
TimeConductorViewService,
3536
TimeConductorController,
3637
TimeConductor,
38+
ConductorAxisController,
3739
MCTConductorAxis,
3840
NumberFormat,
3941
timeConductorTemplate,
@@ -69,6 +71,14 @@ define([
6971
"timeConductorViewService",
7072
"timeSystems[]"
7173
]
74+
},
75+
{
76+
"key": "ConductorAxisController",
77+
"implementation": ConductorAxisController,
78+
"depends": [
79+
"timeConductor",
80+
"formatService"
81+
]
7282
}
7383
],
7484
"directives": [

platform/features/conductor-v2/conductor/res/sass/_time-conductor-base.scss

+4
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@
136136
bottom: 0;
137137
left: 0;
138138
z-index: 1;
139+
pointer-events: none;
139140
.l-time-range-w {
140141
// Wraps a datetime text input field
141142
height: 100%;
@@ -159,6 +160,9 @@
159160
content: 'End';
160161
}
161162
}
163+
.l-time-conductor-inputs {
164+
pointer-events: auto;
165+
}
162166
input[type="text"] {
163167
@include trans-prop-nice(padding, 250ms);
164168
}

platform/features/conductor-v2/conductor/res/templates/time-conductor.html

+71-55
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
<!-- Parent holder for time conductor. follow-mode | fixed-mode -->
2+
<style>
3+
.fixed-mode .l-axis-holder {
4+
cursor: grab;
5+
cursor: -webkit-grab;
6+
}
7+
8+
.fixed-mode .l-axis-holder:active {
9+
cursor: grabbing;
10+
cursor: -webkit-grabbing;
11+
}
12+
</style>
213
<div ng-controller="TimeConductorController as tcController"
3-
class="holder grows flex-elem l-flex-row l-time-conductor {{modeModel.selectedKey}}-mode {{timeSystemModel.selected.metadata.key}}-time-system">
14+
class="holder grows flex-elem l-flex-row l-time-conductor {{modeModel.selectedKey}}-mode {{timeSystemModel.selected.metadata.key}}-time-system"
15+
ng-class="{'status-panning': panning}">
416

517
<div class="flex-elem holder time-conductor-icon">
618
<div class="hand-little"></div>
@@ -13,63 +25,67 @@
1325
<form class="l-time-conductor-inputs-holder"
1426
ng-submit="tcController.updateBoundsFromForm(boundsModel)">
1527
<span class="l-time-range-w start-w">
16-
<span class="l-time-range-input-w start-date">
17-
<span class="title"></span>
18-
<mct-control key="'datetime-field'"
19-
structure="{
20-
format: timeSystemModel.format,
21-
validate: tcController.validation.validateStart
22-
}"
23-
ng-model="boundsModel"
24-
ng-blur="tcController.updateBoundsFromForm(boundsModel)"
25-
field="'start'"
26-
class="time-range-input">
27-
</mct-control>
28-
</span>
29-
<span class="l-time-range-input-w time-delta start-delta"
30-
ng-class="{'hide':(modeModel.selectedKey === 'fixed')}">
31-
-
32-
<mct-control key="'datetime-field'"
33-
structure="{
34-
format: timeSystemModel.deltaFormat,
35-
validate: tcController.validation.validateStartDelta
36-
}"
37-
ng-model="boundsModel"
38-
ng-blur="tcController.updateDeltasFromForm(boundsModel)"
39-
field="'startDelta'"
40-
class="hrs-min-input">
41-
</mct-control>
28+
<span class="l-time-conductor-inputs">
29+
<span class="l-time-range-input-w start-date">
30+
<span class="title"></span>
31+
<mct-control key="'datetime-field'"
32+
structure="{
33+
format: timeSystemModel.format,
34+
validate: tcController.validation.validateStart
35+
}"
36+
ng-model="boundsModel"
37+
ng-blur="tcController.updateBoundsFromForm(boundsModel)"
38+
field="'start'"
39+
class="time-range-input">
40+
</mct-control>
41+
</span>
42+
<span class="l-time-range-input-w time-delta start-delta"
43+
ng-class="{'hide':(modeModel.selectedKey === 'fixed')}">
44+
-
45+
<mct-control key="'datetime-field'"
46+
structure="{
47+
format: timeSystemModel.deltaFormat,
48+
validate: tcController.validation.validateStartDelta
49+
}"
50+
ng-model="boundsModel"
51+
ng-blur="tcController.updateDeltasFromForm(boundsModel)"
52+
field="'startDelta'"
53+
class="hrs-min-input">
54+
</mct-control>
55+
</span>
4256
</span>
4357
</span>
4458
<span class="l-time-range-w end-w">
45-
<span class="l-time-range-input-w end-date"
46-
ng-controller="ToggleController as t2">
47-
<span class="title"></span>
48-
<mct-control key="'datetime-field'"
49-
structure="{
50-
format: timeSystemModel.format,
51-
validate: tcController.validation.validateEnd
52-
}"
53-
ng-model="boundsModel"
54-
ng-blur="tcController.updateBoundsFromForm(boundsModel)"
55-
ng-disabled="modeModel.selectedKey !== 'fixed'"
56-
field="'end'"
57-
class="time-range-input">
58-
</mct-control>
59-
</span>
60-
<span class="l-time-range-input-w time-delta end-delta"
61-
ng-class="{'hide':(modeModel.selectedKey === 'fixed')}">
62-
+
63-
<mct-control key="'datetime-field'"
64-
structure="{
65-
format: timeSystemModel.deltaFormat,
66-
validate: tcController.validation.validateEndDelta
67-
}"
68-
ng-model="boundsModel"
69-
ng-blur="tcController.updateDeltasFromForm(boundsModel)"
70-
field="'endDelta'"
71-
class="hrs-min-input">
72-
</mct-control>
59+
<span class="l-time-conductor-inputs">
60+
<span class="l-time-range-input-w end-date"
61+
ng-controller="ToggleController as t2">
62+
<span class="title"></span>
63+
<mct-control key="'datetime-field'"
64+
structure="{
65+
format: timeSystemModel.format,
66+
validate: tcController.validation.validateEnd
67+
}"
68+
ng-model="boundsModel"
69+
ng-blur="tcController.updateBoundsFromForm(boundsModel)"
70+
ng-disabled="modeModel.selectedKey !== 'fixed'"
71+
field="'end'"
72+
class="time-range-input">
73+
</mct-control>
74+
</span>
75+
<span class="l-time-range-input-w time-delta end-delta"
76+
ng-class="{'hide':(modeModel.selectedKey === 'fixed')}">
77+
+
78+
<mct-control key="'datetime-field'"
79+
structure="{
80+
format: timeSystemModel.deltaFormat,
81+
validate: tcController.validation.validateEndDelta
82+
}"
83+
ng-model="boundsModel"
84+
ng-blur="tcController.updateDeltasFromForm(boundsModel)"
85+
field="'endDelta'"
86+
class="hrs-min-input">
87+
</mct-control>
88+
</span>
7389
</span>
7490
</span>
7591

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*****************************************************************************
2+
* Open MCT Web, Copyright (c) 2014-2015, United States Government
3+
* as represented by the Administrator of the National Aeronautics and Space
4+
* Administration. All rights reserved.
5+
*
6+
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
* http://www.apache.org/licenses/LICENSE-2.0.
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
* License for the specific language governing permissions and limitations
15+
* under the License.
16+
*
17+
* Open MCT Web includes source code licensed under additional open source
18+
* licenses. See the Open Source Licenses file (LICENSES.md) included with
19+
* this source code distribution or the Licensing information page available
20+
* at runtime from the About dialog for additional information.
21+
*****************************************************************************/
22+
23+
define(
24+
[
25+
"d3"
26+
],
27+
function (d3) {
28+
var PADDING = 1;
29+
30+
/**
31+
* The mct-conductor-axis renders a horizontal axis with regular
32+
* labelled 'ticks'. It requires 'start' and 'end' integer values to
33+
* be specified as attributes.
34+
*/
35+
function ConductorAxisController(conductor, formatService) {
36+
// Dependencies
37+
this.d3 = d3;
38+
this.formatService = formatService;
39+
this.conductor = conductor;
40+
41+
// Runtime properties (set by 'link' function)
42+
this.target = undefined;
43+
this.xScale = undefined;
44+
this.xAxis = undefined;
45+
this.axisElement = undefined;
46+
this.initialized = false;
47+
this.msPerPixel = undefined;
48+
49+
this.setScale = this.setScale.bind(this);
50+
this.changeBounds = this.changeBounds.bind(this);
51+
this.changeTimeSystem = this.changeTimeSystem.bind(this);
52+
53+
this.bounds = conductor.bounds();
54+
this.timeSystem = conductor.timeSystem();
55+
}
56+
57+
ConductorAxisController.prototype.changeBounds = function (bounds) {
58+
this.bounds = bounds;
59+
if (this.initialized) {
60+
this.setScale();
61+
}
62+
};
63+
64+
ConductorAxisController.prototype.setScale = function () {
65+
var width = this.target.offsetWidth;
66+
var timeSystem = this.conductor.timeSystem();
67+
var bounds = this.bounds;
68+
69+
if (timeSystem.isUTCBased()) {
70+
this.xScale = this.xScale || this.d3.scaleUtc();
71+
this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]);
72+
} else {
73+
this.xScale = this.xScale || this.d3.scaleLinear();
74+
this.xScale.domain([bounds.start, bounds.end]);
75+
}
76+
77+
this.xScale.range([PADDING, width - PADDING * 2]);
78+
this.axisElement.call(this.xAxis);
79+
80+
this.msPerPixel = (bounds.end - bounds.start) / width;
81+
};
82+
83+
ConductorAxisController.prototype.changeTimeSystem = function (timeSystem) {
84+
this.timeSystem = timeSystem;
85+
86+
var key = timeSystem.formats()[0];
87+
if (this.initialized && key !== undefined) {
88+
var format = this.formatService.getFormat(key);
89+
var bounds = this.conductor.bounds();
90+
91+
if (timeSystem.isUTCBased()) {
92+
this.xScale = this.d3.scaleUtc();
93+
} else {
94+
this.xScale = this.d3.scaleLinear();
95+
}
96+
97+
this.xAxis.scale(this.xScale);
98+
//Define a custom format function
99+
this.xAxis.tickFormat(function (tickValue) {
100+
// Normalize date representations to numbers
101+
if (tickValue instanceof Date) {
102+
tickValue = tickValue.getTime();
103+
}
104+
return format.format(tickValue, {
105+
min: bounds.start,
106+
max: bounds.end
107+
});
108+
});
109+
this.axisElement.call(this.xAxis);
110+
}
111+
};
112+
113+
ConductorAxisController.prototype.link = function (scope, element) {
114+
this.target = element[0].firstChild;
115+
this.scope = scope;
116+
var height = this.target.offsetHeight;
117+
var vis = this.d3.select(this.target)
118+
.append("svg:svg")
119+
.attr("width", "100%")
120+
.attr("height", height);
121+
122+
this.xAxis = this.d3.axisTop();
123+
124+
// draw x axis with labels and move to the bottom of the chart area
125+
this.axisElement = vis.append("g")
126+
.attr("transform", "translate(0," + (height - PADDING) + ")");
127+
128+
this.initialized = true;
129+
130+
if (this.timeSystem !== undefined) {
131+
this.changeTimeSystem(this.timeSystem);
132+
this.setScale(this.bounds);
133+
}
134+
135+
//Respond to changes in conductor
136+
this.conductor.on("timeSystem", this.changeTimeSystem);
137+
this.conductor.on("bounds", this.changeBounds);
138+
};
139+
140+
ConductorAxisController.prototype.panEnd = function () {
141+
//resync view bounds with time conductor bounds
142+
this.conductor.bounds(this.bounds);
143+
this.scope.$emit("pan-stop");
144+
};
145+
146+
ConductorAxisController.prototype.pan = function (delta) {
147+
if (!this.conductor.follow()) {
148+
var deltaInMs = delta[0] * this.msPerPixel;
149+
var bounds = this.conductor.bounds();
150+
var start = Math.floor((bounds.start - deltaInMs) / 1000) * 1000;
151+
var end = Math.floor((bounds.end - deltaInMs) / 1000) * 1000;
152+
this.bounds = {
153+
start: start,
154+
end: end
155+
};
156+
this.setScale();
157+
this.scope.$emit("pan", this.bounds);
158+
}
159+
};
160+
161+
ConductorAxisController.prototype.resize = function () {
162+
if (this.initialized) {
163+
this.setScale();
164+
}
165+
};
166+
167+
return ConductorAxisController;
168+
}
169+
);

0 commit comments

Comments
 (0)