From 6835cab8d5aff48e96362414e5bd06c7db9418f0 Mon Sep 17 00:00:00 2001 From: Paul Felix Date: Tue, 12 Feb 2013 10:09:58 -0500 Subject: [PATCH] Fix for Issue 378: Mouse gradually drifts off of range selection handle --- plugins/range-selector.js | 67 ++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/plugins/range-selector.js b/plugins/range-selector.js index 70b8065..08d04ac 100644 --- a/plugins/range-selector.js +++ b/plugins/range-selector.js @@ -265,7 +265,7 @@ rangeSelector.prototype.createZoomHandles_ = function() { rangeSelector.prototype.initInteraction_ = function() { var self = this; var topElem = this.isIE_ ? document : window; - var xLast = 0; + var pageXLast = 0; var handle = null; var isZooming = false; var isPanning = false; @@ -278,7 +278,7 @@ rangeSelector.prototype.initInteraction_ = function() { // functions, defined below. Defining them this way (rather than with // "function foo() {...}" makes JSHint happy. var toXDataWindow, onZoomStart, onZoom, onZoomEnd, doZoom, isMouseInPanZone, - onPanStart, onPan, onPanEnd, doPan, onCanvasMouseMove, applyBrowserZoomLevel; + onPanStart, onPan, onPanEnd, doPan, onCanvasHover, getCursorPageX; // Touch event functions var onZoomHandleTouchEvent, onCanvasTouchEvent, addTouchEvents; @@ -291,22 +291,27 @@ rangeSelector.prototype.initInteraction_ = function() { return [xDataMin, xDataMax]; }; - applyBrowserZoomLevel = function(delX) { - var zoom = window.outerWidth/document.documentElement.clientWidth; - if (!isNaN(zoom)) { - return delX/zoom; + getCursorPageX = function(e) { + if (e.pageX !== null) { + return e.pageX; } else { - return delX; + // Taken from jQuery. + var target = e.target || e.srcElement || document; + var eventDoc = target.ownerDocument || target.document || document; + var doc = eventDoc.documentElement, body = eventDoc.body; + return e.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); } }; onZoomStart = function(e) { Dygraph.cancelEvent(e); isZooming = true; - xLast = e.screenX; + pageXLast = getCursorPageX(e); handle = e.target ? e.target : e.srcElement; - self.dygraph_.addEvent(topElem, 'mousemove', onZoom); - self.dygraph_.addEvent(topElem, 'mouseup', onZoomEnd); + if (e.type === 'mousedown' || e.type === 'dragstart') { + Dygraph.addEvent(topElem, 'mousemove', onZoom); + Dygraph.addEvent(topElem, 'mouseup', onZoomEnd); + } self.fgcanvas_.style.cursor = 'col-resize'; tarp.cover(); return true; @@ -317,23 +322,23 @@ rangeSelector.prototype.initInteraction_ = function() { return false; } Dygraph.cancelEvent(e); - var delX = e.screenX - xLast; - if (Math.abs(delX) < 4 || e.screenX === 0) { - // First iPad move event seems to have screenX = 0 + + var pageX = getCursorPageX(e); + var delX = pageX - pageXLast; + if (Math.abs(delX) < 4) { return true; } - xLast = e.screenX; - delX = applyBrowserZoomLevel(delX); + pageXLast = pageX; // Move handle. var zoomHandleStatus = self.getZoomHandleStatus_(); var newPos; if (handle == self.leftZoomHandle_) { - newPos = zoomHandleStatus.leftHandlePos + delX; + newPos = pageX; newPos = Math.min(newPos, zoomHandleStatus.rightHandlePos - handle.width - 3); newPos = Math.max(newPos, self.canvasRect_.x); } else { - newPos = zoomHandleStatus.rightHandlePos + delX; + newPos = pageX; newPos = Math.min(newPos, self.canvasRect_.x + self.canvasRect_.w); newPos = Math.max(newPos, zoomHandleStatus.leftHandlePos + handle.width + 3); } @@ -396,9 +401,11 @@ rangeSelector.prototype.initInteraction_ = function() { if (!isPanning && isMouseInPanZone(e) && self.getZoomHandleStatus_().isZoomed) { Dygraph.cancelEvent(e); isPanning = true; - xLast = e.screenX; - self.dygraph_.addEvent(topElem, 'mousemove', onPan); - self.dygraph_.addEvent(topElem, 'mouseup', onPanEnd); + pageXLast = getCursorPageX(e); + if (e.type === 'mousedown') { + Dygraph.addEvent(topElem, 'mousemove', onPan); + Dygraph.addEvent(topElem, 'mouseup', onPanEnd); + } return true; } return false; @@ -410,12 +417,12 @@ rangeSelector.prototype.initInteraction_ = function() { } Dygraph.cancelEvent(e); - var delX = e.screenX - xLast; + var pageX = getCursorPageX(e); + var delX = pageX - pageXLast; if (Math.abs(delX) < 4) { return true; } - xLast = e.screenX; - delX = applyBrowserZoomLevel(delX); + pageXLast = pageX; // Move range view var zoomHandleStatus = self.getZoomHandleStatus_(); @@ -468,7 +475,7 @@ rangeSelector.prototype.initInteraction_ = function() { } }; - onCanvasMouseMove = function(e) { + onCanvasHover = function(e) { if (isZooming || isPanning) { return; } @@ -509,7 +516,7 @@ rangeSelector.prototype.initInteraction_ = function() { addTouchEvents = function(elem, fn) { var types = ['touchstart', 'touchend', 'touchmove', 'touchcancel']; for (var i = 0; i < types.length; i++) { - self.dygraph_.addEvent(elem, types[i], fn); + Dygraph.addEvent(elem, types[i], fn); } }; @@ -517,14 +524,14 @@ rangeSelector.prototype.initInteraction_ = function() { this.setDefaultOption_('panEdgeFraction', 0.0001); var dragStartEvent = window.opera ? 'mousedown' : 'dragstart'; - this.dygraph_.addEvent(this.leftZoomHandle_, dragStartEvent, onZoomStart); - this.dygraph_.addEvent(this.rightZoomHandle_, dragStartEvent, onZoomStart); + Dygraph.addEvent(this.leftZoomHandle_, dragStartEvent, onZoomStart); + Dygraph.addEvent(this.rightZoomHandle_, dragStartEvent, onZoomStart); if (this.isUsingExcanvas_) { - this.dygraph_.addEvent(this.iePanOverlay_, 'mousedown', onPanStart); + Dygraph.addEvent(this.iePanOverlay_, 'mousedown', onPanStart); } else { - this.dygraph_.addEvent(this.fgcanvas_, 'mousedown', onPanStart); - this.dygraph_.addEvent(this.fgcanvas_, 'mousemove', onCanvasMouseMove); + Dygraph.addEvent(this.fgcanvas_, 'mousedown', onPanStart); + Dygraph.addEvent(this.fgcanvas_, 'mousemove', onCanvasHover); } // Touch events -- 2.7.4