Commit ff048e0d authored by timothy@apple.com's avatar timothy@apple.com
Browse files

Implement time range selection for TimelineOverview and TimelineRuler.

https://bugs.webkit.org/show_bug.cgi?id=126035

Reviewed by Joseph Pecoraro.

* UserInterface/TimelineContentView.js:
(WebInspector.TimelineContentView.prototype._update):
(WebInspector.TimelineContentView.prototype._recordingReset):
Properly update start time and the selection start time on reset.

* UserInterface/TimelineOverview.js:
(WebInspector.TimelineOverview):
(WebInspector.TimelineOverview.prototype.get selectionStartTime):
(WebInspector.TimelineOverview.prototype.set selectionStartTime):
(WebInspector.TimelineOverview.prototype.get selectionDuration):
(WebInspector.TimelineOverview.prototype.set selectionDuration):
Added selection getters and setters.

* UserInterface/TimelineRuler.css:
(.timeline-ruler.allows-time-range-selection):
(.timeline-ruler > *):
(.timeline-ruler > .header):
(.timeline-ruler > .selection-drag):
(.timeline-ruler > .selection-drag:active):
(.timeline-ruler > .selection-handle):
(.timeline-ruler > .selection-handle.left):
(.timeline-ruler > .selection-handle.right):
(.timeline-ruler > .shaded-area):
(.timeline-ruler > .shaded-area.left):
(.timeline-ruler > .shaded-area.right):
Added styles for the selection elements and tweaked pointer-events to allow
events on elements we expect.

