Fallback to mouseover/mouseout,

This commit is contained in:
Mark Salsbery 2014-04-15 13:04:08 -07:00
parent e8e0f28f5a
commit 9b15ca090b
4 changed files with 201 additions and 72 deletions

View File

@ -8,7 +8,6 @@ OPENSEADRAGON CHANGELOG
* The overlays elements are no longer accessible via viewer.canvas.childNodes but via viewer.overlaysContainer.childNodes or viewer.currentOverlays[i].element.
* BREAKING CHANGE: Pseudo full screen mode on IE<11 using activex has been dropped. OpenSeadragon will run in full page if full screen mode is requested.
* BREAKING CHANGE: MouseTracker touch pinch gestures are no longer converted to scroll events. MouseTracker.pinchHandler should be used instead. (#369)
* BREAKING CHANGE: MouseTracker now uses pointer enter/leave DOM events instead of pointer over/out DOM events for generating enterHandler/exitHandler events and for tracking pointers inside the hit-test bounds of the tracked element. (#369)
* DEPRECATION: overlay functions have been moved from Drawer to Viewer (#331)
* DEPRECATION: OpenSeadragon.cancelFullScreen has been renamed OpenSeadragon.exitFullScreen (#358)
* DEPRECATION: The 'isTouchEvent' property passed in MouseTracker events is deprecated and has been replaced with 'pointerType', which is a String value "mouse", "touch", "pen", etc. to support multiple simultaneous pointing devices (#369)

View File

@ -163,6 +163,8 @@
DOMMouseScroll: function ( event ) { onMouseWheel( _this, event ); },
MozMousePixelScroll: function ( event ) { onMouseWheel( _this, event ); },
mouseover: function ( event ) { onMouseOver( _this, event ); },
mouseout: function ( event ) { onMouseOut( _this, event ); },
mouseenter: function ( event ) { onMouseEnter( _this, event ); },
mouseleave: function ( event ) { onMouseLeave( _this, event ); },
mousedown: function ( event ) { onMouseDown( _this, event ); },
@ -761,6 +763,7 @@
$.MouseTracker.maxTouchPoints = 0;
}
$.MouseTracker.haveTouchEnter = true;
$.MouseTracker.haveMouseEnter = true;
} else if ( window.MSPointerEvent ) {
// IE10
$.MouseTracker.subscribeEvents.push( "MSPointerEnter", "MSPointerLeave", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" );
@ -771,9 +774,17 @@
$.MouseTracker.maxTouchPoints = 0;
}
$.MouseTracker.haveTouchEnter = true;
$.MouseTracker.haveMouseEnter = true;
} else {
// Legacy W3C mouse events
$.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave", "mousedown", "mouseup", "mousemove" );
$.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" );
if ( 'onmouseenter' in window ) {
$.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" );
@ -862,7 +873,6 @@
this.buttons = 0;
/**
* Current number of contact points (touch points, mouse down, etc.) for the device.
* Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.
* @member {Number} contacts
* @memberof OpenSeadragon.MouseTracker.GesturePointList#
*/
@ -1313,6 +1323,72 @@
}
/**
* @private
* @inner
*/
function isParentChild( parent, child )
{
if ( parent === child ) {
return false;
}
while ( child && child !== parent ) {
child = child.parentNode;
}
return child === parent;
}
/**
* @private
* @inner
*/
function onMouseOver( tracker, event ) {
var gPoint;
event = $.getEvent( event );
if ( this === event.relatedTarget || isParentChild( this, event.relatedTarget ) ) {
return;
}
gPoint = {
id: $.MouseTracker.mousePointerId,
type: 'mouse',
isPrimary: true,
currentPos: getMouseAbsolute( event ),
currentTime: $.now()
};
updatePointersEnter( tracker, event, [ gPoint ] );
}
/**
* @private
* @inner
*/
function onMouseOut( tracker, event ) {
var gPoint;
event = $.getEvent( event );
if ( this === event.relatedTarget || isParentChild( this, event.relatedTarget ) ) {
return;
}
gPoint = {
id: $.MouseTracker.mousePointerId,
type: 'mouse',
isPrimary: true,
currentPos: getMouseAbsolute( event ),
currentTime: $.now()
};
updatePointersExit( tracker, event, [ gPoint ] );
}
/**
* @private
* @inner
@ -1330,7 +1406,7 @@
currentTime: $.now()
};
updatePointersOver( tracker, event, [ gPoint ] );
updatePointersEnter( tracker, event, [ gPoint ] );
}
@ -1351,7 +1427,7 @@
currentTime: $.now()
};
updatePointersOut( tracker, event, [ gPoint ] );
updatePointersExit( tracker, event, [ gPoint ] );
}
@ -1493,7 +1569,7 @@
} );
}
updatePointersOver( tracker, event, gPoints );
updatePointersEnter( tracker, event, gPoints );
}
@ -1516,7 +1592,7 @@
} );
}
updatePointersOut( tracker, event, gPoints );
updatePointersExit( tracker, event, gPoints );
}
@ -1544,7 +1620,7 @@
// simulate touchenter if not natively available
if ( !$.MouseTracker.haveTouchEnter ) {
updatePointersOver( tracker, event, gPoints );
updatePointersEnter( tracker, event, gPoints );
}
if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact
@ -1584,7 +1660,7 @@
// simulate touchleave if not natively available
if ( !$.MouseTracker.haveTouchEnter && touchCount > 0 ) {
updatePointersOut( tracker, event, gPoints );
updatePointersExit( tracker, event, gPoints );
}
$.stopEvent( event );
@ -1675,7 +1751,7 @@
currentTime: $.now()
};
updatePointersOver( tracker, event, [ gPoint ] );
updatePointersEnter( tracker, event, [ gPoint ] );
}
@ -1694,7 +1770,7 @@
currentTime: $.now()
};
updatePointersOut( tracker, event, [ gPoint ] );
updatePointersExit( tracker, event, [ gPoint ] );
}
@ -1871,7 +1947,7 @@
* @param {Array.<OpenSeadragon.MouseTracker.GesturePoint>} gPoints
* Gesture points associated with the event.
*/
function updatePointersOver( tracker, event, gPoints ) {
function updatePointersEnter( tracker, event, gPoints ) {
var pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
i,
gPointCount = gPoints.length,
@ -1935,7 +2011,7 @@
* @param {Array.<OpenSeadragon.MouseTracker.GesturePoint>} gPoints
* Gesture points associated with the event.
*/
function updatePointersOut( tracker, event, gPoints ) {
function updatePointersExit( tracker, event, gPoints ) {
var delegate = THIS[ tracker.hash ],
pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
i,

View File

@ -27,8 +27,10 @@
// ----------
asyncTest( 'MouseTracker: mouse gestures', function () {
var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ),
simEvent = {},
offset = $canvas.offset(),
tracker = viewer.innerTracker,
intervalId,
origEnterHandler,
origExitHandler,
origPressHandler,
@ -47,7 +49,9 @@
dragEndCount,
insideElementPressed,
insideElementReleased,
quickClick;
quickClick,
speed,
direction;
var hookViewerHandlers = function () {
origEnterHandler = tracker.enterHandler;
@ -119,6 +123,8 @@
origDragEndHandler = tracker.dragEndHandler;
tracker.dragEndHandler = function ( event ) {
dragEndCount++;
speed = event.speed;
direction = event.direction;
if (origDragEndHandler) {
return origDragEndHandler( event );
} else {
@ -138,40 +144,76 @@
tracker.dragEndHandler = origDragEndHandler;
};
var simulateEnter = function ($element, event, x, y) {
event.clientX = offset.left + x;
event.clientY = offset.top + y;
$canvas.simulate( 'mouseenter', event );
var simulateEnter = function ($element, x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mouseenter', simEvent );
};
var simulateLeave = function ($element, event, x, y) {
event.clientX = offset.left + x;
event.clientY = offset.top + y;
$canvas.simulate( 'mouseleave', event );
var simulateLeave = function ($element, x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mouseleave', simEvent );
};
var simulateMove = function ($element, event, dX, dY, count) {
var simulateMove = function ($element, dX, dY, count) {
var i;
for ( i = 0; i < count; i++ ) {
event.clientX += dX;
event.clientY += dY;
$canvas.simulate( 'mousemove', event );
simEvent.clientX += dX;
simEvent.clientY += dY;
$canvas.simulate( 'mousemove', simEvent );
}
};
var simulateDown = function ($element, event, x, y) {
event.clientX = offset.left + x;
event.clientY = offset.top + y;
$canvas.simulate( 'mousedown', event );
var simulateTimedMove = function ($element, dX, dY, count, ms, doneCallback) {
var msInterval = Math.floor(ms / count),
dX = dX,
dY = dY,
i = count,
doneCallback = doneCallback,
moves = 0;
intervalId = window.setInterval(function () {
if (i > 0) {
moves++;
//simEvent.clientX += dX;
//simEvent.clientY += dY;
//$canvas.simulate( 'mousemove', simEvent );
}
i--;
if (i === 0) {
window.clearInterval( intervalId );
doneCallback();
}
}, msInterval );
//for ( i = 0; i < count; i++ ) {
// simEvent.clientX += dX;
// simEvent.clientY += dY;
// $canvas.simulate( 'mousemove', simEvent );
// targetTime = msWait + OpenSeadragon.now();
// while (OpenSeadragon.now() < targetTime) {}
//}
};
var simulateUp = function ($element, event, x, y) {
event.clientX = offset.left + x;
event.clientY = offset.top + y;
$canvas.simulate( 'mouseup', event );
var simulateDown = function ($element, x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mousedown', simEvent );
};
var simulateUp = function ($element, x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mouseup', simEvent );
};
var resetForAssessment = function () {
simEvent = {
clientX: offset.left,
clientY: offset.top
};
enterCount = 0;
exitCount = 0;
pressCount = 0;
@ -183,6 +225,8 @@
insideElementPressed = false;
insideElementReleased = false;
quickClick = false;
speed = 0;
direction = 2 * Math.PI;
};
var assessGestureExpectations = function (expected) {
@ -226,9 +270,18 @@
if ('quickClick' in expected) {
equal( quickClick, expected.quickClick, expected.description + 'clickHandler event.quick matches expected (' + expected.quickClick + ')' );
}
if ('speed' in expected) {
equal( speed, expected.speed, expected.description + 'Drag speed matches expected (' + expected.speed + ')' );
}
if ('direction' in expected) {
equal( direction, expected.direction, expected.description + 'Drag direction matches expected (' + expected.direction + ')' );
}
};
var onOpen = function ( event ) {
var timeStart,
timeElapsed;
viewer.removeHandler( 'open', onOpen );
hookViewerHandlers();
@ -236,11 +289,10 @@
// enter-move-release (release in tracked element, press in unknown element)
// (Note we also test to see if the pointer is still being tracked by not simulating a leave event until after assessment)
resetForAssessment();
var event = {};
simulateEnter($canvas, event, 0, 0);
simulateMove($canvas, event, 1, 1, 10);
simulateMove($canvas, event, -1, -1, 10);
simulateUp($canvas, event, 0, 0);
simulateEnter($canvas, 0, 0);
simulateMove($canvas, 1, 1, 10);
simulateMove($canvas, -1, -1, 10);
simulateUp($canvas, 0, 0);
assessGestureExpectations({
description: 'enter-move-release (release in tracked element, press in unknown element): ',
enterCount: 1,
@ -257,15 +309,14 @@
trackedPointers: 1
//quickClick: false
});
simulateLeave($canvas, event, -1, -1); // flush tracked pointer
simulateLeave($canvas, -1, -1); // flush tracked pointer
// enter-move-exit (fly-over)
resetForAssessment();
var event = {};
simulateEnter($canvas, event, 0, 0);
simulateMove($canvas, event, 1, 1, 10);
simulateMove($canvas, event, -1, -1, 10);
simulateLeave($canvas, event, -1, -1);
simulateEnter($canvas, 0, 0);
simulateMove($canvas, 1, 1, 10);
simulateMove($canvas, -1, -1, 10);
simulateLeave($canvas, -1, -1);
assessGestureExpectations({
description: 'enter-move-exit (fly-over): ',
enterCount: 1,
@ -285,10 +336,9 @@
// move-exit (fly-over, no enter event)
resetForAssessment();
var event = {};
simulateMove($canvas, event, 1, 1, 10);
simulateMove($canvas, event, -1, -1, 10);
simulateLeave($canvas, event, -1, -1);
simulateMove($canvas, 1, 1, 10);
simulateMove($canvas, -1, -1, 10);
simulateLeave($canvas, -1, -1);
assessGestureExpectations({
description: 'move-exit (fly-over, no enter event): ',
enterCount: 0,
@ -308,11 +358,10 @@
// enter-press-release-exit
resetForAssessment();
var event = {};
simulateEnter($canvas, event, 0, 0);
simulateDown($canvas, event, 0, 0);
simulateUp($canvas, event, 0, 0);
simulateLeave($canvas, event, -1, -1);
simulateEnter($canvas, 0, 0);
simulateDown($canvas, 0, 0);
simulateUp($canvas, 0, 0);
simulateLeave($canvas, -1, -1);
assessGestureExpectations({
description: 'enter-press-release-exit (click): ',
enterCount: 1,
@ -332,22 +381,21 @@
// enter-press-move-release-move-exit (drag, release in tracked element)
resetForAssessment();
var event = {};
simulateEnter($canvas, event, 0, 0);
simulateDown($canvas, event, 0, 0);
simulateMove($canvas, event, 1, 1, 10);
simulateUp($canvas, event, 10, 10);
simulateMove($canvas, event, -1, -1, 10);
simulateLeave($canvas, event, -1, -1);
simulateEnter($canvas, 0, 0);
simulateDown($canvas, 0, 0);
simulateMove($canvas, 1, 1, 100);
simulateUp($canvas, 10, 10);
simulateMove($canvas, -1, -1, 100);
simulateLeave($canvas, -1, -1);
assessGestureExpectations({
description: 'enter-press-move-release-move-exit (drag, release in tracked element): ',
enterCount: 1,
exitCount: 1,
pressCount: 1,
releaseCount: 1,
moveCount: 20,
moveCount: 200,
clickCount: 1,
dragCount: 10,
dragCount: 100,
dragEndCount: 1,
insideElementPressed: true,
insideElementReleased: true,
@ -358,14 +406,13 @@
// enter-press-move-exit-move-release (drag, release outside tracked element)
resetForAssessment();
var event = {};
simulateEnter($canvas, event, 0, 0);
simulateDown($canvas, event, 0, 0);
simulateMove($canvas, event, 1, 1, 5);
simulateMove($canvas, event, -1, -1, 5);
simulateLeave($canvas, event, -1, -1);
simulateMove($canvas, event, -1, -1, 5);
simulateUp($canvas, event, -5, -5);
simulateEnter($canvas, 0, 0);
simulateDown($canvas, 0, 0);
simulateMove($canvas, 1, 1, 5);
simulateMove($canvas, -1, -1, 5);
simulateLeave($canvas, -1, -1);
simulateMove($canvas, -1, -1, 5);
simulateUp($canvas, -5, -5);
assessGestureExpectations({
description: 'enter-press-move-exit-move-release (drag, release outside tracked element): ',
enterCount: 1,

View File

@ -11,7 +11,14 @@
$.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" );
}
$.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave", "mousedown", "mouseup", "mousemove" );
$.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" );
if ( 'onmouseenter' in window ) {
$.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" );