diff --git a/changelog.txt b/changelog.txt
index 7fe59d18..e8dbe41b 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -7,9 +7,13 @@ OPENSEADRAGON CHANGELOG
* The drawer element is no longer accessible via viewer.canvas.firstChild but via viewer.drawersContainer.firstChild or viewer.drawer.canvas.
* 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", or "" to support multiple simultaneous pointing devices (#369)
+* 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)
+* DEPRECATION: The 'buttonDownAny' property passed in MouseTracker enter and exit events (enterHandler/exitHandler) is deprecated and has been replaced with 'buttons', which indicates the button(s) currently pressed (#369)
+* DEPRECATION: The 'buttonDownAny' property passed in Viewer's 'container-enter' and 'container-exit' events is deprecated and has been replaced with 'buttons', which indicates the button(s) currently pressed (#369)
* Added layers support. Multiple images can now been displayed on top of each other with transparency via the Viewer.addLayer method (#298)
* Improved overlay functions (#331)
* Fixed: Nav button highlight states aren't quite aligned on Firefox (#303)
@@ -28,7 +32,7 @@ OPENSEADRAGON CHANGELOG
* Added optimization for large numbers of overlays: `checkResize = false` option for OpenSeadragon.Overlay (#365)
* Updated full screen API, adding support for Opera and IE11 and allowing keyboard input in Chrome (#358)
* Enhanced MouseTracker for multi-touch (#369)
- * Added support for multiple touch-points on multiple/simultaneous pointing devices
+ * Added support for tracking multiple touch-points on multiple/simultaneous pointing devices
* Added support for the W3C Pointer Events event model. Enables touch/multi-touch on IE10+
* Added a dragEndHandler event callback, called when a drag gesture ends
* Added a pinchHandler event callback, called as a pinch gesture (2 touch points) is occurring
diff --git a/src/mousetracker.js b/src/mousetracker.js
index d7e4cb1c..09a5a8f5 100644
--- a/src/mousetracker.js
+++ b/src/mousetracker.js
@@ -34,15 +34,13 @@
(function ( $ ) {
- // is any button currently being pressed while pointer events occur
- var IS_BUTTON_DOWN = false,
// dictionary from hash to private properties
- THIS = {};
+ var THIS = {};
/**
* @class MouseTracker
- * @classdesc Provides simplified handling of common pointing device (mouse, touch, pen) and keyboard
+ * @classdesc Provides simplified handling of common pointer device (mouse, touch, pen, etc.) and keyboard
* events on a specific element, like 'enter', 'exit', 'press', 'release',
* 'scroll', 'click', and 'drag'.
*
@@ -148,7 +146,7 @@
/**
* @private
* @property {Boolean} tracking
- * Are we currently tracking pointer events.
+ * Are we currently tracking pointer events for this element.
* @property {Boolean} capturing
* Are we curruently capturing mouse events (legacy mouse events only).
*/
@@ -165,15 +163,13 @@
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 ); },
mouseup: function ( event ) { onMouseUp( _this, event ); },
mouseupcaptured: function ( event ) { onMouseUpCaptured( _this, event ); },
- //mouseupcapturedie: function ( event ) { onMouseUpCapturedIE( _this, event ); },
mousemove: function ( event ) { onMouseMove( _this, event ); },
mousemovecaptured: function ( event ) { onMouseMoveCaptured( _this, event ); },
- //mousemovecapturedie: function ( event ) { onMouseMoveCapturedIE( _this, event ); },
touchenter: function ( event ) { onTouchEnter( _this, event ); },
touchleave: function ( event ) { onTouchLeave( _this, event ); },
@@ -185,10 +181,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 ); },
+ MSPointerLeave: function ( event ) { onPointerLeave( _this, event ); },
pointerdown: function ( event ) { onPointerDown( _this, event ); },
MSPointerDown: function ( event ) { onPointerDown( _this, event ); },
pointerup: function ( event ) { onPointerUp( _this, event ); },
@@ -199,12 +195,16 @@
MSPointerCancel: function ( event ) { onPointerCancel( _this, event ); },
tracking: false,
+
+ // Active pointers lists. Array of GesturePointList objects, one for each pointer device type.
+ // GesturePointList objects are added each time a pointer is tracked by a new pointer device type (see getActivePointersListByType()).
+ // Active pointers are any pointer being tracked for this element which are in the hit-test area
+ // of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.
+ activePointersLists: [],
+
+ // Legacy mouse event tracking
capturing: false,
- // Active Contact Points
- mousePoints: new $.MouseTracker.GesturePointList(),
- touchPoints: new $.MouseTracker.GesturePointList(),
- penPoints: new $.MouseTracker.GesturePointList(),
// Tracking for pinch gesture
pinchGPoints: [],
lastPinchDist: 0,
@@ -252,6 +252,30 @@
return this;
},
+ /**
+ * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for the given pointer device type,
+ * creating and caching a new {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} if one doesn't already exist for the type.
+ * @function
+ * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc.
+ * @returns {OpenSeadragon.MouseTracker.GesturePointList}
+ */
+ getActivePointersListByType: function ( type ) {
+ var delegate = THIS[ this.hash ],
+ i,
+ len = delegate.activePointersLists.length,
+ list;
+
+ for ( i = 0; i < len; i++ ) {
+ if ( delegate.activePointersLists[ i ].type === type ) {
+ return delegate.activePointersLists[ i ];
+ }
+ }
+
+ list = new $.MouseTracker.GesturePointList( type );
+ delegate.activePointersLists.push( list );
+ return list;
+ },
+
/**
* Implement or assign implementation to these handlers during or after
* calling the constructor.
@@ -260,14 +284,17 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
+ * @param {Number} event.buttons
+ * Current buttons pressed.
+ * 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.
* @param {Boolean} event.insideElementPressed
* True if the left mouse button is currently being pressed and was
* initiated inside the tracked element, otherwise false.
* @param {Boolean} event.buttonDownAny
- * Was the button down anywhere in the screen during the event.
+ * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.
* @param {Boolean} event.isTouchEvent
* True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.
* @param {Object} event.originalEvent
@@ -287,14 +314,17 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
+ * @param {Number} event.buttons
+ * Current buttons pressed.
+ * 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.
* @param {Boolean} event.insideElementPressed
* True if the left mouse button is currently being pressed and was
* initiated inside the tracked element, otherwise false.
* @param {Boolean} event.buttonDownAny
- * Was the button down anywhere in the screen during the event.
+ * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.
* @param {Boolean} event.isTouchEvent
* True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.
* @param {Object} event.originalEvent
@@ -314,9 +344,12 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
+ * @param {Number} event.buttons
+ * Current buttons pressed.
+ * 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.
* @param {Boolean} event.isTouchEvent
* True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.
* @param {Object} event.originalEvent
@@ -336,14 +369,17 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
+ * @param {Number} event.buttons
+ * Current buttons pressed.
+ * 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.
* @param {Boolean} event.insideElementPressed
* True if the left mouse button is currently being pressed and was
* initiated inside the tracked element, otherwise false.
* @param {Boolean} event.insideElementReleased
- * True if the cursor still inside the tracked element when the button was released.
+ * True if the cursor inside the tracked element when the button was released.
* @param {Boolean} event.isTouchEvent
* True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.
* @param {Object} event.originalEvent
@@ -363,9 +399,12 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
+ * @param {Number} event.buttons
+ * Current buttons pressed.
+ * 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.
* @param {Boolean} event.isTouchEvent
* True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.
* @param {Object} event.originalEvent
@@ -385,7 +424,7 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
* @param {Number} event.scroll
@@ -411,10 +450,10 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
- * @param {Number} event.quick
+ * @param {Boolean} event.quick
* True only if the clickDistThreshold and clickDeltaThreshold are both passed. Useful for ignoring events.
* @param {Boolean} event.shift
* True if the shift key was pressed during this event.
@@ -437,14 +476,17 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
+ * @param {Number} event.buttons
+ * Current buttons pressed.
+ * 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.
* @param {OpenSeadragon.Point} event.delta
* The x,y components of the difference between the current position and the last drag event position. Useful for ignoring or weighting the events.
- * @param {Number} speed
+ * @param {Number} event.speed
* Current computed speed, in pixels per second.
- * @property {Number} direction
+ * @param {Number} event.direction
* Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.
* @param {Boolean} event.shift
* True if the shift key was pressed during this event.
@@ -467,12 +509,12 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
- * @param {Number} speed
+ * @param {Number} event.speed
* Speed at the end of a drag gesture, in pixels per second.
- * @property {Number} direction
+ * @param {Number} event.direction
* Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.
* @param {Boolean} event.shift
* True if the shift key was pressed during this event.
@@ -495,7 +537,7 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {Array.} event.gesturePoints
* Gesture points associated with the gesture. Velocity data can be found here.
* @param {OpenSeadragon.Point} event.lastCenter
@@ -525,9 +567,12 @@
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
- * "mouse", "touch", "pen", or "".
+ * "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
+ * @param {Number} event.buttons
+ * Current buttons pressed.
+ * 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.
* @param {Boolean} event.isTouchEvent
* True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.
* @param {Object} event.originalEvent
@@ -595,12 +640,12 @@
/**
* Provides continuous computation of velocity (speed and direction) of active pointers.
- * This is a singleton, used by all MouseTracker instances. Currently it is extremely unlikely there will ever be more than
+ * This is a singleton, used by all MouseTracker instances, as it is unlikely there will ever be more than
* two active gesture pointers at a time.
*
+ * @private
* @member gesturePointVelocityTracker
* @memberof OpenSeadragon.MouseTracker
- * @private
*/
$.MouseTracker.gesturePointVelocityTracker = (function () {
var trackerPoints = [],
@@ -652,7 +697,7 @@
lastPos: gPoint.currentPos
} );
- // Only fire up the interval timer when there's gesture points to track
+ // Only fire up the interval timer when there's gesture pointers to track
if ( trackerPoints.length === 1 ) {
lastTime = $.now();
intervalId = window.setInterval( _doTracking, 50 );
@@ -667,7 +712,7 @@
for ( i = 0; i < len; i++ ) {
if ( trackerPoints[ i ].guid === guid ) {
trackerPoints.splice( i, 1 );
- // Only run the interval timer if theres gesture points to track
+ // Only run the interval timer if theres gesture pointers to track
len--;
if ( len === 0 ) {
window.clearInterval( intervalId );
@@ -685,7 +730,7 @@
///////////////////////////////////////////////////////////////////////////////
-// Event model detection
+// Pointer event model and feature detection
///////////////////////////////////////////////////////////////////////////////
/**
@@ -708,39 +753,38 @@
if ( window.PointerEvent ) {
// IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents)
- $.MouseTracker.subscribeEvents.push( "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" );
+ $.MouseTracker.subscribeEvents.push( "pointerenter", "pointerleave", "pointerdown", "pointerup", "pointermove", "pointercancel" );
$.MouseTracker.unprefixedPointerEvents = true;
if( navigator.maxTouchPoints ) {
$.MouseTracker.maxTouchPoints = navigator.maxTouchPoints;
- }
- else {
+ } else {
$.MouseTracker.maxTouchPoints = 0;
}
- }
- else if ( window.MSPointerEvent ) {
+ $.MouseTracker.haveTouchEnter = true;
+ } else if ( window.MSPointerEvent ) {
// IE10
- $.MouseTracker.subscribeEvents.push( "MSPointerOver", "MSPointerOut", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" );
+ $.MouseTracker.subscribeEvents.push( "MSPointerEnter", "MSPointerLeave", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" );
$.MouseTracker.unprefixedPointerEvents = false;
if( navigator.msMaxTouchPoints ) {
$.MouseTracker.maxTouchPoints = navigator.msMaxTouchPoints;
- }
- else {
+ } else {
$.MouseTracker.maxTouchPoints = 0;
}
- }
- else {
+ $.MouseTracker.haveTouchEnter = true;
+ } else {
// Legacy W3C mouse events
- $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" );
+ $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave", "mousedown", "mouseup", "mousemove" );
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" );
if ( 'ontouchenter' in window ) {
$.MouseTracker.subscribeEvents.push( "touchenter", "touchleave" );
$.MouseTracker.haveTouchEnter = true;
- }
- else {
+ } else {
$.MouseTracker.haveTouchEnter = false;
}
+ } else {
+ $.MouseTracker.haveTouchEnter = false;
}
if ( 'ongesturestart' in window ) {
// iOS (see https://developer.apple.com/library/safari/documentation/UserExperience/Reference/GestureEventClassReference/GestureEvent/GestureEvent.html)
@@ -757,7 +801,7 @@
///////////////////////////////////////////////////////////////////////////////
/**
- * Represents a point of contact on the screen made by a mouse cursor, pen, touch, or other pointing device.
+ * Represents a point of contact on the screen made by a mouse cursor, pen, touch, or other pointer device.
*
* @typedef {Object} GesturePoint
* @memberof OpenSeadragon.MouseTracker
@@ -765,7 +809,9 @@
* @property {Number} id
* Identifier unique from all other active GesturePoints for a given pointer device.
* @property {String} type
- * The pointer device type: "mouse", "touch", "pen", or "".
+ * The pointer device type: "mouse", "touch", "pen", etc.
+ * @property {Boolean} captured
+ * True if events for the gesture point are captured to the tracked element.
* @property {Boolean} isPrimary
* True if the gesture point is a master pointer amongst the set of active pointers for each pointer type. True for mouse and primary (first) touch/pen pointers.
* @property {Boolean} insideElementPressed
@@ -776,10 +822,10 @@
* Current computed speed, in pixels per second.
* @property {Number} direction
* Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.
- * @property {OpenSeadragon.Point} startPos
- * The initial pointer position, relative to the page including any scrolling.
- * @property {Number} startTime
- * The initial pointer contact time, in milliseconds.
+ * @property {OpenSeadragon.Point} contactPos
+ * The initial pointer contact position, relative to the page including any scrolling. Only valid if the pointer has contact (pressed, touch contact, pen contact).
+ * @property {Number} contactTime
+ * The initial pointer contact time, in milliseconds. Only valid if the pointer has contact (pressed, touch contact, pen contact).
* @property {OpenSeadragon.Point} lastPos
* The last pointer position, relative to the page including any scrolling.
* @property {Number} lastTime
@@ -791,14 +837,36 @@
*/
- /***
+ /**
* @class GesturePointList
- * @classdesc Provides an abstraction for a set of {@link OpenSeadragon.MouseTracker.GesturePoint} objects.
+ * @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type.
+ * Active pointers are any pointer being tracked for this element which are in the hit-test area
+ * of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.
* @memberof OpenSeadragon.MouseTracker
- * @private
+ * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc.
*/
- $.MouseTracker.GesturePointList = function () {
+ $.MouseTracker.GesturePointList = function ( type ) {
this._gPoints = [];
+ /**
+ * The pointer device type: "mouse", "touch", "pen", etc.
+ * @member {String} type
+ * @memberof OpenSeadragon.MouseTracker.GesturePointList#
+ */
+ this.type = type;
+ /**
+ * Current buttons pressed 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} buttons
+ * @memberof OpenSeadragon.MouseTracker.GesturePointList#
+ */
+ 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#
+ */
+ this.contacts = 0;
};
$.MouseTracker.GesturePointList.prototype = /** @lends OpenSeadragon.MouseTracker.GesturePointList.prototype */{
/**
@@ -949,8 +1017,9 @@
if ( delegate.setCaptureCapable ) {
// IE<10, Firefox, other browsers with setCapture()/releaseCapture()
tracker.element.setCapture( true );
- }
- else {
+ } 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,
"mouseup",
@@ -981,8 +1050,9 @@
if ( delegate.setCaptureCapable ) {
// IE<10, Firefox, other browsers with setCapture()/releaseCapture()
tracker.element.releaseCapture();
- }
- else {
+ } 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,
"mousemove",
@@ -1001,32 +1071,9 @@
}
- /**
- * @private
- * @inner
- */
- function getGPointsListByType( tracker, type ) {
- var delegate = THIS[ tracker.hash ],
- list;
- if ( type === 'mouse' ) {
- list = delegate.mousePoints;
- }
- else if ( type === 'touch' ) {
- list = delegate.touchPoints;
- }
- else if ( type === 'pen' ) {
- list = delegate.penPoints;
- }
- else {
- list = null;
- }
- return list;
- }
-
-
/**
* Gets a W3C Pointer Events model compatible pointer type string from a DOM pointer event.
- * IE10 used a long integer value, but the W3C specification (and IE11+) use a string "mouse", "touch", "pen", or "".
+ * IE10 used a long integer value, but the W3C specification (and IE11+) use a string "mouse", "touch", "pen", etc.
* @private
* @inner
*/
@@ -1034,8 +1081,7 @@
var pointerTypeStr;
if ( $.MouseTracker.unprefixedPointerEvents ) {
pointerTypeStr = event.pointerType;
- }
- else {
+ } else {
// IE10
// MSPOINTER_TYPE_TOUCH: 0x00000002
// MSPOINTER_TYPE_PEN: 0x00000003
@@ -1094,7 +1140,7 @@
///////////////////////////////////////////////////////////////////////////////
-// DOM event handlers
+// Device-specific DOM event handlers
///////////////////////////////////////////////////////////////////////////////
/**
@@ -1228,526 +1274,6 @@
}
- /**
- * @private
- * @inner
- */
- function onMouseOver( tracker, event ) {
- var gPoint;
-
- event = $.getEvent( event );
-
- gPoint = {
- id: $.MouseTracker.mousePointerId,
- type: 'mouse',
- isPrimary: true,
- insideElement: true,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- updatePointersOver( tracker, event, [ gPoint ] );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onMouseOut( tracker, event ) {
- var gPoint;
-
- event = $.getEvent( event );
-
- gPoint = {
- id: $.MouseTracker.mousePointerId,
- type: 'mouse',
- isPrimary: true,
- insideElement: false,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- updatePointersOut( tracker, event, [ gPoint ] );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onMouseDown( tracker, event ) {
- var gPoint;
-
- event = $.getEvent( event );
-
- if ( event.button == 2 ) {
- return;
- }
-
- if ( tracker.pressHandler || tracker.clickHandler || tracker.dragHandler ) {
- captureMouse( tracker );
- }
-
- gPoint = {
- id: $.MouseTracker.mousePointerId,
- type: 'mouse',
- isPrimary: true,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- addPointers( tracker, event, [ gPoint ] );
-
- if ( tracker.pressHandler || tracker.clickHandler || tracker.dragHandler ) {
- $.cancelEvent( event );
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onMouseUp( tracker, event ) {
- var delegate = THIS[ tracker.hash ];
-
- if ( !delegate.capturing || delegate.setCaptureCapable ) {
- handleMouseUp( tracker, event );
- }
-
- if ( delegate.capturing ) {
- releaseMouse( tracker );
- }
- }
-
- /**
- * This handler is attached to the window object to emulate mouse capture.
- * Only triggered in older W3C browsers that don't have setCapture/releaseCapture
- * methods or don't support the new pointer events model.
- * onMouseUp is still called on the tracked element, so avoid processing twice.
- * @private
- * @inner
- */
- function onMouseUpCaptured( tracker, event ) {
- var delegate = THIS[ tracker.hash ];
-
- handleMouseUp( tracker, event );
-
- if ( delegate.capturing ) {
- releaseMouse( tracker );
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onMouseMove( tracker, event ) {
- var delegate = THIS[ tracker.hash ];
- if ( !delegate.capturing || delegate.setCaptureCapable ) {
- handleMouseMove( tracker, event );
- }
- }
-
-
- /**
- * This handler is attached to the window object to emulate mouse capture.
- * Only triggered in older W3C browsers that don't have setCapture/releaseCapture
- * methods or don't support the new pointer events model.
- * onMouseMove is still called on the tracked element, so avoid processing twice.
- * @private
- * @inner
- */
- function onMouseMoveCaptured( tracker, event ) {
- handleMouseMove( tracker, event );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onTouchEnter( tracker, event ) {
- var i,
- touchCount = event.changedTouches.length,
- gPoints = [];
-
- for ( i = 0; i < touchCount; i++ ) {
- gPoints.push( {
- id: event.changedTouches[ i ].identifier,
- type: 'touch',
- insideElement: true,
- currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
- currentTime: $.now()
- } );
- }
-
- updatePointersOver( tracker, event, gPoints );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onTouchLeave( tracker, event ) {
- var i,
- touchCount = event.changedTouches.length,
- gPoints = [];
-
- for ( i = 0; i < touchCount; i++ ) {
- gPoints.push( {
- id: event.changedTouches[ i ].identifier,
- type: 'touch',
- insideElement: false,
- currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
- currentTime: $.now()
- } );
- }
-
- updatePointersOut( tracker, event, gPoints );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onTouchStart( tracker, event ) {
- var delegate = THIS[ tracker.hash ],
- time,
- primaryPoint,
- primaryId,
- gPoint,
- i,
- touchCount = event.changedTouches.length,
- gPoints = [];
-
- time = $.now();
-
- if ( !$.MouseTracker.haveTouchEnter && touchCount > 0 && delegate.touchPoints.getLength() === 0 ) {
- gPoint = {
- id: event.changedTouches[ 0 ].identifier,
- type: 'touch',
- insideElement: true,
- currentPos: getMouseAbsolute( event.changedTouches[ 0 ] ),
- currentTime: time
- };
- updatePointersOver( tracker, event, [ gPoint ] );
- }
-
- primaryPoint = delegate.touchPoints.getPrimary();
- if ( primaryPoint ) {
- primaryId = primaryPoint.id;
- }
- else {
- primaryId = event.changedTouches[ 0 ].identifier;
- }
-
- for ( i = 0; i < touchCount; i++ ) {
- gPoints.push( {
- id: event.changedTouches[ i ].identifier,
- type: 'touch',
- isPrimary: event.changedTouches[ i ].identifier === primaryId,
- currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
- currentTime: time
- } );
- }
-
- addPointers( tracker, event, gPoints );
-
- if ( tracker.pressHandler || tracker.dragHandler || tracker.pinchHandler ) {
- $.stopEvent( event );
- $.cancelEvent( event );
- return false;
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onTouchEnd( tracker, event ) {
- var delegate = THIS[ tracker.hash ],
- time,
- primaryPoint,
- gPoint,
- i,
- touchCount = event.changedTouches.length,
- gPoints = [];
-
- time = $.now();
-
- for ( i = 0; i < touchCount; i++ ) {
- gPoints.push( {
- id: event.changedTouches[ i ].identifier,
- type: 'touch',
- currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
- currentTime: time
- } );
- }
-
- removePointers( tracker, event, gPoints );
-
- primaryPoint = delegate.touchPoints.getPrimary();
- if ( !primaryPoint ) {
- primaryPoint = delegate.touchPoints.getByIndex( 0 );
- if ( primaryPoint ) {
- primaryPoint.isPrimary = true;
- }
- }
-
- if ( !$.MouseTracker.haveTouchEnter && touchCount > 0 && delegate.touchPoints.getLength() === 0 ) {
- gPoint = {
- id: event.changedTouches[ 0 ].identifier,
- type: 'touch',
- insideElement: false,
- currentPos: getMouseAbsolute( event.changedTouches[ 0 ] ),
- currentTime: time
- };
- updatePointersOut( tracker, event, [ gPoint ] );
- }
-
- if ( tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
- $.stopEvent( event );
- $.cancelEvent( event );
- return false;
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onTouchMove( tracker, event ) {
- var i,
- touchCount = event.changedTouches.length,
- gPoints = [];
-
- for ( i = 0; i < touchCount; i++ ) {
- gPoints.push( {
- id: event.changedTouches[ i ].identifier,
- type: 'touch',
- currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
- currentTime: $.now()
- } );
- }
-
- updatePointers( tracker, event, gPoints );
-
- if ( tracker.pressHandler || tracker.dragHandler || tracker.pinchHandler ) {
- $.stopEvent( event );
- $.cancelEvent( event );
- return false;
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onTouchCancel( tracker, event ) {
- var i,
- touchCount = event.changedTouches.length,
- gPoints = [];
-
- for ( i = 0; i < touchCount; i++ ) {
- gPoints.push( {
- id: event.changedTouches[ i ].identifier,
- type: 'touch',
- } );
- }
-
- cancelPointers( tracker, event, gPoints );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onGestureStart( tracker, event ) {
- event.stopPropagation();
- event.preventDefault();
- return false;
- }
-
-
- /**
- * @private
- * @inner
- */
- function onGestureChange( tracker, event ) {
- event.stopPropagation();
- event.preventDefault();
- return false;
- }
-
-
- /**
- * @private
- * @inner
- */
- function onPointerOver( tracker, event ) {
- var gPoint;
-
- gPoint = {
- id: event.pointerId,
- type: getPointerType( event ),
- isPrimary: event.isPrimary,
- insideElement: true,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- updatePointersOver( tracker, event, [ gPoint ] );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onPointerOut( tracker, event ) {
- var gPoint;
-
- gPoint = {
- id: event.pointerId,
- type: getPointerType( event ),
- isPrimary: event.isPrimary,
- insideElement: false,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- updatePointersOut( tracker, event, [ gPoint ] );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onPointerDown( tracker, event ) {
- var gPoint;
-
- if ( event.button == 2 ) {
- return;
- }
-
- if ( $.MouseTracker.unprefixedPointerEvents ) {
- event.currentTarget.setPointerCapture( event.pointerId );
- }
- else {
- event.currentTarget.msSetPointerCapture( event.pointerId );
- }
-
- gPoint = {
- id: event.pointerId,
- type: getPointerType( event ),
- isPrimary: event.isPrimary,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- addPointers( tracker, event, [ gPoint ] );
-
- if ( tracker.pressHandler || tracker.dragHandler || tracker.pinchHandler ) {
- $.stopEvent( event );
- $.cancelEvent( event );
- return false;
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onPointerUp( tracker, event ) {
- var gPoint;
-
- if ( event.button == 2 ) {
- return;
- }
-
- if ( $.MouseTracker.unprefixedPointerEvents ) {
- event.currentTarget.releasePointerCapture( event.pointerId );
- }
- else {
- event.currentTarget.msReleasePointerCapture( event.pointerId );
- }
-
- gPoint = {
- id: event.pointerId,
- type: getPointerType( event ),
- isPrimary: event.isPrimary,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- removePointers(tracker, event, [ gPoint ]);
-
- if ( tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
- $.stopEvent( event );
- $.cancelEvent( event );
- return false;
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onPointerMove( tracker, event ) {
- // Pointer changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)
- var gPoint;
-
- gPoint = {
- id: event.pointerId,
- type: getPointerType( event ),
- isPrimary: event.isPrimary,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- updatePointers(tracker, event, [ gPoint ]);
-
- if ( tracker.pressHandler || tracker.dragHandler || tracker.pinchHandler ) {
- $.stopEvent( event );
- $.cancelEvent( event );
- return false;
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onPointerCancel( tracker, event ) {
- var gPoint;
-
- gPoint = {
- id: event.pointerId,
- type: getPointerType( event ),
- isPrimary: event.isPrimary,
- };
-
- cancelPointers( tracker, event, [ gPoint ] );
- }
-
-
-///////////////////////////////////////////////////////////////////////////////
-// DOM event handler utility functions
-///////////////////////////////////////////////////////////////////////////////
-
/**
* Handles 'wheel' events.
* The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()).
@@ -1787,6 +1313,146 @@
}
+ /**
+ * @private
+ * @inner
+ */
+ function onMouseEnter( tracker, event ) {
+ var gPoint;
+
+ event = $.getEvent( event );
+
+ gPoint = {
+ id: $.MouseTracker.mousePointerId,
+ type: 'mouse',
+ isPrimary: true,
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ updatePointersOver( tracker, event, [ gPoint ] );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onMouseLeave( tracker, event ) {
+ var gPoint;
+
+ event = $.getEvent( event );
+
+ gPoint = {
+ id: $.MouseTracker.mousePointerId,
+ type: 'mouse',
+ isPrimary: true,
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ updatePointersOut( tracker, event, [ gPoint ] );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onMouseDown( tracker, event ) {
+ var gPoint;
+
+ event = $.getEvent( event );
+
+ gPoint = {
+ id: $.MouseTracker.mousePointerId,
+ type: 'mouse',
+ isPrimary: true,
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) {
+ $.stopEvent( event );
+ captureMouse( tracker );
+ }
+
+ if ( tracker.clickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) {
+ $.cancelEvent( event );
+ }
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onMouseUp( tracker, event ) {
+ handleMouseUp( tracker, event );
+ }
+
+ /**
+ * This handler is attached to the window object (on the capture phase) to emulate mouse capture.
+ * Only triggered in W3C browsers that don't have setCapture/releaseCapture
+ * methods or don't support the new pointer events model.
+ * onMouseUp is still attached to the tracked element, so stop propagation to avoid processing twice.
+ *
+ * @private
+ * @inner
+ */
+ function onMouseUpCaptured( tracker, event ) {
+ handleMouseUp( tracker, event );
+ $.stopEvent( event );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function handleMouseUp( tracker, event ) {
+ var gPoint;
+
+ event = $.getEvent( event );
+
+ gPoint = {
+ id: $.MouseTracker.mousePointerId,
+ type: 'mouse',
+ isPrimary: true,
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) {
+ releaseMouse( tracker );
+ }
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onMouseMove( tracker, event ) {
+ handleMouseMove( tracker, event );
+ }
+
+
+ /**
+ * This handler is attached to the window object (on the capture phase) to emulate mouse capture.
+ * Only triggered in W3C browsers that don't have setCapture/releaseCapture
+ * methods or don't support the new pointer events model.
+ * onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice.
+ *
+ * @private
+ * @inner
+ */
+ function onMouseMoveCaptured( tracker, event ) {
+ handleMouseMove( tracker, event );
+ $.stopEvent( event );
+ }
+
+
/**
* @private
* @inner
@@ -1804,7 +1470,7 @@
currentTime: $.now()
};
- updatePointers( tracker, event, [ gPoint ] );
+ updatePointersMove( tracker, event, [ gPoint ] );
}
@@ -1812,24 +1478,1023 @@
* @private
* @inner
*/
- function handleMouseUp( tracker, event ) {
- var gPoint;
+ function onTouchEnter( tracker, event ) {
+ var i,
+ touchCount = event.changedTouches.length,
+ gPoints = [];
- event = $.getEvent( event );
-
- if ( event.button == 2 ) {
- return;
+ for ( i = 0; i < touchCount; i++ ) {
+ gPoints.push( {
+ id: event.changedTouches[ i ].identifier,
+ type: 'touch',
+ // isPrimary not set - let the updatePointers functions determine it
+ currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
+ currentTime: $.now()
+ } );
}
+ updatePointersOver( tracker, event, gPoints );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onTouchLeave( tracker, event ) {
+ var i,
+ touchCount = event.changedTouches.length,
+ gPoints = [];
+
+ for ( i = 0; i < touchCount; i++ ) {
+ gPoints.push( {
+ id: event.changedTouches[ i ].identifier,
+ type: 'touch',
+ // isPrimary not set - let the updatePointers functions determine it
+ currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
+ currentTime: $.now()
+ } );
+ }
+
+ updatePointersOut( tracker, event, gPoints );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onTouchStart( tracker, event ) {
+ var time,
+ i,
+ touchCount = event.changedTouches.length,
+ gPoints = [];
+
+ time = $.now();
+
+ for ( i = 0; i < touchCount; i++ ) {
+ gPoints.push( {
+ id: event.changedTouches[ i ].identifier,
+ type: 'touch',
+ // isPrimary not set - let the updatePointers functions determine it
+ currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
+ currentTime: time
+ } );
+ }
+
+ // simulate touchenter if not natively available
+ if ( !$.MouseTracker.haveTouchEnter ) {
+ updatePointersOver( tracker, event, gPoints );
+ }
+
+ if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact
+ // Touch event model start, end, and move events are always captured so we don't need to capture explicitly
+ }
+
+ $.stopEvent( event );
+ $.cancelEvent( event );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onTouchEnd( tracker, event ) {
+ var time,
+ i,
+ touchCount = event.changedTouches.length,
+ gPoints = [];
+
+ time = $.now();
+
+ for ( i = 0; i < touchCount; i++ ) {
+ gPoints.push( {
+ id: event.changedTouches[ i ].identifier,
+ type: 'touch',
+ // isPrimary not set - let the updatePointers functions determine it
+ currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
+ currentTime: time
+ } );
+ }
+
+ // Touch event model start, end, and move events are always captured so we don't need to release capture.
+ // We'll ignore the should-release-capture return value here
+ updatePointersUp( tracker, event, gPoints, 0 ); // 0 means primary button press/release or touch contact
+
+ // simulate touchleave if not natively available
+ if ( !$.MouseTracker.haveTouchEnter && touchCount > 0 ) {
+ updatePointersOut( tracker, event, gPoints );
+ }
+
+ $.stopEvent( event );
+ $.cancelEvent( event );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onTouchMove( tracker, event ) {
+ var i,
+ touchCount = event.changedTouches.length,
+ gPoints = [];
+
+ for ( i = 0; i < touchCount; i++ ) {
+ gPoints.push( {
+ id: event.changedTouches[ i ].identifier,
+ type: 'touch',
+ // isPrimary not set - let the updatePointers functions determine it
+ currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
+ currentTime: $.now()
+ } );
+ }
+
+ updatePointersMove( tracker, event, gPoints );
+
+ $.stopEvent( event );
+ $.cancelEvent( event );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onTouchCancel( tracker, event ) {
+ var i,
+ touchCount = event.changedTouches.length,
+ gPoints = [];
+
+ for ( i = 0; i < touchCount; i++ ) {
+ gPoints.push( {
+ id: event.changedTouches[ i ].identifier,
+ type: 'touch',
+ } );
+ }
+
+ updatePointersCancel( tracker, event, gPoints );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onGestureStart( tracker, event ) {
+ event.stopPropagation();
+ event.preventDefault();
+ return false;
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onGestureChange( tracker, event ) {
+ event.stopPropagation();
+ event.preventDefault();
+ return false;
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onPointerEnter( tracker, event ) {
+ var gPoint;
+
gPoint = {
- id: $.MouseTracker.mousePointerId,
- type: 'mouse',
- isPrimary: true,
+ id: event.pointerId,
+ type: getPointerType( event ),
+ isPrimary: event.isPrimary,
currentPos: getMouseAbsolute( event ),
currentTime: $.now()
};
- removePointers( tracker, event, [ gPoint ] );
+ updatePointersOver( tracker, event, [ gPoint ] );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onPointerLeave( tracker, event ) {
+ var gPoint;
+
+ gPoint = {
+ id: event.pointerId,
+ type: getPointerType( event ),
+ isPrimary: event.isPrimary,
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ updatePointersOut( tracker, event, [ gPoint ] );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onPointerDown( tracker, event ) {
+ var gPoint;
+
+ gPoint = {
+ id: event.pointerId,
+ type: getPointerType( event ),
+ isPrimary: event.isPrimary,
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) {
+ if ( $.MouseTracker.unprefixedPointerEvents ) {
+ event.currentTarget.setPointerCapture( event.pointerId );
+ } else {
+ event.currentTarget.msSetPointerCapture( event.pointerId );
+ }
+ $.stopEvent( event );
+ }
+
+ if ( tracker.clickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
+ $.cancelEvent( event );
+ }
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onPointerUp( tracker, event ) {
+ var gPoint;
+
+ gPoint = {
+ id: event.pointerId,
+ type: getPointerType( event ),
+ isPrimary: event.isPrimary,
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) {
+ if ( $.MouseTracker.unprefixedPointerEvents ) {
+ event.currentTarget.releasePointerCapture( event.pointerId );
+ } else {
+ event.currentTarget.msReleasePointerCapture( event.pointerId );
+ }
+ }
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onPointerMove( tracker, event ) {
+ // Pointer changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)
+ var gPoint;
+
+ gPoint = {
+ id: event.pointerId,
+ type: getPointerType( event ),
+ isPrimary: event.isPrimary,
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ updatePointersMove( tracker, event, [ gPoint ] );
+ }
+
+
+ /**
+ * @private
+ * @inner
+ */
+ function onPointerCancel( tracker, event ) {
+ var gPoint;
+
+ gPoint = {
+ id: event.pointerId,
+ type: getPointerType( event ),
+ };
+
+ updatePointersCancel( tracker, event, [ gPoint ] );
+ }
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Device-agnostic DOM event handlers
+///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList
+ * The GesturePointList to track the pointer in.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
+ * Gesture point to track.
+ * @returns {Number} Number of gesture points in pointsList.
+ */
+ function startTrackingPointer( pointsList, gPoint ) {
+
+ // If isPrimary is not known for the pointer then set it according to our rules:
+ // true if the first pointer in the gesture, otherwise false
+ if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) {
+ if ( pointsList.getLength() === 0 ) {
+ gPoint.isPrimary = true;
+ } else {
+ gPoint.isPrimary = false;
+ }
+ }
+ gPoint.speed = 0;
+ gPoint.direction = 0;
+ gPoint.contactPos = gPoint.currentPos;
+ gPoint.contactTime = gPoint.currentTime;
+ gPoint.lastPos = gPoint.currentPos;
+ gPoint.lastTime = gPoint.currentTime;
+
+ return pointsList.add( gPoint );
+ }
+
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList
+ * The GesturePointList to stop tracking the pointer on.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
+ * Gesture point to stop tracking.
+ * @returns {Number} Number of gesture points in pointsList.
+ */
+ function stopTrackingPointer( pointsList, gPoint ) {
+ var listLength,
+ primaryPoint;
+
+ if ( pointsList.getById( gPoint.id ) ) {
+ listLength = pointsList.removeById( gPoint.id );
+
+ // If isPrimary is not known for the pointer and we just removed the primary pointer from the list then we need to set another pointer as primary
+ if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) {
+ primaryPoint = pointsList.getPrimary();
+ if ( !primaryPoint ) {
+ primaryPoint = pointsList.getByIndex( 0 );
+ if ( primaryPoint ) {
+ primaryPoint.isPrimary = true;
+ }
+ }
+ }
+ } else {
+ listLength = pointsList.getLength();
+ }
+
+ return listLength;
+ }
+
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {Object} event
+ * A reference to the originating DOM event.
+ * @param {Array.} gPoints
+ * Gesture points associated with the event.
+ */
+ function updatePointersOver( tracker, event, gPoints ) {
+ var pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
+ i,
+ gPointCount = gPoints.length,
+ curGPoint,
+ updateGPoint,
+ propagate;
+
+ for ( i = 0; i < gPointCount; i++ ) {
+ curGPoint = gPoints[ i ];
+ updateGPoint = pointsList.getById( curGPoint.id );
+
+ if ( updateGPoint ) {
+ // Already tracking the pointer...update it
+ updateGPoint.insideElement = true;
+ updateGPoint.lastPos = updateGPoint.currentPos;
+ updateGPoint.lastTime = updateGPoint.currentTime;
+ updateGPoint.currentPos = curGPoint.currentPos;
+ updateGPoint.currentTime = curGPoint.currentTime;
+
+ curGPoint = updateGPoint;
+ } else {
+ // Initialize for tracking and add to the tracking list
+ curGPoint.captured = false;
+ curGPoint.insideElementPressed = false;
+ curGPoint.insideElement = true;
+ startTrackingPointer( pointsList, curGPoint );
+ }
+
+ // Enter
+ if ( tracker.enterHandler ) {
+ propagate = tracker.enterHandler(
+ {
+ eventSource: tracker,
+ pointerType: curGPoint.type,
+ position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),
+ buttons: pointsList.buttons,
+ insideElementPressed: curGPoint.insideElementPressed,
+ buttonDownAny: pointsList.buttons !== 0,// IS_BUTTON_DOWN, *deprecated*
+ isTouchEvent: curGPoint.type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+ }
+ }
+
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {Object} event
+ * A reference to the originating DOM event.
+ * @param {Array.} gPoints
+ * Gesture points associated with the event.
+ */
+ function updatePointersOut( tracker, event, gPoints ) {
+ var delegate = THIS[ tracker.hash ],
+ pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
+ i,
+ gPointCount = gPoints.length,
+ curGPoint,
+ updateGPoint,
+ propagate;
+
+ for ( i = 0; i < gPointCount; i++ ) {
+ curGPoint = gPoints[ i ];
+ updateGPoint = pointsList.getById( curGPoint.id );
+
+ if ( updateGPoint ) {
+ // Already tracking the pointer. If captured then update it, else stop tracking it
+ if ( updateGPoint.captured ) {
+ updateGPoint.insideElement = false;
+ updateGPoint.lastPos = updateGPoint.currentPos;
+ updateGPoint.lastTime = updateGPoint.currentTime;
+ updateGPoint.currentPos = curGPoint.currentPos;
+ updateGPoint.currentTime = curGPoint.currentTime;
+ } else {
+ stopTrackingPointer( pointsList, updateGPoint );
+ }
+
+ curGPoint = updateGPoint;
+ }
+
+ // Exit
+ if ( tracker.exitHandler ) {
+ propagate = tracker.exitHandler(
+ {
+ eventSource: tracker,
+ pointerType: curGPoint.type,
+ position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),
+ buttons: pointsList.buttons,
+ insideElementPressed: updateGPoint ? updateGPoint.insideElementPressed : false,
+ buttonDownAny: pointsList.buttons !== 0,// IS_BUTTON_DOWN, *deprecated*
+ isTouchEvent: curGPoint.type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+ }
+ }
+
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {Object} event
+ * A reference to the originating DOM event.
+ * @param {Array.} gPoints
+ * Gesture points associated with the event.
+ * @param {Number} buttonChanged
+ * The button involved in the event: -1: none, 0: primary, 1: aux, 2: secondary, 3: X1, 4: X2, 5: pen eraser.
+ * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,
+ * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.
+ *
+ * @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false.
+ */
+ function updatePointersDown( tracker, event, gPoints, buttonChanged ) {
+ var delegate = THIS[ tracker.hash ],
+ propagate,
+ pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
+ i,
+ gPointCount = gPoints.length,
+ curGPoint,
+ updateGPoint;
+
+ if ( typeof event.buttons !== 'undefined' ) {
+ pointsList.buttons = event.buttons;
+ } else {
+ if ( buttonChanged === 0 ) {
+ // Primary
+ pointsList.buttons |= 1;
+ } else if ( buttonChanged === 1 ) {
+ // Aux
+ pointsList.buttons |= 4;
+ } else if ( buttonChanged === 2 ) {
+ // Secondary
+ pointsList.buttons |= 2;
+ } else if ( buttonChanged === 3 ) {
+ // X1 (Back)
+ pointsList.buttons |= 8;
+ } else if ( buttonChanged === 4 ) {
+ // X2 (Forward)
+ pointsList.buttons |= 16;
+ } else if ( buttonChanged === 5 ) {
+ // Pen Eraser
+ pointsList.buttons |= 32;
+ }
+ }
+
+ // Only capture and track primary button, pen, and touch contacts
+ //if ( buttonChanged !== 0 ) {
+ if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the line above
+ return false;
+ }
+
+ for ( i = 0; i < gPointCount; i++ ) {
+ curGPoint = gPoints[ i ];
+ updateGPoint = pointsList.getById( curGPoint.id );
+
+ if ( updateGPoint ) {
+ // Already tracking the pointer...update it
+ updateGPoint.captured = true;
+ updateGPoint.insideElementPressed = true;
+ updateGPoint.insideElement = true;
+ updateGPoint.contactPos = curGPoint.currentPos;
+ updateGPoint.contactTime = curGPoint.currentTime;
+ updateGPoint.lastPos = updateGPoint.currentPos;
+ updateGPoint.lastTime = updateGPoint.currentTime;
+ updateGPoint.currentPos = curGPoint.currentPos;
+ updateGPoint.currentTime = curGPoint.currentTime;
+
+ curGPoint = updateGPoint;
+ } else {
+ // Initialize for tracking and add to the tracking list (no pointerover or pointermove event occurred before this)
+ curGPoint.captured = true;
+ curGPoint.insideElementPressed = true;
+ curGPoint.insideElement = true;
+ startTrackingPointer( pointsList, curGPoint );
+ }
+
+ pointsList.contacts++;
+
+ if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
+ $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, curGPoint );
+ }
+
+ if ( pointsList.contacts === 1 ) {
+ // Press
+ if ( tracker.pressHandler ) {
+ propagate = tracker.pressHandler(
+ {
+ eventSource: tracker,
+ pointerType: curGPoint.type,
+ position: getPointRelativeToAbsolute( curGPoint.contactPos, tracker.element ),
+ buttons: pointsList.buttons,
+ isTouchEvent: curGPoint.type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+ } else if ( pointsList.contacts === 2 ) {
+ if ( tracker.pinchHandler && curGPoint.type === 'touch' ) {
+ // Initialize for pinch
+ delegate.pinchGPoints = pointsList.asArray();
+ delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
+ delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {Object} event
+ * A reference to the originating DOM event.
+ * @param {Array.} gPoints
+ * Gesture points associated with the event.
+ * @param {Number} buttonChanged
+ * The button involved in the event: -1: none, 0: primary, 1: aux, 2: secondary, 3: X1, 4: X2, 5: pen eraser.
+ * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,
+ * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.
+ *
+ * @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false.
+ */
+ function updatePointersUp( tracker, event, gPoints, buttonChanged ) {
+ var delegate = THIS[ tracker.hash ],
+ pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
+ propagate,
+ insideElementReleased,
+ releasePoint,
+ releaseTime,
+ i,
+ gPointCount = gPoints.length,
+ curGPoint,
+ updateGPoint,
+ releaseCapture = false,
+ wasCaptured = false;
+
+ if ( typeof event.buttons !== 'undefined' ) {
+ pointsList.buttons = event.buttons;
+ } else {
+ if ( buttonChanged === 0 ) {
+ // Primary
+ pointsList.buttons ^= ~1;
+ } else if ( buttonChanged === 1 ) {
+ // Aux
+ pointsList.buttons ^= ~4;
+ } else if ( buttonChanged === 2 ) {
+ // Secondary
+ pointsList.buttons ^= ~2;
+ } else if ( buttonChanged === 3 ) {
+ // X1 (Back)
+ pointsList.buttons ^= ~8;
+ } else if ( buttonChanged === 4 ) {
+ // X2 (Forward)
+ pointsList.buttons ^= ~16;
+ } else if ( buttonChanged === 5 ) {
+ // Pen Eraser
+ pointsList.buttons ^= ~32;
+ }
+ }
+
+ // Only capture and track primary button, pen, and touch contacts
+ //if ( buttonChanged !== 0 ) {
+ if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the line above
+ return false;
+ }
+
+ for ( i = 0; i < gPointCount; i++ ) {
+ curGPoint = gPoints[ i ];
+ updateGPoint = pointsList.getById( curGPoint.id );
+
+ if ( updateGPoint ) {
+ // Update the pointer, stop tracking it if not still in this element
+ if ( updateGPoint.captured ) {
+ updateGPoint.captured = false;
+ releaseCapture = true;
+ wasCaptured = true;
+ }
+ updateGPoint.lastPos = updateGPoint.currentPos;
+ updateGPoint.lastTime = updateGPoint.currentTime;
+ updateGPoint.currentPos = curGPoint.currentPos;
+ updateGPoint.currentTime = curGPoint.currentTime;
+ if ( !updateGPoint.insideElement ) {
+ stopTrackingPointer( pointsList, updateGPoint );
+ }
+
+ releasePoint = updateGPoint.currentPos;
+ releaseTime = updateGPoint.currentTime;
+
+ if ( wasCaptured ) {
+ // Pointer was activated in our element but could have been removed in any element since events are captured to our element
+
+ pointsList.contacts--;
+
+ if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
+ $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, updateGPoint );
+ }
+
+ if ( pointsList.contacts === 0 ) {
+
+ // Release (pressed in our element)
+ if ( tracker.releaseHandler ) {
+ propagate = tracker.releaseHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( releasePoint, tracker.element ),
+ buttons: pointsList.buttons,
+ insideElementPressed: updateGPoint.insideElementPressed,
+ insideElementReleased: updateGPoint.insideElement,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+
+ // Drag End
+ if ( tracker.dragEndHandler && !updateGPoint.currentPos.equals( updateGPoint.contactPos ) ) {
+ propagate = tracker.dragEndHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
+ speed: updateGPoint.speed,
+ direction: updateGPoint.direction,
+ shift: event.shiftKey,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+
+ // Click
+ if ( tracker.clickHandler && updateGPoint.insideElementPressed && updateGPoint.insideElement ) {
+ var time = releaseTime - updateGPoint.contactTime,
+ distance = updateGPoint.contactPos.distanceTo( releasePoint ),
+ quick = time <= tracker.clickTimeThreshold &&
+ distance <= tracker.clickDistThreshold;
+
+ propagate = tracker.clickHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
+ quick: quick,
+ shift: event.shiftKey,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+ } else if ( pointsList.contacts === 2 ) {
+ if ( tracker.pinchHandler && updateGPoint.type === 'touch' ) {
+ // Reset for pinch
+ delegate.pinchGPoints = pointsList.asArray();
+ delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
+ delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
+ }
+ }
+ } else {
+ // Pointer was activated in another element but removed in our element
+
+ // Release (pressed in another element)
+ if ( tracker.releaseHandler ) {
+ propagate = tracker.releaseHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( releasePoint, tracker.element ),
+ buttons: pointsList.buttons,
+ insideElementPressed: updateGPoint.insideElementPressed,
+ insideElementReleased: updateGPoint.insideElement,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+ }
+ }
+ }
+
+ return releaseCapture;
+ }
+
+
+ /**
+ * Call when pointer(s) change coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)
+ *
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {Object} event
+ * A reference to the originating DOM event.
+ * @param {Array.} gPoints
+ * Gesture points associated with the event.
+ */
+ function updatePointersMove( tracker, event, gPoints ) {
+ var delegate = THIS[ tracker.hash ],
+ pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
+ i,
+ gPointCount = gPoints.length,
+ curGPoint,
+ updateGPoint,
+ gPointArray,
+ delta,
+ propagate;
+
+ if ( typeof event.buttons !== 'undefined' ) {
+ pointsList.buttons = event.buttons;
+ }
+
+ for ( i = 0; i < gPointCount; i++ ) {
+ curGPoint = gPoints[ i ];
+ updateGPoint = pointsList.getById( curGPoint.id );
+
+ if ( updateGPoint ) {
+ // Already tracking the pointer...update it
+ if ( curGPoint.hasOwnProperty( 'isPrimary' ) ) {
+ updateGPoint.isPrimary = curGPoint.isPrimary;
+ }
+ updateGPoint.lastPos = updateGPoint.currentPos;
+ updateGPoint.lastTime = updateGPoint.currentTime;
+ updateGPoint.currentPos = curGPoint.currentPos;
+ updateGPoint.currentTime = curGPoint.currentTime;
+ } else {
+ // Initialize for tracking and add to the tracking list (no pointerover or pointerdown event occurred before this)
+ curGPoint.captured = false;
+ curGPoint.insideElementPressed = false;
+ curGPoint.insideElement = true;
+ startTrackingPointer( pointsList, curGPoint );
+ }
+ }
+
+ // Stop (mouse only)
+ if ( tracker.stopHandler && gPoints[ 0 ].type === 'mouse' ) {
+ clearTimeout( tracker.stopTimeOut );
+ tracker.stopTimeOut = setTimeout( function() {
+ handlePointerStop( tracker, event, gPoints[ 0 ].type );
+ }, tracker.stopDelay );
+ }
+
+ if ( pointsList.contacts === 0 ) {
+ // Move (no contacts: hovering mouse or other hover-capable device)
+ if ( tracker.moveHandler ) {
+ propagate = tracker.moveHandler(
+ {
+ eventSource: tracker,
+ pointerType: gPoints[ 0 ].type,
+ position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),
+ buttons: pointsList.buttons,
+ isTouchEvent: gPoints[ 0 ].type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+ } else if ( pointsList.contacts === 1 ) {
+ // Move (1 contact)
+ if ( tracker.moveHandler ) {
+ updateGPoint = pointsList.asArray()[ 0 ];
+ propagate = tracker.moveHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
+ buttons: pointsList.buttons,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+
+ // Drag
+ if ( tracker.dragHandler ) {
+ updateGPoint = pointsList.asArray()[ 0 ];
+ delta = updateGPoint.currentPos.minus( updateGPoint.lastPos );
+ propagate = tracker.dragHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
+ buttons: pointsList.buttons,
+ delta: delta,
+ speed: updateGPoint.speed,
+ direction: updateGPoint.direction,
+ shift: event.shiftKey,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+ } else if ( pointsList.contacts === 2 ) {
+ // Move (2 contacts, use center)
+ if ( tracker.moveHandler ) {
+ gPointArray = pointsList.asArray();
+ propagate = tracker.moveHandler(
+ {
+ eventSource: tracker,
+ pointerType: gPointArray[ 0 ].type,
+ position: getPointRelativeToAbsolute( getCenterPoint( gPointArray[ 0 ].currentPos, gPointArray[ 1 ].currentPos ), tracker.element ),
+ buttons: pointsList.buttons,
+ isTouchEvent: gPointArray[ 0 ].type === 'touch',
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+
+ // Pinch
+ if ( tracker.pinchHandler && gPoints[ 0 ].type === 'touch' ) {
+ delta = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
+ if ( delta != delegate.currentPinchDist ) {
+ delegate.lastPinchDist = delegate.currentPinchDist;
+ delegate.currentPinchDist = delta;
+ delegate.lastPinchCenter = delegate.currentPinchCenter;
+ delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
+ propagate = tracker.pinchHandler(
+ {
+ eventSource: tracker,
+ pointerType: 'touch',
+ gesturePoints: delegate.pinchGPoints,
+ lastCenter: getPointRelativeToAbsolute( delegate.lastPinchCenter, tracker.element ),
+ center: getPointRelativeToAbsolute( delegate.currentPinchCenter, tracker.element ),
+ lastDistance: delegate.lastPinchDist,
+ distance: delegate.currentPinchDist,
+ shift: event.shiftKey,
+ originalEvent: event,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ if ( propagate === false ) {
+ $.cancelEvent( event );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {Object} event
+ * A reference to the originating DOM event.
+ * @param {Array.} gPoints
+ * Gesture points associated with the event.
+ */
+ function updatePointersCancel( tracker, event, gPoints ) {
+ //removePointers( tracker, event, gPoints );
}
@@ -1843,6 +2508,7 @@
eventSource: tracker,
pointerType: pointerType,
position: getMouseRelative( originalMoveEvent, tracker.element ),
+ buttons: tracker.getActivePointersListByType( pointerType ).buttons,
isTouchEvent: pointerType === 'touch',
originalEvent: originalMoveEvent,
preventDefaultAction: false,
@@ -1851,503 +2517,4 @@
}
}
-
- /**
- * @private
- * @inner
- */
- function addPointers( tracker, event, gPoints ) {
- var delegate = THIS[ tracker.hash ],
- propagate,
- pointsList = getGPointsListByType( tracker, gPoints[ 0 ].type ),
- pointsListLength,
- i,
- gPointCount = gPoints.length,
- curGPoint;
-
- if ( pointsList ) {
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
-
- // Initialize for gesture tracking
- curGPoint.insideElementPressed = true;
- curGPoint.insideElement = true;
- curGPoint.speed = 0;
- curGPoint.direction = 0;
- curGPoint.startPos = curGPoint.currentPos;
- curGPoint.startTime = curGPoint.currentTime;
- curGPoint.lastPos = curGPoint.currentPos;
- curGPoint.lastTime = curGPoint.currentTime;
-
- if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
- $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, curGPoint );
- }
-
- pointsListLength = pointsList.add( curGPoint );
-
- if ( pointsListLength == 1 ) {
- // Press
- if ( tracker.pressHandler ) {
- propagate = tracker.pressHandler(
- {
- eventSource: tracker,
- pointerType: curGPoint.type,
- position: getPointRelativeToAbsolute( curGPoint.startPos, tracker.element ),
- isTouchEvent: curGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
- }
- else if ( pointsListLength == 2 ) {
- if ( tracker.pinchHandler && curGPoint.type === 'touch' ) {
- // Initialize for pinch
- delegate.pinchGPoints = pointsList.asArray();
- delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
- delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
- }
- }
- }
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function updatePointersOver( tracker, event, gPoints ) {
- var delegate = THIS[ tracker.hash ],
- pointsList = getGPointsListByType( tracker, gPoints[ 0 ].type ),
- i,
- gPointCount = gPoints.length,
- curGPoint,
- updateGPoint,
- insideElementPressed,
- propagate;
-
- if ( pointsList ) {
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
- updateGPoint = pointsList.getById( curGPoint.id );
-
- if ( updateGPoint ) {
- updateGPoint.insideElement = true;
- updateGPoint.lastPos = updateGPoint.currentPos;
- updateGPoint.lastTime = updateGPoint.currentTime;
- updateGPoint.currentPos = curGPoint.currentPos;
- updateGPoint.currentTime = curGPoint.currentTime;
- insideElementPressed = updateGPoint.insideElementPressed;
- }
- else {
- insideElementPressed = false;
- }
-
- // Enter
- if ( tracker.enterHandler ) {
- propagate = tracker.enterHandler(
- {
- eventSource: tracker,
- pointerType: curGPoint.type,
- position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),
- insideElementPressed: insideElementPressed,
- buttonDownAny: IS_BUTTON_DOWN,
- isTouchEvent: curGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
- }
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function updatePointersOut( tracker, event, gPoints ) {
- var delegate = THIS[ tracker.hash ],
- pointsList = getGPointsListByType( tracker, gPoints[ 0 ].type ),
- i,
- gPointCount = gPoints.length,
- curGPoint,
- updateGPoint,
- insideElementPressed,
- propagate;
-
- if ( pointsList ) {
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
- updateGPoint = pointsList.getById( curGPoint.id );
-
- if ( updateGPoint ) {
- updateGPoint.insideElement = false;
- updateGPoint.lastPos = updateGPoint.currentPos;
- updateGPoint.lastTime = updateGPoint.currentTime;
- updateGPoint.currentPos = curGPoint.currentPos;
- updateGPoint.currentTime = curGPoint.currentTime;
- insideElementPressed = updateGPoint.insideElementPressed;
- }
- else {
- insideElementPressed = false;
- }
-
- // Exit
- if ( tracker.exitHandler ) {
- propagate = tracker.exitHandler(
- {
- eventSource: tracker,
- pointerType: curGPoint.type,
- position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),
- insideElementPressed: insideElementPressed,
- buttonDownAny: IS_BUTTON_DOWN,
- isTouchEvent: curGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
-
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
- }
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function updatePointers( tracker, event, gPoints ) {
- // Pointer(s) changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)
- var delegate = THIS[ tracker.hash ],
- pointsList = getGPointsListByType( tracker, gPoints[ 0 ].type ),
- pointsListLength,
- i,
- gPointCount = gPoints.length,
- curGPoint,
- updateGPoint,
- gPointArray,
- delta,
- propagate;
-
- if ( pointsList ) {
- pointsListLength = pointsList.getLength();
-
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
- updateGPoint = pointsList.getById( curGPoint.id );
-
- if ( updateGPoint ) {
- updateGPoint.lastPos = updateGPoint.currentPos;
- updateGPoint.lastTime = updateGPoint.currentTime;
- updateGPoint.currentPos = curGPoint.currentPos;
- updateGPoint.currentTime = curGPoint.currentTime;
- }
- }
-
- // Stop (mouse only)
- if ( gPoints[ 0 ].type === 'mouse' && tracker.stopHandler ) {
- clearTimeout( tracker.stopTimeOut );
- tracker.stopTimeOut = setTimeout( function() {
- handlePointerStop( tracker, event, gPoints[ 0 ].type );
- }, tracker.stopDelay );
- }
-
- if ( pointsListLength === 0 ) {
- // Move (no contacts, mouse or other hover-capable device)
- if ( tracker.moveHandler ) {
- propagate = tracker.moveHandler(
- {
- eventSource: tracker,
- pointerType: gPoints[ 0 ].type,
- position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),
- isTouchEvent: gPoints[ 0 ].type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
- }
- else if ( pointsListLength === 1 ) {
- // Move (1 contact)
- if ( tracker.moveHandler ) {
- updateGPoint = pointsList.asArray()[ 0 ];
- propagate = tracker.moveHandler(
- {
- eventSource: tracker,
- pointerType: updateGPoint.type,
- position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
- isTouchEvent: updateGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
-
- // Drag
- if ( tracker.dragHandler ) {
- updateGPoint = pointsList.asArray()[ 0 ];
- delta = updateGPoint.currentPos.minus( updateGPoint.lastPos );
- propagate = tracker.dragHandler(
- {
- eventSource: tracker,
- pointerType: updateGPoint.type,
- position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
- delta: delta,
- speed: updateGPoint.speed,
- direction: updateGPoint.direction,
- shift: event.shiftKey,
- isTouchEvent: updateGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
- }
- else if ( pointsListLength === 2 ) {
- // Move (2 contacts, use center)
- if ( tracker.moveHandler ) {
- gPointArray = pointsList.asArray();
- propagate = tracker.moveHandler(
- {
- eventSource: tracker,
- pointerType: gPointArray[ 0 ].type,
- position: getPointRelativeToAbsolute( getCenterPoint( gPointArray[ 0 ].currentPos, gPointArray[ 1 ].currentPos ), tracker.element ),
- isTouchEvent: gPointArray[ 0 ].type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
-
- // Pinch
- if ( tracker.pinchHandler && gPoints[ 0 ].type === 'touch' ) {
- delta = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
- if ( delta != delegate.currentPinchDist ) {
- delegate.lastPinchDist = delegate.currentPinchDist;
- delegate.currentPinchDist = delta;
- delegate.lastPinchCenter = delegate.currentPinchCenter;
- delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
- propagate = tracker.pinchHandler(
- {
- eventSource: tracker,
- pointerType: 'touch',
- gesturePoints: delegate.pinchGPoints,
- lastCenter: getPointRelativeToAbsolute( delegate.lastPinchCenter, tracker.element ),
- center: getPointRelativeToAbsolute( delegate.currentPinchCenter, tracker.element ),
- lastDistance: delegate.lastPinchDist,
- distance: delegate.currentPinchDist,
- shift: event.shiftKey,
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
- }
- }
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function removePointers( tracker, event, gPoints ) {
- var delegate = THIS[ tracker.hash ],
- pointsList = getGPointsListByType( tracker, gPoints[ 0 ].type ),
- pointsListLength,
- propagate,
- insideElementPressed,
- insideElementReleased,
- releasePoint,
- releaseTime,
- i,
- gPointCount = gPoints.length,
- curGPoint,
- updateGPoint,
- removedGPoint;
-
- if ( pointsList ) {
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
-
- removedGPoint = pointsList.getById( curGPoint.id );
-
- if ( removedGPoint ) {
-
- releasePoint = removedGPoint.currentPos;
- releaseTime = removedGPoint.currentTime;
-
- if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
- $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, removedGPoint );
- }
-
- pointsListLength = pointsList.removeById( curGPoint.id );
-
- if ( pointsListLength === 0 ) {
-
- insideElementPressed = removedGPoint.insideElementPressed;
- insideElementReleased = removedGPoint.insideElement || $.pointInElement( tracker.element, releasePoint );
-
- // Release
- if ( tracker.releaseHandler ) {
- propagate = tracker.releaseHandler(
- {
- eventSource: tracker,
- pointerType: removedGPoint.type,
- position: getPointRelativeToAbsolute( releasePoint, tracker.element ),
- insideElementPressed: insideElementPressed,
- insideElementReleased: insideElementReleased,
- isTouchEvent: removedGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
-
- // Drag End
- if ( tracker.dragEndHandler ) {
- propagate = tracker.dragEndHandler(
- {
- eventSource: tracker,
- pointerType: removedGPoint.type,
- position: getPointRelativeToAbsolute( removedGPoint.currentPos, tracker.element ),
- speed: removedGPoint.speed,
- direction: removedGPoint.direction,
- shift: event.shiftKey,
- isTouchEvent: removedGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
-
- // Click
- if ( tracker.clickHandler && insideElementPressed && insideElementReleased ) {
- var time = releaseTime - removedGPoint.startTime,
- distance = removedGPoint.startPos.distanceTo( releasePoint ),
- quick = time <= tracker.clickTimeThreshold &&
- distance <= tracker.clickDistThreshold;
-
- propagate = tracker.clickHandler(
- {
- eventSource: tracker,
- pointerType: curGPoint.type,
- position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),
- quick: quick,
- shift: event.shiftKey,
- isTouchEvent: curGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
- }
- //else if ( pointsListLength === 1 ) {
- //}
- else if ( pointsListLength === 2 ) {
- if ( tracker.pinchHandler && curGPoint.type === 'touch' ) {
- // Reset for pinch
- delegate.pinchGPoints = pointsList.asArray();
- delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
- delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
- }
- }
- }
- }
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function cancelPointers( tracker, event, gPoints ) {
- removePointers( tracker, event, gPoints );
- }
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Deprecated
-///////////////////////////////////////////////////////////////////////////////
-
- // TODO Do we really need these anymore (used as buttonDownAny in enterHandler/exitHandler callbacks)?
- // Surely there's a more robust and elegant solution...
-
- /**
- * @private
- * @inner
- */
- function onGlobalMouseDown() {
- IS_BUTTON_DOWN = true;
- }
-
- /**
- * @private
- * @inner
- */
- function onGlobalMouseUp() {
- IS_BUTTON_DOWN = false;
- }
-
-
- (function () {
- if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 9 ) {
- $.addEvent( document, "mousedown", onGlobalMouseDown, false );
- $.addEvent( document, "mouseup", onGlobalMouseUp, false );
- } else {
- $.addEvent( window, "mousedown", onGlobalMouseDown, true );
- $.addEvent( window, "mouseup", onGlobalMouseUp, true );
- }
- } )();
-
} ( OpenSeadragon ) );
diff --git a/src/openseadragon.js b/src/openseadragon.js
index de3ef7ee..e55cf3d7 100644
--- a/src/openseadragon.js
+++ b/src/openseadragon.js
@@ -285,24 +285,32 @@
* @property {Boolean} [gestureSettingsMouse.scrollToZoom=true] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture
* @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick gesture
- * @property {Number} [gestureSettingsMouse.flickMinSpeed=20] - Minimum speed to initiate a flick gesture (pixels-per-second)
- * @property {Number} [gestureSettingsMouse.flickMomentum=0.35] - Momentum factor for the flick gesture
+ * @property {Number} [gestureSettingsMouse.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
+ * @property {Number} [gestureSettingsMouse.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture
*
* @property {OpenSeadragon.GestureSettings} [gestureSettingsTouch]
* Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings})
* @property {Boolean} [gestureSettingsTouch.scrollToZoom=false] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture
* @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick gesture
- * @property {Number} [gestureSettingsTouch.flickMinSpeed=20] - Minimum speed to initiate a flick gesture (pixels-per-second)
- * @property {Number} [gestureSettingsTouch.flickMomentum=0.35] - Momentum factor for the flick gesture
+ * @property {Number} [gestureSettingsTouch.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
+ * @property {Number} [gestureSettingsTouch.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture
*
* @property {OpenSeadragon.GestureSettings} [gestureSettingsPen]
* Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings})
* @property {Boolean} [gestureSettingsPen.scrollToZoom=false] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture
* @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick gesture
- * @property {Number} [gestureSettingsPen.flickMinSpeed=20] - Minimum speed to initiate a flick gesture (pixels-per-second)
- * @property {Number} [gestureSettingsPen.flickMomentum=0.35] - Momentum factor for the flick gesture
+ * @property {Number} [gestureSettingsPen.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
+ * @property {Number} [gestureSettingsPen.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture
+ *
+ * @property {OpenSeadragon.GestureSettings} [gestureSettingsUnknown]
+ * Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings})
+ * @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture
+ * @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture
+ * @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick gesture
+ * @property {Number} [gestureSettingsUnknown.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
+ * @property {Number} [gestureSettingsUnknown.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture
*
* @property {Number} [zoomPerClick=2.0]
* The "zoom distance" per mouse click or touch tap. Note: Setting this to 1.0 effectively disables the click-to-zoom feature (also see gestureSettings[Mouse|Touch|Pen].clickToZoom).
@@ -455,12 +463,12 @@
* Set to false to disable the kinetic panning effect (flick) at the end of a drag gesture.
*
* @property {Number} flickMinSpeed
- * Minimum speed (in pixels-per-second) required to cause the kinetic panning effect (flick) at the end of a drag gesture.
+ * If flickEnabled is true, the minimum speed (in pixels-per-second) required to cause the kinetic panning effect (flick) at the end of a drag gesture.
*
* @property {Number} flickMomentum
- * Constant multiplied by the velocity to determine the distance of the kinetic panning effect (flick) at the end of a drag gesture.
+ * If flickEnabled is true, a constant multiplied by the velocity to determine the distance of the kinetic panning effect (flick) at the end of a drag gesture.
* A larger value will make the flick feel "lighter", while a smaller value will make the flick feel "heavier".
- * Also, springStiffness and animationTime affect the "spring" used to stop the flick animation.
+ * Note: springStiffness and animationTime also affect the "spring" used to stop the flick animation.
*
*/
@@ -798,6 +806,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
gestureSettingsMouse: { scrollToZoom: true, clickToZoom: true, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 },
gestureSettingsTouch: { scrollToZoom: false, clickToZoom: false, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 },
gestureSettingsPen: { scrollToZoom: false, clickToZoom: true, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 },
+ gestureSettingsUnknown: { scrollToZoom: false, clickToZoom: false, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 },
zoomPerClick: 2,
zoomPerScroll: 1.2,
zoomPerSecond: 1.0,
diff --git a/src/viewer.js b/src/viewer.js
index 8c72347b..9285a501 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -278,8 +278,7 @@ $.Viewer = function( options ) {
// Disable browser default touch handling
if (style["touch-action"] !== undefined) {
style["touch-action"] = "none";
- }
- else if (style["-ms-touch-action"] !== undefined) {
+ } else if (style["-ms-touch-action"] !== undefined) {
style["-ms-touch-action"] = "none";
}
}(this.canvas.style));
@@ -1776,21 +1775,19 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
/**
* Gets this viewer's gesture settings for the given pointer device type.
* @method
- * @param {String} type - The pointer device type to get the gesture settings for. "mouse", "touch", "pen", or "".
+ * @param {String} type - The pointer device type to get the gesture settings for ("mouse", "touch", "pen", etc.).
* @return {OpenSeadragon.GestureSettings}
*/
gestureSettingsByDeviceType: function ( type ) {
- if ( type === 'mouse' ) {
- return this.gestureSettingsMouse;
- }
- else if ( type === 'touch' ) {
- return this.gestureSettingsTouch;
- }
- else if ( type === 'pen' ) {
- return this.gestureSettingsPen;
- }
- else {
- return { scrollToZoom: false, clickToZoom: false, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.35 };
+ switch ( type ) {
+ case 'mouse':
+ return this.gestureSettingsMouse;
+ case 'touch':
+ return this.gestureSettingsTouch;
+ case 'pen':
+ return this.gestureSettingsPen;
+ default:
+ return this.gestureSettingsUnknown;
}
}
@@ -2472,14 +2469,16 @@ function onContainerExit( event ) {
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
+ * @property {Number} buttons - Current buttons pressed. A 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.
* @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.
- * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event.
+ * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.raiseEvent( 'container-exit', {
tracker: event.eventSource,
position: event.position,
+ buttons: event.buttons,
insideElementPressed: event.insideElementPressed,
buttonDownAny: event.buttonDownAny,
originalEvent: event.originalEvent
@@ -2528,14 +2527,16 @@ function onContainerEnter( event ) {
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
+ * @property {Number} buttons - Current buttons pressed. A 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.
* @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.
- * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event.
+ * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.raiseEvent( 'container-enter', {
tracker: event.eventSource,
position: event.position,
+ buttons: event.buttons,
insideElementPressed: event.insideElementPressed,
buttonDownAny: event.buttonDownAny,
originalEvent: event.originalEvent
diff --git a/test/events.js b/test/events.js
index 86f007c1..413dade3 100644
--- a/test/events.js
+++ b/test/events.js
@@ -25,184 +25,365 @@
} );
// ----------
- asyncTest( 'addHandler without userData', function () {
- var openHandler = function ( event ) {
- viewer.removeHandler( 'open', openHandler );
- ok( event, 'Event handler received event data' );
- if ( event ) {
- strictEqual( event.eventSource, viewer, 'eventSource sent, eventSource is viewer' );
- strictEqual( event.userData, null, 'User data defaulted to null' );
- }
- viewer.close();
- start();
- };
-
- viewer.addHandler( 'open', openHandler );
- viewer.open( '/test/data/testpattern.dzi' );
- } );
-
- // ----------
- asyncTest( 'addHandler with userData', function () {
- var userData = { item1: 'Test user data', item2: Math.random() },
- originalUserData = { item1: userData.item1, item2: userData.item2 };
-
- var openHandler = function ( event ) {
- viewer.removeHandler( 'open', openHandler );
- ok( event, 'Event handler received event data' );
- ok( event && event.userData, 'Event handler received user data' );
- if ( event && event.userData ) {
- deepEqual( event.userData, originalUserData, 'User data was untouched' );
- }
- viewer.close();
- start();
- };
-
- viewer.addHandler( 'open', openHandler, userData );
- viewer.open( '/test/data/testpattern.dzi' );
- } );
-
- // ----------
- asyncTest( 'MouseTracker, EventSource canvas-drag canvas-release canvas-click', function () {
+ asyncTest( 'MouseTracker: mouse gestures', function () {
var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ),
- mouseTracker = null,
- userData = { item1: 'Test user data', item2: Math.random() },
- originalUserData = { item1: userData.item1, item2: userData.item2 },
- dragCount = 10,
- dragsHandledEventSource = 0,
- releasesHandledEventSource = 0,
- clicksHandledEventSource = 0,
- eventsHandledMouseTracker = 0,
- eventSourcePassedMouseTracker = 0,
- originalEventsPassedMouseTracker = 0,
- eventsHandledViewer = 0,
- originalEventsPassedViewer = 0,
- releasesExpected = 1,
- clicksExpected = 1;
+ offset = $canvas.offset(),
+ tracker = viewer.innerTracker,
+ origEnterHandler,
+ origExitHandler,
+ origPressHandler,
+ origReleaseHandler,
+ origMoveHandler,
+ origClickHandler,
+ origDragHandler,
+ origDragEndHandler,
+ enterCount,
+ exitCount,
+ pressCount,
+ releaseCount,
+ moveCount,
+ clickCount,
+ dragCount,
+ dragEndCount,
+ insideElementPressed,
+ insideElementReleased,
+ quickClick;
+
+ var hookViewerHandlers = function () {
+ origEnterHandler = tracker.enterHandler;
+ tracker.enterHandler = function ( event ) {
+ enterCount++;
+ if (origEnterHandler) {
+ return origEnterHandler( event );
+ } else {
+ return true;
+ }
+ };
+ origExitHandler = tracker.exitHandler;
+ tracker.exitHandler = function ( event ) {
+ exitCount++;
+ if (origExitHandler) {
+ return origExitHandler( event );
+ } else {
+ return true;
+ }
+ };
+ origPressHandler = tracker.pressHandler;
+ tracker.pressHandler = function ( event ) {
+ pressCount++;
+ if (origPressHandler) {
+ return origPressHandler( event );
+ } else {
+ return true;
+ }
+ };
+ origReleaseHandler = tracker.releaseHandler;
+ tracker.releaseHandler = function ( event ) {
+ releaseCount++;
+ insideElementPressed = event.insideElementPressed;
+ insideElementReleased = event.insideElementReleased;
+ if (origReleaseHandler) {
+ return origReleaseHandler( event );
+ } else {
+ return true;
+ }
+ };
+ origMoveHandler = tracker.moveHandler;
+ tracker.moveHandler = function ( event ) {
+ moveCount++;
+ if (origMoveHandler) {
+ return origMoveHandler( event );
+ } else {
+ return true;
+ }
+ };
+ origClickHandler = tracker.clickHandler;
+ tracker.clickHandler = function ( event ) {
+ clickCount++;
+ quickClick = event.quick;
+ if (origClickHandler) {
+ return origClickHandler( event );
+ } else {
+ return true;
+ }
+ };
+ origDragHandler = tracker.dragHandler;
+ tracker.dragHandler = function ( event ) {
+ dragCount++;
+ if (origDragHandler) {
+ return origDragHandler( event );
+ } else {
+ return true;
+ }
+ };
+ origDragEndHandler = tracker.dragEndHandler;
+ tracker.dragEndHandler = function ( event ) {
+ dragEndCount++;
+ if (origDragEndHandler) {
+ return origDragEndHandler( event );
+ } else {
+ return true;
+ }
+ };
+ };
+
+ var unhookViewerHandlers = function () {
+ tracker.enterHandler = origEnterHandler;
+ tracker.exitHandler = origExitHandler;
+ tracker.pressHandler = origPressHandler;
+ tracker.releaseHandler = origReleaseHandler;
+ tracker.moveHandler = origMoveHandler;
+ tracker.clickHandler = origClickHandler;
+ tracker.dragHandler = origDragHandler;
+ 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 simulateLeave = function ($element, event, x, y) {
+ event.clientX = offset.left + x;
+ event.clientY = offset.top + y;
+ $canvas.simulate( 'mouseleave', event );
+ };
+
+ var simulateMove = function ($element, event, dX, dY, count) {
+ var i;
+ for ( i = 0; i < count; i++ ) {
+ event.clientX += dX;
+ event.clientY += dY;
+ $canvas.simulate( 'mousemove', event );
+ }
+ };
+
+ var simulateDown = function ($element, event, x, y) {
+ event.clientX = offset.left + x;
+ event.clientY = offset.top + y;
+ $canvas.simulate( 'mousedown', event );
+ };
+
+ var simulateUp = function ($element, event, x, y) {
+ event.clientX = offset.left + x;
+ event.clientY = offset.top + y;
+ $canvas.simulate( 'mouseup', event );
+ };
+
+ var resetForAssessment = function () {
+ enterCount = 0;
+ exitCount = 0;
+ pressCount = 0;
+ releaseCount = 0;
+ moveCount = 0;
+ clickCount = 0;
+ dragCount = 0;
+ dragEndCount = 0;
+ insideElementPressed = false;
+ insideElementReleased = false;
+ quickClick = false;
+ };
+
+ var assessGestureExpectations = function (expected) {
+ var pointersList = tracker.getActivePointersListByType('mouse');
+ if ('enterCount' in expected) {
+ equal( enterCount, expected.enterCount, expected.description + 'enterHandler event count matches expected (' + expected.enterCount + ')' );
+ }
+ if ('exitCount' in expected) {
+ equal( exitCount, expected.exitCount, expected.description + 'exitHandler event count matches expected (' + expected.exitCount + ')' );
+ }
+ if ('pressCount' in expected) {
+ equal( pressCount, expected.pressCount, expected.description + 'pressHandler event count matches expected (' + expected.pressCount + ')' );
+ }
+ if ('releaseCount' in expected) {
+ equal( releaseCount, expected.releaseCount, expected.description + 'releaseHandler event count matches expected (' + expected.releaseCount + ')' );
+ }
+ if ('moveCount' in expected) {
+ equal( moveCount, expected.moveCount, expected.description + 'moveHandler event count matches expected (' + expected.moveCount + ')' );
+ }
+ if ('clickCount' in expected) {
+ equal( clickCount, expected.clickCount, expected.description + 'clickHandler event count matches expected (' + expected.clickCount + ')' );
+ }
+ if ('dragCount' in expected) {
+ equal( dragCount, expected.dragCount, expected.description + 'dragHandler event count matches expected (' + expected.dragCount + ')' );
+ }
+ if ('dragEndCount' in expected) {
+ equal( dragEndCount, expected.dragEndCount, expected.description + 'dragEndHandler event count matches expected (' + expected.dragEndCount + ')' );
+ }
+ if ('insideElementPressed' in expected) {
+ equal( insideElementPressed, expected.insideElementPressed, expected.description + 'releaseHandler event.insideElementPressed matches expected (' + expected.insideElementPressed + ')' );
+ }
+ if ('insideElementReleased' in expected) {
+ equal( insideElementReleased, expected.insideElementReleased, expected.description + 'releaseHandler event.insideElementReleased matches expected (' + expected.insideElementReleased + ')' );
+ }
+ if ('contacts' in expected) {
+ equal( pointersList.contacts, expected.contacts, expected.description + 'Remaining pointer contact count matches expected (' + expected.contacts + ')' );
+ }
+ if ('trackedPointers' in expected) {
+ equal( pointersList.getLength(), expected.trackedPointers, expected.description + 'Remaining tracked pointer count matches expected (' + expected.trackedPointers + ')' );
+ }
+ if ('quickClick' in expected) {
+ equal( quickClick, expected.quickClick, expected.description + 'clickHandler event.quick matches expected (' + expected.quickClick + ')' );
+ }
+ };
var onOpen = function ( event ) {
viewer.removeHandler( 'open', onOpen );
- viewer.addHandler( 'canvas-drag', onEventSourceDrag );
- viewer.addHandler( 'canvas-release', onEventSourceRelease );
- viewer.addHandler( 'canvas-click', onEventSourceClick );
+ hookViewerHandlers();
- mouseTracker = new OpenSeadragon.MouseTracker( {
- element: $canvas[0],
- userData: userData,
- clickTimeThreshold: OpenSeadragon.DEFAULT_SETTINGS.clickTimeThreshold,
- clickDistThreshold: OpenSeadragon.DEFAULT_SETTINGS.clickDistThreshold,
- focusHandler: onMouseTrackerFocus,
- blurHandler: onMouseTrackerBlur,
- enterHandler: onMouseTrackerEnter,
- pressHandler: onMouseTrackerPress,
- moveHandler: onMouseTrackerMove,
- dragHandler: onMouseTrackerDrag,
- releaseHandler: onMouseTrackerRelease,
- clickHandler: onMouseTrackerClick,
- exitHandler: onMouseTrackerExit
- } ).setTracking( true );
+ // 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);
+ assessGestureExpectations({
+ description: 'enter-move-release (release in tracked element, press in unknown element): ',
+ enterCount: 1,
+ exitCount: 0,
+ pressCount: 0,
+ releaseCount: 1,
+ moveCount: 20,
+ clickCount: 0,
+ dragCount: 0,
+ dragEndCount: 0,
+ insideElementPressed: false,
+ insideElementReleased: true,
+ contacts: 0,
+ trackedPointers: 1
+ //quickClick: false
+ });
+ simulateLeave($canvas, event, -1, -1); // flush tracked pointer
- var event = {
- clientX:1,
- clientY:1
- };
+ // 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);
+ assessGestureExpectations({
+ description: 'enter-move-exit (fly-over): ',
+ enterCount: 1,
+ exitCount: 1,
+ pressCount: 0,
+ releaseCount: 0,
+ moveCount: 20,
+ clickCount: 0,
+ dragCount: 0,
+ dragEndCount: 0,
+ //insideElementPressed: false,
+ //insideElementReleased: false,
+ contacts: 0,
+ trackedPointers: 0
+ //quickClick: false
+ });
- $canvas.simulate( 'focus', event );
- Util.simulateViewerClickWithDrag( {
- viewer: viewer,
- widthFactor: 0.25,
- heightFactor: 0.25,
- dragCount: dragCount,
- dragDx: 1,
- dragDy: 1
- } );
- $canvas.simulate( 'blur', event );
- };
+ // 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);
+ assessGestureExpectations({
+ description: 'move-exit (fly-over, no enter event): ',
+ enterCount: 0,
+ exitCount: 1,
+ pressCount: 0,
+ releaseCount: 0,
+ moveCount: 20,
+ clickCount: 0,
+ dragCount: 0,
+ dragEndCount: 0,
+ //insideElementPressed: false,
+ //insideElementReleased: false,
+ contacts: 0,
+ trackedPointers: 0
+ //quickClick: false
+ });
- var checkOriginalEventReceivedViewer = function ( event ) {
- eventsHandledViewer++;
- //TODO Provide a better check for the original event...simulate doesn't currently extend the object
- // with arbitrary user data.
- if ( event && event.originalEvent ) {
- originalEventsPassedViewer++;
- }
- };
+ // 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);
+ assessGestureExpectations({
+ description: 'enter-press-release-exit (click): ',
+ enterCount: 1,
+ exitCount: 1,
+ pressCount: 1,
+ releaseCount: 1,
+ moveCount: 0,
+ clickCount: 1,
+ dragCount: 0,
+ dragEndCount: 0,
+ insideElementPressed: true,
+ insideElementReleased: true,
+ contacts: 0,
+ trackedPointers: 0,
+ quickClick: true
+ });
- var onEventSourceDrag = function ( event ) {
- checkOriginalEventReceivedViewer( event );
- dragsHandledEventSource++;
- };
+ // 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);
+ assessGestureExpectations({
+ description: 'enter-press-move-release-move-exit (drag, release in tracked element): ',
+ enterCount: 1,
+ exitCount: 1,
+ pressCount: 1,
+ releaseCount: 1,
+ moveCount: 20,
+ clickCount: 1,
+ dragCount: 10,
+ dragEndCount: 1,
+ insideElementPressed: true,
+ insideElementReleased: true,
+ contacts: 0,
+ trackedPointers: 0,
+ quickClick: false
+ });
- var onEventSourceRelease = function ( event ) {
- checkOriginalEventReceivedViewer( event );
- releasesHandledEventSource++;
- };
+ // 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);
+ assessGestureExpectations({
+ description: 'enter-press-move-exit-move-release (drag, release outside tracked element): ',
+ enterCount: 1,
+ exitCount: 1,
+ pressCount: 1,
+ releaseCount: 1,
+ moveCount: 15,
+ clickCount: 0,
+ dragCount: 15,
+ dragEndCount: 1,
+ insideElementPressed: true,
+ insideElementReleased: false,
+ contacts: 0,
+ trackedPointers: 0,
+ quickClick: false
+ });
- var onEventSourceClick = function ( event ) {
- checkOriginalEventReceivedViewer( event );
- clicksHandledEventSource++;
- };
-
- var checkOriginalEventReceived = function ( event ) {
- eventsHandledMouseTracker++;
- if ( event && event.eventSource === mouseTracker ) {
- eventSourcePassedMouseTracker++;
- }
- //TODO Provide a better check for the original event...simulate doesn't currently extend the object
- // with arbitrary user data.
- if ( event && event.originalEvent ) {
- originalEventsPassedMouseTracker++;
- }
- };
-
- var onMouseTrackerFocus = function ( event ) {
- checkOriginalEventReceived( event );
- };
-
- var onMouseTrackerBlur = function ( event ) {
- checkOriginalEventReceived( event );
- };
-
- var onMouseTrackerEnter = function ( event ) {
- checkOriginalEventReceived( event );
- };
-
- var onMouseTrackerPress = function ( event ) {
- checkOriginalEventReceived( event );
- };
-
- var onMouseTrackerMove = function ( event ) {
- checkOriginalEventReceived( event );
- };
-
- var onMouseTrackerDrag = function ( event ) {
- checkOriginalEventReceived( event );
- };
-
- var onMouseTrackerRelease = function ( event ) {
- checkOriginalEventReceived( event );
- };
-
- var onMouseTrackerClick = function ( event ) {
- checkOriginalEventReceived( event );
- };
-
- var onMouseTrackerExit = function ( event ) {
- checkOriginalEventReceived( event );
-
- mouseTracker.destroy();
- viewer.removeHandler( 'canvas-drag', onEventSourceDrag );
- viewer.removeHandler( 'canvas-release', onEventSourceRelease );
- viewer.removeHandler( 'canvas-click', onEventSourceClick );
-
- equal( dragsHandledEventSource, dragCount, "'canvas-drag' event count matches 'mousemove' event count (" + dragCount + ")" );
- equal( releasesHandledEventSource, releasesExpected, "'canvas-release' event count matches expected (" + releasesExpected + ")" );
- equal( clicksHandledEventSource, releasesExpected, "'canvas-click' event count matches expected (" + releasesExpected + ")" );
- equal( originalEventsPassedViewer, eventsHandledViewer, "Original event received count matches expected (" + eventsHandledViewer + ")" );
-
- equal( eventSourcePassedMouseTracker, eventsHandledMouseTracker, "Event source received count matches expected (" + eventsHandledMouseTracker + ")" );
- equal( originalEventsPassedMouseTracker, eventsHandledMouseTracker, "Original event received count matches expected (" + eventsHandledMouseTracker + ")" );
- deepEqual( event.userData, originalUserData, 'MouseTracker userData was untouched' );
+ unhookViewerHandlers();
viewer.close();
start();
@@ -213,7 +394,7 @@
} );
// ----------
- asyncTest( 'MouseTracker preventDefaultAction', function () {
+ asyncTest( 'MouseTracker: preventDefaultAction', function () {
var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ),
tracker = viewer.innerTracker,
origClickHandler,
@@ -281,7 +462,209 @@
} );
// ----------
- asyncTest( 'tile-drawing event', function () {
+ asyncTest( 'EventSource/MouseTracker/Viewer: event.originalEvent event.userData canvas-drag canvas-drag-end canvas-release canvas-click', function () {
+ var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ),
+ mouseTracker = null,
+ userData = { item1: 'Test user data', item2: Math.random() },
+ originalUserData = { item1: userData.item1, item2: userData.item2 },
+ dragCount = 10,
+ dragsHandledEventSource = 0,
+ dragEndsHandledEventSource = 0,
+ releasesHandledEventSource = 0,
+ clicksHandledEventSource = 0,
+ eventsHandledMouseTracker = 0,
+ eventSourcePassedMouseTracker = 0,
+ originalEventsPassedMouseTracker = 0,
+ eventsHandledViewer = 0,
+ originalEventsPassedViewer = 0,
+ dragEndsExpected = 1,
+ releasesExpected = 1,
+ clicksExpected = 1;
+
+ var onOpen = function ( event ) {
+ viewer.removeHandler( 'open', onOpen );
+
+ viewer.addHandler( 'canvas-drag', onEventSourceDrag );
+ viewer.addHandler( 'canvas-drag-end', onEventSourceDragEnd );
+ viewer.addHandler( 'canvas-release', onEventSourceRelease );
+ viewer.addHandler( 'canvas-click', onEventSourceClick );
+
+ mouseTracker = new OpenSeadragon.MouseTracker( {
+ element: $canvas[0],
+ userData: userData,
+ clickTimeThreshold: OpenSeadragon.DEFAULT_SETTINGS.clickTimeThreshold,
+ clickDistThreshold: OpenSeadragon.DEFAULT_SETTINGS.clickDistThreshold,
+ focusHandler: onMouseTrackerFocus,
+ blurHandler: onMouseTrackerBlur,
+ enterHandler: onMouseTrackerEnter,
+ pressHandler: onMouseTrackerPress,
+ moveHandler: onMouseTrackerMove,
+ dragHandler: onMouseTrackerDrag,
+ dragEndHandler: onMouseTrackerDragEnd,
+ releaseHandler: onMouseTrackerRelease,
+ clickHandler: onMouseTrackerClick,
+ exitHandler: onMouseTrackerExit
+ } ).setTracking( true );
+
+ var event = {
+ clientX:1,
+ clientY:1
+ };
+
+ $canvas.simulate( 'focus', event );
+ Util.simulateViewerClickWithDrag( {
+ viewer: viewer,
+ widthFactor: 0.25,
+ heightFactor: 0.25,
+ dragCount: dragCount,
+ dragDx: 1,
+ dragDy: 1
+ } );
+ $canvas.simulate( 'blur', event );
+ };
+
+ var checkOriginalEventReceivedViewer = function ( event ) {
+ eventsHandledViewer++;
+ //TODO Provide a better check for the original event...simulate doesn't currently extend the object
+ // with arbitrary user data.
+ if ( event && event.originalEvent ) {
+ originalEventsPassedViewer++;
+ }
+ };
+
+ var onEventSourceDrag = function ( event ) {
+ checkOriginalEventReceivedViewer( event );
+ dragsHandledEventSource++;
+ };
+
+ var onEventSourceDragEnd = function ( event ) {
+ checkOriginalEventReceivedViewer( event );
+ dragEndsHandledEventSource++;
+ };
+
+ var onEventSourceRelease = function ( event ) {
+ checkOriginalEventReceivedViewer( event );
+ releasesHandledEventSource++;
+ };
+
+ var onEventSourceClick = function ( event ) {
+ checkOriginalEventReceivedViewer( event );
+ clicksHandledEventSource++;
+ };
+
+ var checkOriginalEventReceived = function ( event ) {
+ eventsHandledMouseTracker++;
+ if ( event && event.eventSource === mouseTracker ) {
+ eventSourcePassedMouseTracker++;
+ }
+ //TODO Provide a better check for the original event...simulate doesn't currently extend the object
+ // with arbitrary user data.
+ if ( event && event.originalEvent ) {
+ originalEventsPassedMouseTracker++;
+ }
+ };
+
+ var onMouseTrackerFocus = function ( event ) {
+ checkOriginalEventReceived( event );
+ };
+
+ var onMouseTrackerBlur = function ( event ) {
+ checkOriginalEventReceived( event );
+ };
+
+ var onMouseTrackerEnter = function ( event ) {
+ checkOriginalEventReceived( event );
+ };
+
+ var onMouseTrackerPress = function ( event ) {
+ checkOriginalEventReceived( event );
+ };
+
+ var onMouseTrackerMove = function ( event ) {
+ checkOriginalEventReceived( event );
+ };
+
+ var onMouseTrackerDrag = function ( event ) {
+ checkOriginalEventReceived( event );
+ };
+
+ var onMouseTrackerDragEnd = function ( event ) {
+ checkOriginalEventReceived( event );
+ };
+
+ var onMouseTrackerRelease = function ( event ) {
+ checkOriginalEventReceived( event );
+ };
+
+ var onMouseTrackerClick = function ( event ) {
+ checkOriginalEventReceived( event );
+ };
+
+ var onMouseTrackerExit = function ( event ) {
+ checkOriginalEventReceived( event );
+
+ mouseTracker.destroy();
+ viewer.removeHandler( 'canvas-drag', onEventSourceDrag );
+ viewer.removeHandler( 'canvas-release', onEventSourceRelease );
+ viewer.removeHandler( 'canvas-click', onEventSourceClick );
+
+ equal( dragsHandledEventSource, dragCount, "'canvas-drag' event count matches 'mousemove' event count (" + dragCount + ")" );
+ equal( dragEndsHandledEventSource, dragEndsExpected, "'canvas-drag-end' event count matches expected (" + dragEndsExpected + ")" );
+ equal( releasesHandledEventSource, releasesExpected, "'canvas-release' event count matches expected (" + releasesExpected + ")" );
+ equal( clicksHandledEventSource, releasesExpected, "'canvas-click' event count matches expected (" + releasesExpected + ")" );
+ equal( originalEventsPassedViewer, eventsHandledViewer, "Original event received count matches expected (" + eventsHandledViewer + ")" );
+
+ equal( eventSourcePassedMouseTracker, eventsHandledMouseTracker, "Event source received count matches expected (" + eventsHandledMouseTracker + ")" );
+ equal( originalEventsPassedMouseTracker, eventsHandledMouseTracker, "Original event received count matches expected (" + eventsHandledMouseTracker + ")" );
+ deepEqual( event.userData, originalUserData, 'MouseTracker userData was untouched' );
+
+ viewer.close();
+ start();
+ };
+
+ viewer.addHandler( 'open', onOpen );
+ viewer.open( '/test/data/testpattern.dzi' );
+ } );
+
+ // ----------
+ asyncTest( 'Viewer: addHandler without userData', function () {
+ var openHandler = function ( event ) {
+ viewer.removeHandler( 'open', openHandler );
+ ok( event, 'Event handler received event data' );
+ if ( event ) {
+ strictEqual( event.eventSource, viewer, 'eventSource sent, eventSource is viewer' );
+ strictEqual( event.userData, null, 'User data defaulted to null' );
+ }
+ viewer.close();
+ start();
+ };
+
+ viewer.addHandler( 'open', openHandler );
+ viewer.open( '/test/data/testpattern.dzi' );
+ } );
+
+ // ----------
+ asyncTest( 'Viewer: addHandler with userData', function () {
+ var userData = { item1: 'Test user data', item2: Math.random() },
+ originalUserData = { item1: userData.item1, item2: userData.item2 };
+
+ var openHandler = function ( event ) {
+ viewer.removeHandler( 'open', openHandler );
+ ok( event, 'Event handler received event data' );
+ ok( event && event.userData, 'Event handler received user data' );
+ if ( event && event.userData ) {
+ deepEqual( event.userData, originalUserData, 'User data was untouched' );
+ }
+ viewer.close();
+ start();
+ };
+
+ viewer.addHandler( 'open', openHandler, userData );
+ viewer.open( '/test/data/testpattern.dzi' );
+ } );
+
+ // ----------
+ asyncTest( 'Viewer: tile-drawing event', function () {
var tileDrawing = function ( event ) {
viewer.removeHandler( 'tile-drawing', tileDrawing );
ok( event, 'Event handler should be invoked' );
diff --git a/test/legacy.mouse.shim.js b/test/legacy.mouse.shim.js
index 8a503759..0402ed6e 100644
--- a/test/legacy.mouse.shim.js
+++ b/test/legacy.mouse.shim.js
@@ -11,17 +11,18 @@
$.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" );
}
- $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" );
+ $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave", "mousedown", "mouseup", "mousemove" );
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" );
if ( 'ontouchenter' in window ) {
$.MouseTracker.subscribeEvents.push( "touchenter", "touchleave" );
$.MouseTracker.haveTouchEnter = true;
- }
- else {
+ } else {
$.MouseTracker.haveTouchEnter = false;
}
+ } else {
+ $.MouseTracker.haveTouchEnter = false;
}
if ( 'ongesturestart' in window ) {
// iOS (see https://developer.apple.com/library/safari/documentation/UserExperience/Reference/GestureEventClassReference/GestureEvent/GestureEvent.html)
diff --git a/test/navigator.js b/test/navigator.js
index 95631a91..a073fee8 100644
--- a/test/navigator.js
+++ b/test/navigator.js
@@ -189,7 +189,7 @@ QUnit.config.autostart = false;
clientY:offset.top + locationY
};
$canvas
- .simulate('mouseover', event)
+ .simulate('mouseenter', event)
.simulate('mousedown', event)
.simulate('mouseup', event);
};
diff --git a/test/test.js b/test/test.js
index 2272ea9d..cc640abd 100644
--- a/test/test.js
+++ b/test/test.js
@@ -37,7 +37,7 @@
};
$canvas
- .simulate( 'mouseover', event )
+ .simulate( 'mouseenter', event )
.simulate( 'mousedown', event );
for ( var i = 0; i < args.dragCount; i++ ) {
event.clientX += args.dragDx;
@@ -47,7 +47,7 @@
}
$canvas
.simulate( 'mouseup', event )
- .simulate( 'mouseout', event );
+ .simulate( 'mouseleave', event );
},
initializeTestDOM: function () {