* UserInterface/TimelineRuler.js:
(WebInspector.TimelineRuler):
(WebInspector.TimelineRuler.prototype.get allowsTimeRangeSelection): Added.
(WebInspector.TimelineRuler.prototype.set allowsTimeRangeSelection): Added.
(WebInspector.TimelineRuler.prototype.get selectionStartTime): Added.
(WebInspector.TimelineRuler.prototype.set selectionStartTime): Added.
(WebInspector.TimelineRuler.prototype.get selectionEndTime): Added.
(WebInspector.TimelineRuler.prototype.set selectionEndTime): Added.
(WebInspector.TimelineRuler.prototype.updateLayout):
(WebInspector.TimelineRuler.prototype._needsMarkerLayout.update):
(WebInspector.TimelineRuler.prototype._needsMarkerLayout):
(WebInspector.TimelineRuler.prototype._needsSelectionLayout.update):
(WebInspector.TimelineRuler.prototype._needsSelectionLayout):
(WebInspector.TimelineRuler.prototype._recalculate):
(WebInspector.TimelineRuler.prototype._updatePositionOfElement):
(WebInspector.TimelineRuler.prototype._updateMarkers):
(WebInspector.TimelineRuler.prototype._updateSelection): Added.
(WebInspector.TimelineRuler.prototype._dispatchTimeRangeSelectionChangedEvent):
(WebInspector.TimelineRuler.prototype._timelineMarkerTimeChanged):
(WebInspector.TimelineRuler.prototype._handleMouseDown): Added.
(WebInspector.TimelineRuler.prototype._handleMouseMove): Added.
(WebInspector.TimelineRuler.prototype._handleMouseUp): Added.
(WebInspector.TimelineRuler.prototype._handleSelectionHandleMouseDown): Added.
(WebInspector.TimelineRuler.prototype._handleSelectionHandleMouseMove): Added.
(WebInspector.TimelineRuler.prototype._handleSelectionHandleMouseUp): Added.
Create selection elements and handle mouse events for drag and move.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@162410 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ca968a0c
2013-12-19 Timothy Hatcher <timothy@apple.com>
Implement time range selection for TimelineOverview and TimelineRuler.
https://bugs.webkit.org/show_bug.cgi?id=126035
Reviewed by Joseph Pecoraro.
* UserInterface/TimelineContentView.js:
(WebInspector.TimelineContentView.prototype._update):
(WebInspector.TimelineContentView.prototype._recordingReset):
Properly update start time and the selection start time on reset.
* UserInterface/TimelineOverview.js:
(WebInspector.TimelineOverview):
(WebInspector.TimelineOverview.prototype.get selectionStartTime):
(WebInspector.TimelineOverview.prototype.set selectionStartTime):
(WebInspector.TimelineOverview.prototype.get selectionDuration):
(WebInspector.TimelineOverview.prototype.set selectionDuration):
Added selection getters and setters.
* UserInterface/TimelineRuler.css:
(.timeline-ruler.allows-time-range-selection):
(.timeline-ruler > *):
(.timeline-ruler > .header):
(.timeline-ruler > .selection-drag):
(.timeline-ruler > .selection-drag:active):
(.timeline-ruler > .selection-handle):
(.timeline-ruler > .selection-handle.left):
(.timeline-ruler > .selection-handle.right):
(.timeline-ruler > .shaded-area):
(.timeline-ruler > .shaded-area.left):
(.timeline-ruler > .shaded-area.right):
Added styles for the selection elements and tweaked pointer-events to allow
events on elements we expect.
* UserInterface/TimelineRuler.js:
(WebInspector.TimelineRuler):
(WebInspector.TimelineRuler.prototype.get allowsTimeRangeSelection): Added.
(WebInspector.TimelineRuler.prototype.set allowsTimeRangeSelection): Added.
(WebInspector.TimelineRuler.prototype.get selectionStartTime): Added.
(WebInspector.TimelineRuler.prototype.set selectionStartTime): Added.
(WebInspector.TimelineRuler.prototype.get selectionEndTime): Added.
(WebInspector.TimelineRuler.prototype.set selectionEndTime): Added.
(WebInspector.TimelineRuler.prototype.updateLayout):
(WebInspector.TimelineRuler.prototype._needsMarkerLayout.update):
(WebInspector.TimelineRuler.prototype._needsMarkerLayout):
(WebInspector.TimelineRuler.prototype._needsSelectionLayout.update):
(WebInspector.TimelineRuler.prototype._needsSelectionLayout):
(WebInspector.TimelineRuler.prototype._recalculate):
(WebInspector.TimelineRuler.prototype._updatePositionOfElement):
(WebInspector.TimelineRuler.prototype._updateMarkers):
(WebInspector.TimelineRuler.prototype._updateSelection): Added.
(WebInspector.TimelineRuler.prototype._dispatchTimeRangeSelectionChangedEvent):
(WebInspector.TimelineRuler.prototype._timelineMarkerTimeChanged):
(WebInspector.TimelineRuler.prototype._handleMouseDown): Added.
(WebInspector.TimelineRuler.prototype._handleMouseMove): Added.
(WebInspector.TimelineRuler.prototype._handleMouseUp): Added.
(WebInspector.TimelineRuler.prototype._handleSelectionHandleMouseDown): Added.
(WebInspector.TimelineRuler.prototype._handleSelectionHandleMouseMove): Added.
(WebInspector.TimelineRuler.prototype._handleSelectionHandleMouseUp): Added.
Create selection elements and handle mouse events for drag and move.
2013-12-17 Timothy Hatcher <timothy@apple.com>
Support scroll to zoom in TimelineOverview.
......
......@@ -192,7 +192,13 @@ WebInspector.TimelineContentView.prototype = {
this._currentTimeMarker.time = currentTime;
this._timelineOverview.startTime = startTime;
if (this._startTimeNeedsReset && !isNaN(startTime)) {
var selectionOffset = this._timelineOverview.selectionStartTime - this._timelineOverview.startTime;
this._timelineOverview.startTime = startTime;
this._timelineOverview.selectionStartTime = startTime + selectionOffset;
delete this._startTimeNeedsReset;
}
this._timelineOverview.endTime = Math.max(endTime, currentTime);
// Force a layout now since we are already in an animation frame and don't need to delay it until the next.
......@@ -233,6 +239,7 @@ WebInspector.TimelineContentView.prototype = {
_recordingReset: function(event)
{
this._startTimeNeedsReset = true;
this._currentTimeMarker.time = 0;
this._overviewTimelineView.reset();
......
......@@ -38,12 +38,14 @@ WebInspector.TimelineOverview = function()
this._timelineRuler = new WebInspector.TimelineRuler;
this._timelineRuler.allowsClippedLabels = true;
this._timelineRuler.allowsTimeRangeSelection = true;
this._scrollContainer.appendChild(this._timelineRuler.element);
this._endTime = 0;
this.startTime = 0;
this.secondsPerPixel = 0.0025;
this.selectionDuration = 5;
};
WebInspector.TimelineOverview.StyleClassName = "timeline-overview";
......@@ -108,6 +110,31 @@ WebInspector.TimelineOverview.prototype = {
this._needsLayout();
},
get selectionStartTime()
{
return this._timelineRuler.selectionStartTime;
},
set selectionStartTime(x)
{
x = x || 0;
var selectionDuration = this.selectionDuration;
this._timelineRuler.selectionStartTime = x;
this._timelineRuler.selectionEndTime = x + selectionDuration;
},
get selectionDuration()
{
return this._timelineRuler.selectionEndTime - this._timelineRuler.selectionStartTime;
},
set selectionDuration(x)
{
x = Math.max(WebInspector.TimelineRuler.MinimumSelectionTimeRange, x);
this._timelineRuler.selectionEndTime = this._timelineRuler.selectionStartTime + x;
},
addMarker: function(marker)
{
this._timelineRuler.addMarker(marker);
......
......@@ -28,12 +28,22 @@
pointer-events: none;
}
.timeline-ruler.allows-time-range-selection {
pointer-events: all;
}
.timeline-ruler > * {
pointer-events: none;
}
.timeline-ruler > .header {
border-bottom: 1px solid rgb(200, 200, 200);
position: absolute;
top: 0;
left: 0;
right: 0;
height: 22px;
position: relative;
}
.timeline-ruler > .header > .divider {
......@@ -115,3 +125,50 @@
.timeline-ruler > .markers > .marker.timestamp {
border-left-color: rgba(0, 110, 0, 0.5);
}
.timeline-ruler > .selection-drag {
position: absolute;
top: 0;
height: 22px;
cursor: -webkit-grab;
pointer-events: all;
}
.timeline-ruler > .selection-drag:active {
cursor: -webkit-grabbing;
}
.timeline-ruler > .selection-handle {
position: absolute;
top: 0;
width: 8px;
height: 21px;
border-radius: 5px;
background-color: rgb(164, 164, 164);
border: 1px solid white;
cursor: col-resize;
pointer-events: all;
}
.timeline-ruler > .selection-handle.left {
-webkit-transform: translateX(-4px);
}
.timeline-ruler > .selection-handle.right {
-webkit-transform: translateX(4px);
}
.timeline-ruler > .shaded-area {
position: absolute;
top: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.1);
}
.timeline-ruler > .shaded-area.left {
left: 0;
}
.timeline-ruler > .shaded-area.right {
right: 0;
}
......@@ -43,8 +43,11 @@ WebInspector.TimelineRuler = function()
this._endTime = 0;
this._duration = NaN;
this._secondsPerPixel = 0;
this._selectionStartTime = 0;
this._selectionEndTime = Infinity;
this._endTimePinned = false;
this._allowsClippedLabels = false;
this._allowsTimeRangeSelection = false;
this._markerElementMap = new Map;
}
......@@ -53,12 +56,23 @@ WebInspector.TimelineRuler.MinimumLeftDividerSpacing = 48;
WebInspector.TimelineRuler.MinimumDividerSpacing = 64;
WebInspector.TimelineRuler.StyleClassName = "timeline-ruler";
WebInspector.TimelineRuler.AllowsTimeRangeSelectionStyleClassName = "allows-time-range-selection";
WebInspector.TimelineRuler.HeaderElementStyleClassName = "header";
WebInspector.TimelineRuler.DividerElementStyleClassName = "divider";
WebInspector.TimelineRuler.DividerLabelElementStyleClassName = "label";
WebInspector.TimelineRuler.MarkersElementStyleClassName = "markers";
WebInspector.TimelineRuler.BaseMarkerElementStyleClassName = "marker";
WebInspector.TimelineRuler.ShadedAreaElementStyleClassName = "shaded-area";
WebInspector.TimelineRuler.SelectionDragElementStyleClassName = "selection-drag";
WebInspector.TimelineRuler.SelectionHandleElementStyleClassName = "selection-handle";
WebInspector.TimelineRuler.LeftSelectionElementStyleClassName = "left";
WebInspector.TimelineRuler.RightSelectionElementStyleClassName = "right";
WebInspector.TimelineRuler.MinimumSelectionTimeRange = 0.1;
WebInspector.TimelineRuler.Event = {
TimeRangeSelectionChanged: "time-ruler-time-range-selection-changed"
};
WebInspector.TimelineRuler.prototype = {
constructor: WebInspector.TimelineRuler,
......@@ -70,11 +84,6 @@ WebInspector.TimelineRuler.prototype = {
return this._element;
},
get headerElement()
{
return this._headerElement;
},
get allowsClippedLabels()
{
return this._allowsClippedLabels
......@@ -90,6 +99,62 @@ WebInspector.TimelineRuler.prototype = {
this._needsLayout();
},
get allowsTimeRangeSelection()
{
return this._allowsTimeRangeSelection;
},
set allowsTimeRangeSelection(x)
{
if (this._allowsTimeRangeSelection === x)
return;
this._allowsTimeRangeSelection = x || false;
if (x) {
this._mouseDownEventListener = this._handleMouseDown.bind(this);
this._element.addEventListener("mousedown", this._mouseDownEventListener);
this._leftShadedAreaElement = document.createElement("div");
this._leftShadedAreaElement.classList.add(WebInspector.TimelineRuler.ShadedAreaElementStyleClassName);
this._leftShadedAreaElement.classList.add(WebInspector.TimelineRuler.LeftSelectionElementStyleClassName);
this._rightShadedAreaElement = document.createElement("div");
this._rightShadedAreaElement.classList.add(WebInspector.TimelineRuler.ShadedAreaElementStyleClassName);
this._rightShadedAreaElement.classList.add(WebInspector.TimelineRuler.RightSelectionElementStyleClassName);
this._leftSelectionHandleElement = document.createElement("div");
this._leftSelectionHandleElement.classList.add(WebInspector.TimelineRuler.SelectionHandleElementStyleClassName);
this._leftSelectionHandleElement.classList.add(WebInspector.TimelineRuler.LeftSelectionElementStyleClassName);
this._leftSelectionHandleElement.addEventListener("mousedown", this._handleSelectionHandleMouseDown.bind(this));
this._rightSelectionHandleElement = document.createElement("div");
this._rightSelectionHandleElement.classList.add(WebInspector.TimelineRuler.SelectionHandleElementStyleClassName);
this._rightSelectionHandleElement.classList.add(WebInspector.TimelineRuler.RightSelectionElementStyleClassName);
this._rightSelectionHandleElement.addEventListener("mousedown", this._handleSelectionHandleMouseDown.bind(this));
this._selectionDragElement = document.createElement("div");
this._selectionDragElement.classList.add(WebInspector.TimelineRuler.SelectionDragElementStyleClassName);
this._needsSelectionLayout();
} else {
this._element.removeEventListener("mousedown", this._mouseDownEventListener);
delete this._mouseDownEventListener;
this._leftShadedAreaElement.remove();
this._rightShadedAreaElement.remove();
this._leftSelectionHandleElement.remove();
this._rightSelectionHandleElement.remove();
this._selectionDragElement.remove();
delete this._leftShadedAreaElement;
delete this._rightShadedAreaElement;
delete this._leftSelectionHandleElement;
delete this._rightSelectionHandleElement;
delete this._selectionDragElement;
}
},
get zeroTime()
{
return this._zeroTime;
......@@ -183,6 +248,38 @@ WebInspector.TimelineRuler.prototype = {
this._needsLayout();
},
get selectionStartTime()
{
return this._selectionStartTime;
},
set selectionStartTime(x)
{
if (this._selectionStartTime === x)
return;
this._selectionStartTime = x || 0;
this._timeRangeSelectionChanged = true;
this._needsSelectionLayout();
},
get selectionEndTime()
{
return this._selectionEndTime;
},
set selectionEndTime(x)
{
if (this._selectionEndTime === x)
return;
this._selectionEndTime = x || 0;
this._timeRangeSelectionChanged = true;
this._needsSelectionLayout();
},
addMarker: function(marker)
{
console.assert(marker instanceof WebInspector.TimelineMarker);
......@@ -292,8 +389,8 @@ WebInspector.TimelineRuler.prototype = {
continue;
}
this._updateLeftPositionOfElement(dividerElement, newLeftPosition, visibleWidth);
this._updateLeftPositionOfElement(markerDividerElement, newLeftPosition, visibleWidth);
this._updatePositionOfElement(dividerElement, newLeftPosition, visibleWidth);
this._updatePositionOfElement(markerDividerElement, newLeftPosition, visibleWidth);
dividerElement._labelElement.textContent = isNaN(dividerTime) ? "" : Number.secondsToString(dividerTime - this._zeroTime, true);
dividerElement = dividerElement.nextSibling;
......@@ -310,6 +407,7 @@ WebInspector.TimelineRuler.prototype = {
markerDividers[i].remove();
this._updateMarkers(visibleWidth, duration);
this._updateSelection(visibleWidth, duration);
},
// Private
......@@ -324,6 +422,11 @@ WebInspector.TimelineRuler.prototype = {
delete this._scheduledMarkerLayoutUpdateIdentifier;
}
if (this._scheduledSelectionLayoutUpdateIdentifier) {
cancelAnimationFrame(this._scheduledSelectionLayoutUpdateIdentifier);
delete this._scheduledSelectionLayoutUpdateIdentifier;
}
this._scheduledLayoutUpdateIdentifier = requestAnimationFrame(this.updateLayout.bind(this));
},
......@@ -340,7 +443,7 @@ WebInspector.TimelineRuler.prototype = {
{
delete this._scheduledMarkerLayoutUpdateIdentifier;
var visibleWidth = this._headerElement.clientWidth;
var visibleWidth = this._element.clientWidth;
if (visibleWidth <= 0)
return;
......@@ -350,9 +453,35 @@ WebInspector.TimelineRuler.prototype = {
this._scheduledMarkerLayoutUpdateIdentifier = requestAnimationFrame(update.bind(this));
},
_needsSelectionLayout: function()
{
if (!this._allowsTimeRangeSelection)
return;
// If layout is scheduled, abort since the selection will be updated when layout happens.
if (this._scheduledLayoutUpdateIdentifier)
return;
if (this._scheduledSelectionLayoutUpdateIdentifier)
return;
function update()
{
delete this._scheduledSelectionLayoutUpdateIdentifier;
var visibleWidth = this._element.clientWidth;
if (visibleWidth <= 0)
return;
this._updateSelection(visibleWidth, this.duration);
}
this._scheduledSelectionLayoutUpdateIdentifier = requestAnimationFrame(update.bind(this));
},
_recalculate: function()
{
var visibleWidth = this._headerElement.clientWidth;
var visibleWidth = this._element.clientWidth;
if (visibleWidth <= 0)
return 0;
......@@ -369,31 +498,235 @@ WebInspector.TimelineRuler.prototype = {
return visibleWidth;
},
_updateLeftPositionOfElement: function(element, newLeftPosition, visibleWidth)
_updatePositionOfElement: function(element, newPosition, visibleWidth, property)
{
newLeftPosition *= this._endTimePinned ? 100 : visibleWidth;
newLeftPosition = newLeftPosition.toFixed(2);
property = property || "left";
newPosition *= this._endTimePinned ? 100 : visibleWidth;
newPosition = newPosition.toFixed(2);
var currentLeftPosition = parseFloat(element.style.left).toFixed(2);
if (currentLeftPosition !== newLeftPosition)
element.style.left = newLeftPosition + (this._endTimePinned ? "%" : "px");
var currentPosition = parseFloat(element.style[property]).toFixed(2);
if (currentPosition !== newPosition)
element.style[property] = newPosition + (this._endTimePinned ? "%" : "px");
},
_updateMarkers: function(visibleWidth, duration)
{
if (this._scheduledMarkerLayoutUpdateIdentifier) {
cancelAnimationFrame(this._scheduledMarkerLayoutUpdateIdentifier);
delete this._scheduledMarkerLayoutUpdateIdentifier;
}
this._markerElementMap.forEach(function(markerElement, marker) {
var newLeftPosition = (marker.time - this._startTime) / duration;
this._updateLeftPositionOfElement(markerElement, newLeftPosition, visibleWidth);
this._updatePositionOfElement(markerElement, newLeftPosition, visibleWidth);
if (!markerElement.parentNode)
this._markersElement.appendChild(markerElement);
}, this);
},
_updateSelection: function(visibleWidth, duration)
{
if (this._scheduledSelectionLayoutUpdateIdentifier) {
cancelAnimationFrame(this._scheduledSelectionLayoutUpdateIdentifier);
delete this._scheduledSelectionLayoutUpdateIdentifier;
}
this._element.classList.toggle(WebInspector.TimelineRuler.AllowsTimeRangeSelectionStyleClassName, this._allowsTimeRangeSelection);
if (!this._allowsTimeRangeSelection)
return;
var newLeftPosition = Math.max(0, (this._selectionStartTime - this._startTime) / duration);
this._updatePositionOfElement(this._leftShadedAreaElement, newLeftPosition, visibleWidth, "width");
this._updatePositionOfElement(this._leftSelectionHandleElement, newLeftPosition, visibleWidth, "left");
this._updatePositionOfElement(this._selectionDragElement, newLeftPosition, visibleWidth, "left");
var newRightPosition = 1 - Math.min((this._selectionEndTime - this._startTime) / duration, 1);
this._updatePositionOfElement(this._rightShadedAreaElement, newRightPosition, visibleWidth, "width");
this._updatePositionOfElement(this._rightSelectionHandleElement, newRightPosition, visibleWidth, "right");
this._updatePositionOfElement(this._selectionDragElement, newRightPosition, visibleWidth, "right");
if (!this._selectionDragElement.parentNode) {
this._element.appendChild(this._selectionDragElement);
this._element.appendChild(this._leftShadedAreaElement);
this._element.appendChild(this._leftSelectionHandleElement);
this._element.appendChild(this._rightShadedAreaElement);
this._element.appendChild(this._rightSelectionHandleElement);
}
if (this._timeRangeSelectionChanged)
this._dispatchTimeRangeSelectionChangedEvent();
},
_dispatchTimeRangeSelectionChangedEvent: function()
{
delete this._timeRangeSelectionChanged;
if (this._suppressTimeRangeSelectionChangedEvent)
return;
this.dispatchEventToListeners(WebInspector.TimelineRuler.Event.TimeRangeSelectionChanged);
},
_timelineMarkerTimeChanged: function()
{
this._needsMarkerLayout();
},
_handleMouseDown: function(event)
{
// Only handle left mouse clicks.
if (event.button !== 0 || event.ctrlKey)
return;
this._selectionIsMove = event.target === this._selectionDragElement;
this._suppressTimeRangeSelectionChangedEvent = !this._selectionIsMove;
if (this._selectionIsMove)
this._lastMousePosition = event.pageX;
else
this._mouseDownPosition = event.pageX - this._element.totalOffsetLeft;
this._mouseMoveEventListener = this._handleMouseMove.bind(this);
this._mouseUpEventListener = this._handleMouseUp.bind(this);
// Register these listeners on the document so we can track the mouse if it leaves the ruler.
document.addEventListener("mousemove", this._mouseMoveEventListener);
document.addEventListener("mouseup", this._mouseUpEventListener);
event.preventDefault();
event.stopPropagation();
},
_handleMouseMove: function(event)
{
console.assert(event.button === 0);
if (this._selectionIsMove) {
var currentMousePosition = event.pageX;
var offsetTime = (currentMousePosition - this._lastMousePosition) * this.secondsPerPixel;
var selectionDuration = this.selectionEndTime - this.selectionStartTime;
this.selectionStartTime = Math.max(this.startTime, Math.min(this.selectionStartTime + offsetTime, this.endTime - selectionDuration));
this.selectionEndTime = this.selectionStartTime + selectionDuration;
this._lastMousePosition = currentMousePosition;
} else {
var currentMousePosition = event.pageX - this._element.totalOffsetLeft;
this.selectionStartTime = Math.max(this.startTime, this.startTime + (Math.min(currentMousePosition, this._mouseDownPosition) * this.secondsPerPixel));
this.selectionEndTime = Math.min(this.startTime + (Math.max(currentMousePosition, this._mouseDownPosition) * this.secondsPerPixel), this.endTime);
}
this._updateSelection(this._element.clientWidth, this.duration);
event.preventDefault();
event.stopPropagation();
},
_handleMouseUp: function(event)
{
console.assert(event.button === 0);
if (!this._selectionIsMove && this.selectionEndTime - this.selectionStartTime < WebInspector.TimelineRuler.MinimumSelectionTimeRange) {
// The section is smaller than allowed, grow in the direction of the drag to meet the minumum.
var currentMousePosition = event.pageX - this._element.totalOffsetLeft;
if (currentMousePosition > this._mouseDownPosition) {
this.selectionEndTime = Math.min(this.selectionStartTime + WebInspector.TimelineRuler.MinimumSelectionTimeRange, this.endTime);
this.selectionStartTime = this.selectionEndTime - WebInspector.TimelineRuler.MinimumSelectionTimeRange;
} else {
this.selectionStartTime = Math.max(this.startTime, this.selectionEndTime - WebInspector.TimelineRuler.MinimumSelectionTimeRange);