From e11095968c514965ddad1f1bb9e81f0b6a298234 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Mon, 4 Aug 2014 21:41:07 -0700 Subject: [PATCH] Mousetracker Over/Out Tracking Fixes --- src/button.js | 7 ++ src/buttongroup.js | 6 + src/mousetracker.js | 238 +++++++++++++++++++++++++++++++++----- src/navigator.js | 6 + src/openseadragon.js | 2 +- src/referencestrip.js | 11 ++ src/viewer.js | 8 +- test/legacy.mouse.shim.js | 10 +- 8 files changed, 251 insertions(+), 37 deletions(-) diff --git a/src/button.js b/src/button.js index a83d40a6..b399ccd1 100644 --- a/src/button.js +++ b/src/button.js @@ -137,6 +137,11 @@ $.Button = function( options ) { this.tooltip; this.element.style.position = "relative"; + if ( this.element.style[ "touch-action" ] !== undefined ) { + this.element.style[ "touch-action" ] = "none"; + } else if ( this.element.style[ "-ms-touch-action" ] !== undefined ) { + this.element.style[ "-ms-touch-action" ] = "none"; + } this.imgGroup.style.position = this.imgHover.style.position = @@ -207,6 +212,7 @@ $.Button = function( options ) { clickDistThreshold: this.clickDistThreshold, enterHandler: function( event ) { + $.console.log('Enter ');// + event.currentTarget.className); if ( event.insideElementPressed ) { inTo( _this, $.ButtonState.DOWN ); /** @@ -241,6 +247,7 @@ $.Button = function( options ) { }, exitHandler: function( event ) { + $.console.log('Exit ');// + event.currentTarget.className); outTo( _this, $.ButtonState.GROUP ); if ( event.insideElementPressed ) { /** diff --git a/src/buttongroup.js b/src/buttongroup.js index a05e9084..51bb5642 100644 --- a/src/buttongroup.js +++ b/src/buttongroup.js @@ -80,6 +80,12 @@ $.ButtonGroup = function( options ) { } } + if ( this.element.style[ "touch-action" ] !== undefined ) { + this.element.style[ "touch-action" ] = "none"; + } else if ( this.element.style[ "-ms-touch-action" ] !== undefined ) { + this.element.style[ "-ms-touch-action" ] = "none"; + } + /** * Tracks mouse/touch/key events accross the group of buttons. * @member {OpenSeadragon.MouseTracker} tracker diff --git a/src/mousetracker.js b/src/mousetracker.js index 03ed2b43..6d63b57f 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -205,6 +205,10 @@ gesturestart: function ( event ) { onGestureStart( _this, event ); }, gesturechange: function ( event ) { onGestureChange( _this, event ); }, + pointerover: function ( event ) { onPointerOver( _this, event ); }, + MSPointerOver: function ( event ) { onPointerOver( _this, event ); }, + pointerout: function ( event ) { onPointerOut( _this, event ); }, + MSPointerOut: function ( event ) { onPointerOut( _this, event ); }, pointerenter: function ( event ) { onPointerEnter( _this, event ); }, MSPointerEnter: function ( event ) { onPointerEnter( _this, event ); }, pointerleave: function ( event ) { onPointerLeave( _this, event ); }, @@ -217,6 +221,8 @@ MSPointerMove: function ( event ) { onPointerMove( _this, event ); }, pointercancel: function ( event ) { onPointerCancel( _this, event ); }, MSPointerCancel: function ( event ) { onPointerCancel( _this, event ); }, + pointerupcaptured: function ( event ) { onPointerUpCaptured( _this, event ); }, + pointermovecaptured: function ( event ) { onPointerMoveCaptured( _this, event ); }, tracking: false, @@ -812,32 +818,41 @@ } if ( window.PointerEvent ) { + $.console.log('***** Pointer Event Model'); // IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents) - $.MouseTracker.subscribeEvents.push( "pointerenter", "pointerleave", "pointerdown", "pointerup", "pointermove", "pointercancel" ); + $.MouseTracker.subscribeEvents.push( "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" ); $.MouseTracker.unprefixedPointerEvents = true; if( navigator.maxTouchPoints ) { $.MouseTracker.maxTouchPoints = navigator.maxTouchPoints; } else { $.MouseTracker.maxTouchPoints = 0; } - $.MouseTracker.haveTouchEnter = true; - $.MouseTracker.haveMouseEnter = true; + $.MouseTracker.haveTouchEnter = false; + $.MouseTracker.haveMouseEnter = false; } else if ( window.MSPointerEvent ) { + $.console.log('***** Pointer Event Model (Prefixed IE10)'); // IE10 - $.MouseTracker.subscribeEvents.push( "MSPointerEnter", "MSPointerLeave", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" ); + $.MouseTracker.subscribeEvents.push( "MSPointerOver", "MSPointerOut", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" ); $.MouseTracker.unprefixedPointerEvents = false; if( navigator.msMaxTouchPoints ) { $.MouseTracker.maxTouchPoints = navigator.msMaxTouchPoints; } else { $.MouseTracker.maxTouchPoints = 0; } - $.MouseTracker.haveTouchEnter = true; - $.MouseTracker.haveMouseEnter = true; + $.MouseTracker.haveTouchEnter = false; + $.MouseTracker.haveMouseEnter = false; } else { + $.console.log('***** Legacy Event Model'); // Legacy W3C mouse events // TODO: Favor mouseenter/mouseleave over mouseover/mouseout when Webkit browser support is better - $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" ); - $.MouseTracker.haveMouseEnter = false; + $.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" ); + //if ( $.Browser.vendor == $.BROWSERS.IE ) { + // $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" ); + // $.MouseTracker.haveMouseEnter = true; + //} else { + $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout" ); + $.MouseTracker.haveMouseEnter = false; + //} if ( 'ontouchstart' in window ) { // iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505) $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" ); @@ -1083,10 +1098,10 @@ var delegate = THIS[ tracker.hash ]; if ( !delegate.capturing ) { - if ( $.MouseTracker.supportsMouseCapture ) { - // IE<10, Firefox, other browsers with setCapture()/releaseCapture() - tracker.element.setCapture( true ); - } else { +// if ( $.MouseTracker.supportsMouseCapture ) { +// // IE<10, Firefox, other browsers with setCapture()/releaseCapture() +// tracker.element.setCapture( true ); +// } else { // For browsers without setCapture()/releaseCapture(), we emulate mouse capture by hanging listeners on the window object. // (Note we listen on the capture phase so the captured handlers will get called first) $.addEvent( @@ -1101,7 +1116,7 @@ delegate.mousemovecaptured, true ); - } +// } delegate.capturing = true; } } @@ -1116,10 +1131,10 @@ var delegate = THIS[ tracker.hash ]; if ( delegate.capturing ) { - if ( $.MouseTracker.supportsMouseCapture ) { - // IE<10, Firefox, other browsers with setCapture()/releaseCapture() - tracker.element.releaseCapture(); - } else { +// if ( $.MouseTracker.supportsMouseCapture ) { +// // IE<10, Firefox, other browsers with setCapture()/releaseCapture() +// tracker.element.releaseCapture(); +// } else { // For browsers without setCapture()/releaseCapture(), we emulate mouse capture by hanging listeners on the window object. // (Note we listen on the capture phase so the captured handlers will get called first) $.removeEvent( @@ -1134,7 +1149,7 @@ delegate.mouseupcaptured, true ); - } +// } delegate.capturing = false; } } @@ -1418,7 +1433,7 @@ event = $.getEvent( event ); - if ( this === event.relatedTarget || isParentChild( this, event.relatedTarget ) ) { + if ( isParentChild( event.currentTarget, event.relatedTarget ) ) {//this === event.relatedTarget || return; } @@ -1443,7 +1458,7 @@ event = $.getEvent( event ); - if ( this === event.relatedTarget || isParentChild( this, event.relatedTarget ) ) { + if ( isParentChild( event.currentTarget, event.relatedTarget ) ) {//this === event.relatedTarget || return; } @@ -1803,6 +1818,52 @@ } + /** + * @private + * @inner + */ + function onPointerOver( tracker, event ) { + var gPoint; + + if ( isParentChild( event.currentTarget, event.relatedTarget ) ) {//this === event.relatedTarget || + return; + } + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersEnter( tracker, event, [ gPoint ] ); + } + + + /** + * @private + * @inner + */ + function onPointerOut( tracker, event ) { + var gPoint; + + if ( isParentChild( event.currentTarget, event.relatedTarget ) ) {//this === event.relatedTarget || + return; + } + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersExit( tracker, event, [ gPoint ] ); + } + + /** * @private * @inner @@ -1841,6 +1902,72 @@ } + /** + * Begin capturing pointer events to the tracked element (pointer event model only). + * @private + * @inner + */ + function capturePointer( tracker ) { + var delegate = THIS[ tracker.hash ]; + + if ( !delegate.capturing ) { +// if ( $.MouseTracker.supportsMouseCapture ) { +// // IE<10, Firefox, other browsers with setCapture()/releaseCapture() +// tracker.element.setCapture( true ); +// } else { + // For browsers without setCapture()/releaseCapture(), we emulate mouse capture by hanging listeners on the window object. + // (Note we listen on the capture phase so the captured handlers will get called first) + $.addEvent( + window, + $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + delegate.pointerupcaptured, + true + ); + $.addEvent( + window, + $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + delegate.pointermovecaptured, + true + ); +// } + delegate.capturing = true; + } + } + + + /** + * Stop capturing pointer events to the tracked element (pointer event model only). + * @private + * @inner + */ + function releasePointer( tracker ) { + var delegate = THIS[ tracker.hash ]; + + if ( delegate.capturing ) { +// if ( $.MouseTracker.supportsMouseCapture ) { +// // IE<10, Firefox, other browsers with setCapture()/releaseCapture() +// tracker.element.releaseCapture(); +// } else { + // For browsers without setCapture()/releaseCapture(), we emulate mouse capture by hanging listeners on the window object. + // (Note we listen on the capture phase so the captured handlers will get called first) + $.removeEvent( + window, + $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + delegate.pointermovecaptured, + true + ); + $.removeEvent( + window, + $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + delegate.pointerupcaptured, + true + ); +// } + delegate.capturing = false; + } + } + + /** * @private * @inner @@ -1857,11 +1984,12 @@ }; if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { - if ( $.MouseTracker.unprefixedPointerEvents ) { - event.currentTarget.setPointerCapture( event.pointerId ); - } else { - event.currentTarget.msSetPointerCapture( event.pointerId ); - } +// if ( $.MouseTracker.unprefixedPointerEvents ) { +// event.currentTarget.setPointerCapture( event.pointerId ); +// } else { +// event.currentTarget.msSetPointerCapture( event.pointerId ); +// } + capturePointer( tracker ); $.stopEvent( event ); } @@ -1876,6 +2004,28 @@ * @inner */ function onPointerUp( tracker, event ) { + handlePointerUp( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onPointerUp is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onPointerUpCaptured( tracker, event ) { + handlePointerUp( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handlePointerUp( tracker, event ) { var gPoint; gPoint = { @@ -1887,11 +2037,13 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - if ( $.MouseTracker.unprefixedPointerEvents ) { - event.currentTarget.releasePointerCapture( event.pointerId ); - } else { - event.currentTarget.msReleasePointerCapture( event.pointerId ); - } +// if ( $.MouseTracker.unprefixedPointerEvents ) { +// event.currentTarget.releasePointerCapture( event.pointerId ); +// } else { +// event.currentTarget.msReleasePointerCapture( event.pointerId ); +// } + releasePointer( tracker ); +// $.stopEvent( event ); } } @@ -1901,6 +2053,28 @@ * @inner */ function onPointerMove( tracker, event ) { + handlePointerMove( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onPointerMove is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onPointerMoveCaptured( tracker, event ) { + handlePointerMove( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handlePointerMove( tracker, event ) { // Pointer changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height) var gPoint; @@ -1964,6 +2138,7 @@ gPoint.lastPos = gPoint.currentPos; gPoint.lastTime = gPoint.currentTime; +// $.console.log('startTrackingPointer() ', pointsList.getLength() + 1); return pointsList.add( gPoint ); } @@ -1999,6 +2174,7 @@ listLength = pointsList.getLength(); } +// $.console.log('stopTrackingPointer() ', listLength); return listLength; } @@ -2213,6 +2389,7 @@ } pointsList.contacts++; + $.console.log('contacts++ ', pointsList.contacts); if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, curGPoint ); @@ -2339,6 +2516,7 @@ // Pointer was activated in our element but could have been removed in any element since events are captured to our element pointsList.contacts--; + $.console.log('contacts-- ', pointsList.contacts); if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, updateGPoint ); diff --git a/src/navigator.js b/src/navigator.js index 2043a8f4..d27e58cf 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -112,6 +112,12 @@ $.Navigator = function( options ){ options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio; + if ( this.element.style[ "touch-action" ] !== undefined ) { + this.element.style[ "touch-action" ] = "none"; + } else if ( this.element.style[ "-ms-touch-action" ] !== undefined ) { + this.element.style[ "-ms-touch-action" ] = "none"; + } + this.borderWidth = 2; //At some browser magnification levels the display regions lines up correctly, but at some there appears to //be a one pixel gap. diff --git a/src/openseadragon.js b/src/openseadragon.js index 14ddd3d5..9b98ff76 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -2161,7 +2161,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ ) ); } else { - regex = new RegExp( "Trident/.*rv:([0-9]{1,}[.0-9]{0,}) "); + regex = new RegExp( "Trident/.*rv:([0-9]{1,}[.0-9]{0,})"); if ( regex.exec( ua ) !== null ) { $.Browser.vendor = $.BROWSERS.IE; $.Browser.version = parseFloat( RegExp.$1 ); diff --git a/src/referencestrip.js b/src/referencestrip.js index b7192517..c344c880 100644 --- a/src/referencestrip.js +++ b/src/referencestrip.js @@ -114,6 +114,12 @@ $.ReferenceStrip = function ( options ) { style.background = '#000'; style.position = 'relative'; + if ( this.element.style[ "touch-action" ] !== undefined ) { + this.element.style[ "touch-action" ] = "none"; + } else if ( this.element.style[ "-ms-touch-action" ] !== undefined ) { + this.element.style[ "-ms-touch-action" ] = "none"; + } + $.setElementOpacity( this.element, 0.8 ); this.viewer = viewer; @@ -189,6 +195,11 @@ $.ReferenceStrip = function ( options ) { element.style.cssFloat = 'left'; //Firefox element.style.styleFloat = 'left'; //IE element.style.padding = '2px'; + if ( element.style[ "touch-action" ] !== undefined ) { + element.style[ "touch-action" ] = "none"; + } else if ( element.style[ "-ms-touch-action" ] !== undefined ) { + element.style[ "-ms-touch-action" ] = "none"; + } element.innerTracker = new $.MouseTracker( { element: element, diff --git a/src/viewer.js b/src/viewer.js index aa4daa64..27a24cb2 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -276,10 +276,10 @@ $.Viewer = function( options ) { style.top = "0px"; style.left = "0px"; // Disable browser default touch handling - if (style["touch-action"] !== undefined) { - style["touch-action"] = "none"; - } else if (style["-ms-touch-action"] !== undefined) { - style["-ms-touch-action"] = "none"; + if ( style[ "touch-action" ] !== undefined ) { + style[ "touch-action" ] = "none"; + } else if ( style["-ms-touch-action"] !== undefined ) { + style[ "-ms-touch-action" ] = "none"; } }(this.canvas.style)); diff --git a/test/legacy.mouse.shim.js b/test/legacy.mouse.shim.js index 7a8ff7cc..4d27c39a 100644 --- a/test/legacy.mouse.shim.js +++ b/test/legacy.mouse.shim.js @@ -11,8 +11,14 @@ $.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" ); } - $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" ); - $.MouseTracker.haveMouseEnter = false; + $.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" ); + if ( $.Browser.vendor == $.BROWSERS.IE ) { + $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" ); + $.MouseTracker.haveMouseEnter = true; + } else { + $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout" ); + $.MouseTracker.haveMouseEnter = false; + } if ( 'ontouchstart' in window ) { // iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505) $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" );