Skip to content

Commit

Permalink
Merge pull request ngageoint#657 in WV/opensphere from ~WELCHD/opensp…
Browse files Browse the repository at this point in the history
…here:THIN-12907 to release

* commit '480f87c28ff30eec03440da6da02a8ba1e20a86d':
  feat(timeline): Change svg click handler to mouse up instead
  feat(timeline): Show current time above data, add click, update less
  • Loading branch information
welchyd committed Mar 1, 2019
2 parents 20bd3c4 + 480f87c commit 3dc5692
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 46 deletions.
7 changes: 5 additions & 2 deletions scss/os/_timeline.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
background: $u-theme-variables--bg-offset;
border-bottom: 1px solid $border-color;
border-top: 1px solid $border-color;
margin-top: .25rem;
z-index: 200;
}

Expand Down Expand Up @@ -43,13 +42,17 @@
@include grab-cursor();
fill: darken($u-theme-variables--bg-offset, 10%);
fill-opacity: .5;
width: 100%;
}

.c-svg-timeline__background-future.dragging {
@include grabbing-cursor();
}

.c-svg-timeline__current-time {
fill: $gray-300;
font-weight: bold;
}

.c-svg-timeline__axis-background {
fill: darken($u-theme-variables--bg-offset, 5);
fill-opacity: .8;
Expand Down
14 changes: 13 additions & 1 deletion src/os/ui/timeline/brush.js
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,10 @@ os.ui.timeline.Brush.prototype.initSVG = function(container, height) {
this.render(height);

if (this.drawFlagCheck()) { // draw flags
group.selectAll('.resize').append('polygon').attr('points', '0,0 0,-10 10,-10 10,-4');
group.selectAll('.resize').
append('polygon').
attr('points', '0,0 0,-10 10,-10 10,-4').
on('mouseout', this.showTimeText_);
group.select('.resize.w > polygon').attr('transform', 'scale(-1, 1)');
}
};
Expand Down Expand Up @@ -779,6 +782,15 @@ os.ui.timeline.Brush.prototype.onBrushDeleteButtonOut = function() {
};


/**
* Handler for brush mouse leave
* This covers an edge case where hovering the current time text then over a brush can cause the text to still be hidden
*/
os.ui.timeline.Brush.prototype.showTimeText_ = function() {
d3.select('.js-svg-timeline__current-time-placeholder').attr('href', '#js-svg-timeline__current-time');
};


/**
* Updates the button location for this instance.
*/
Expand Down
150 changes: 108 additions & 42 deletions src/os/ui/timeline/currenttimemarker.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
goog.provide('os.ui.timeline.CurrentTimeMarker');

goog.require('os.time.TimeInstant');
goog.require('os.ui.timeline.BaseItem');
goog.require('os.ui.timeline.ITimelineItem');
Expand All @@ -21,10 +20,23 @@ os.ui.timeline.CurrentTimeMarker = function() {
this.animationFrameRef_ = null;

/**
* @type {number?}
* @type {boolean}
* @private
*/
this.stopped_ = false;

/**
* @type {number}
* @private
*/
this.lastUpdateTime_ = 0;

/**
* The main background of the timeline
* @type {?d3.Selection}
* @private
*/
this.height_ = 0;
this.backgroundElement_ = null;
};
goog.inherits(os.ui.timeline.CurrentTimeMarker, os.ui.timeline.BaseItem);

Expand All @@ -33,9 +45,7 @@ goog.inherits(os.ui.timeline.CurrentTimeMarker, os.ui.timeline.BaseItem);
* @inheritDoc
*/
os.ui.timeline.CurrentTimeMarker.prototype.dispose = function() {
if (this.animationFrameRef_) {
window.cancelAnimationFrame(this.animationFrameRef_);
}
this.stopAnimation_();
os.ui.timeline.CurrentTimeMarker.base(this, 'dispose');
};

Expand All @@ -44,13 +54,16 @@ os.ui.timeline.CurrentTimeMarker.prototype.dispose = function() {
* @inheritDoc
*/
os.ui.timeline.CurrentTimeMarker.prototype.initSVG = function(container, height) {
this.height_ = height;
var past = /** @type {d3.Selection} */ (container.append('g'));
past.append('rect').
attr('class', 'c-svg-timeline__background-future').
attr('height', '' + this.height_).
attr('width', '100%');
past.append('text').attr('class', 'label js-c-svg-timeline__current-time');
var background = /** @type {d3.Selection} */ (d3.select('.js-svg-timeline__background-group'));
this.backgroundElement_ = background.append('rect').attr('height', '100%').attr('width', '100%').
attr('class', 'c-svg-timeline__background-future js-svg-timeline__background-future').
on(goog.events.EventType.MOUSEDOWN, this.styleDragStart_.bind(this)).
on(goog.events.EventType.MOUSEUP, this.styleDragEnd_.bind(this)).
on(goog.events.EventType.MOUSEOUT, this.styleDragEnd_.bind(this));
var currentTime = /** @type {d3.Selection} */ (container.append('g')).style('cursor', 'pointer');
currentTime.attr('id', 'js-svg-timeline__time-background').append('title').text('Click to hide/show current time');
currentTime.append('rect').attr('class', 'js-svg-timeline__bg-time').attr('height', '16');
currentTime.append('text').attr('class', 'label c-svg-timeline__current-time js-svg-timeline__current-time');
this.animationFrameRef_ = window.requestAnimationFrame(this.updateCurrentTimeRAF.bind(this));
};

Expand All @@ -60,51 +73,104 @@ os.ui.timeline.CurrentTimeMarker.prototype.initSVG = function(container, height)
* @param {number} timestamp a DOMHighResTimeStamp indicating the point in time when RAF starts to excute
*/
os.ui.timeline.CurrentTimeMarker.prototype.updateCurrentTimeRAF = function(timestamp) {
this.updateCurrentTime(true);
this.updateCurrentTime();
};


/**
* Updates the current time clock and background
* @param {boolean=} opt_loop loop for request animation frame
* @param {boolean=} opt_immediate apply changes immediately
*/
os.ui.timeline.CurrentTimeMarker.prototype.updateCurrentTime = function(opt_loop) {
var times = this.getExtent();
var dates = [new Date(times[0]), new Date(times[1])];
var range = this.xScale.range();
var today = new Date();
var date = new os.time.TimeInstant(today).toISOString().split(' ');
// include offset block if there is one
var prettyDate = date.length === 2 ? date[1] : date.length === 3 ? date[1] + ' ' + date[2] : '';
var shade = d3.select('.c-svg-timeline__background-future');
var currentDateText = d3.select('.js-c-svg-timeline__current-time');

if (today > dates[0] && today < dates[1]) { // in view
var currentDiff = today - dates[0];
var ratio = currentDiff / (dates[1] - dates[0]);
var translate = range[1] * ratio;
var transformString = 'translate(' + (translate + prettyDate.length - 7) + ', ' + (this.height_ - 7) + ')';
shade.style('display', 'block').attr('transform', 'translate(' + translate + ', 0)');
currentDateText.style('display', 'block').text(prettyDate).attr('transform', transformString);
} else if (today > dates[0]) { // completely in past
shade.style('display', 'none');
currentDateText.style('display', 'none');
} else { // completely in future
shade.style('display', 'block').attr('transform', 'translate(0, 0)');
currentDateText.style('display', 'none');
os.ui.timeline.CurrentTimeMarker.prototype.updateCurrentTime = function(opt_immediate) {
var now = Date.now();
if (!this.stopped_ && (now - this.lastUpdateTime_ >= 1000 || opt_immediate)) { // run once per second
this.lastUpdateTime_ = now;
var times = this.getExtent();
var dates = [new Date(times[0]), new Date(times[1])];
var range = this.xScale.range();
var today = new Date();
var date = new os.time.TimeInstant(today).toISOString().split(' ');
var prettyDate = date.length === 2 ? date[1] : date.length === 3 ? date[1] + ' ' + date[2] : ''; // include offset
var timeBackground = d3.select('.js-svg-timeline__bg-time');
var currentDateText = d3.select('.js-svg-timeline__current-time');
var placeholder = d3.select('#js-svg-timeline__background-time-placeholder');

if (today > dates[0] && today < dates[1]) { // in view
var currentDiff = today - dates[0];
var ratio = currentDiff / (dates[1] - dates[0]);
var translate = range[1] * ratio;
this.backgroundElement_.style('display', 'block').attr('transform', 'translate(' + translate + ', 0)');
placeholder.style('display', 'block');

var transformString = 'translate(' + (translate + prettyDate.length - 5) + ', -4)';
currentDateText.style('display', 'block').text(prettyDate).attr('transform', transformString);

// fit background to text
var currentDateTextEl = currentDateText[0][0];
if (currentDateTextEl) {
var textRect = currentDateTextEl.getBBox();
timeBackground.style('display', 'block').attr('transform', transformString).
attr('x', textRect.x).attr('y', textRect.y).attr('width', textRect.width);
}
} else if (today > dates[0]) { // completely in past
this.backgroundElement_.style('display', 'none');
currentDateText.style('display', 'none');
timeBackground.style('display', 'none');
placeholder.style('display', 'none');
if (this.animationFrameRef_) {
window.cancelAnimationFrame(this.animationFrameRef_);
}
return;
} else { // completely in future
this.backgroundElement_.style('display', 'block').attr('transform', 'translate(0, 0)');
currentDateText.style('display', 'none');
timeBackground.style('display', 'none');
placeholder.style('display', 'none');
}
}

if (opt_loop) {
this.animationFrameRef_ = window.requestAnimationFrame(this.updateCurrentTimeRAF.bind(this));
this.animationFrameRef_ = window.requestAnimationFrame(this.updateCurrentTimeRAF.bind(this));
};


/**
* Append dragging classes to the timeline background element
* @private
*/
os.ui.timeline.CurrentTimeMarker.prototype.styleDragStart_ = function() {
this.backgroundElement_.classed('dragging', true);
};


/**
* Remove dragging classes from the timeline background element
* @private
*/
os.ui.timeline.CurrentTimeMarker.prototype.styleDragEnd_ = function() {
if (this.backgroundElement_) {
this.backgroundElement_.classed('dragging', false);
}
};


/**
* Stop updating the clock time
* @private
*/
os.ui.timeline.CurrentTimeMarker.prototype.stopAnimation_ = function() {
if (this.animationFrameRef_) {
window.cancelAnimationFrame(this.animationFrameRef_);
this.animationFrameRef_ = null;
}
this.stopped_ = true;
};


/**
* @inheritDoc
*/
os.ui.timeline.CurrentTimeMarker.prototype.render = function(opt_height) {
this.updateCurrentTime(false);
this.updateCurrentTime(true);
};


Expand Down
27 changes: 26 additions & 1 deletion src/os/ui/timeline/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ os.ui.timeline.TimelineCtrl.AXIS_WIDTH = 30;
/**
* @type {number}
*/
os.ui.timeline.TimelineCtrl.HANDLE_HEIGHT = 10;
os.ui.timeline.TimelineCtrl.HANDLE_HEIGHT = 15;


/**
Expand Down Expand Up @@ -976,6 +976,10 @@ os.ui.timeline.TimelineCtrl.prototype.initSvg = function() {

// add place holder for hold and skip brushes
this.skipHoldElement_ = mainGroup.append('g').attr('class', 'skip-hold-brushes');
mainGroup.append('use').attr('href', '#js-svg-timeline__time-background').
attr('id', 'js-svg-timeline__background-time-placeholder').
on(goog.events.EventType.MOUSEUP, this.toggleVisible_.bind(this)).
append('title').text('Click to hide/show current time');

this.offArrows_.setXScale(this.xScale_);
this.offArrows_.setItems(this.items_.filter(
Expand All @@ -998,6 +1002,27 @@ os.ui.timeline.TimelineCtrl.prototype.initSvg = function() {
};


/**
* Handles click logic for hiding and showing the current time text
* In FF the front most element gets the click, in Chrome both elements get the click, so adjust accordingly
* @private
*/
os.ui.timeline.TimelineCtrl.prototype.toggleVisible_ = function() {
var opacity = d3.select('#js-svg-timeline__time-background').style('opacity');
if (opacity == '0') {
d3.select('#js-svg-timeline__time-background').style('opacity', '1').style('cursor', 'pointer').
on(goog.events.EventType.MOUSEUP, function() {});
d3.select('#js-svg-timeline__background-time-placeholder').attr('href', '#js-svg-timeline__time-background').
on(goog.events.EventType.MOUSEUP, this.toggleVisible_.bind(this));
} else {
d3.select('#js-svg-timeline__time-background').style('opacity', '0').style('cursor', 'cell').
on(goog.events.EventType.MOUSEUP, this.toggleVisible_.bind(this));
d3.select('#js-svg-timeline__background-time-placeholder').attr('href', '#js-svg-timeline__time-background-none').
on(goog.events.EventType.MOUSEUP, function() {});
}
};


/**
* Handles drag-to-pan start for items on edges
* @param {os.ui.timeline.DragPanEvent} event
Expand Down

0 comments on commit 3dc5692

Please sign in to comment.