From b3fa8f11844fec1fe5b3601c62e627ccda7102d8 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Thu, 5 Sep 2013 17:20:17 -0700 Subject: [PATCH] MouseTracker original events in handlers Implemented "Expose original event in handlers" (#23) for MouseTracker Added OpenSeadragon.getElementOffset() method. Element-relative mouse coordinates should be correct even if the element and/or page is scrolled (#131) --- src/button.js | 38 +- src/buttongroup.js | 20 +- src/eventhandler.js | 2 +- src/mousetracker.js | 1065 ++++++++++++++++++++++++----------------- src/navigator.js | 16 +- src/openseadragon.js | 42 ++ src/referencestrip.js | 862 ++++++++++++++++----------------- src/viewer.js | 88 ++-- 8 files changed, 1166 insertions(+), 967 deletions(-) diff --git a/src/button.js b/src/button.js index 7eead5da..4524234e 100644 --- a/src/button.js +++ b/src/button.js @@ -175,57 +175,59 @@ $.Button = function( options ) { clickTimeThreshold: this.clickTimeThreshold, clickDistThreshold: this.clickDistThreshold, - enterHandler: function( tracker, position, buttonDownElement, buttonDownAny ) { - if ( buttonDownElement ) { + enterHandler: function( tracker, eventData ) { + if ( eventData.buttonDownElement ) { inTo( _this, $.ButtonState.DOWN ); _this.raiseEvent( "onEnter", _this ); - } else if ( !buttonDownAny ) { + } else if ( !eventData.buttonDownAny ) { inTo( _this, $.ButtonState.HOVER ); } }, - focusHandler: function( tracker, position, buttonDownElement, buttonDownAny ) { - this.enterHandler( tracker, position, buttonDownElement, buttonDownAny ); + // TODO: This didn't match handler signature in MouseTracker. Investigate! + focusHandler: function ( tracker, eventData ) { //position, buttonDownElement, buttonDownAny + //this.enterHandler( tracker, eventData ); //position, buttonDownElement, buttonDownAny _this.raiseEvent( "onFocus", _this ); }, - exitHandler: function( tracker, position, buttonDownElement, buttonDownAny ) { + exitHandler: function( tracker, eventData ) { outTo( _this, $.ButtonState.GROUP ); - if ( buttonDownElement ) { + if ( eventData.buttonDownElement ) { _this.raiseEvent( "onExit", _this ); } }, - blurHandler: function( tracker, position, buttonDownElement, buttonDownAny ) { - this.exitHandler( tracker, position, buttonDownElement, buttonDownAny ); + // TODO: This didn't match handler signature in MouseTracker. Investigate! + blurHandler: function ( tracker, eventData ) { //position, buttonDownElement, buttonDownAny + //this.exitHandler( tracker, eventData ); //position, buttonDownElement, buttonDownAny _this.raiseEvent( "onBlur", _this ); }, - pressHandler: function( tracker, position ) { + pressHandler: function ( tracker, eventData ) { inTo( _this, $.ButtonState.DOWN ); _this.raiseEvent( "onPress", _this ); }, - releaseHandler: function( tracker, position, insideElementPress, insideElementRelease ) { - if ( insideElementPress && insideElementRelease ) { + releaseHandler: function( tracker, eventData ) { + if ( eventData.insideElementPress && eventData.insideElementRelease ) { outTo( _this, $.ButtonState.HOVER ); _this.raiseEvent( "onRelease", _this ); - } else if ( insideElementPress ) { + } else if ( eventData.insideElementPress ) { outTo( _this, $.ButtonState.GROUP ); } else { inTo( _this, $.ButtonState.HOVER ); } }, - clickHandler: function( tracker, position, quick, shift ) { - if ( quick ) { + clickHandler: function( tracker, eventData ) { + if ( eventData.quick ) { _this.raiseEvent("onClick", _this); } }, - keyHandler: function( tracker, key ){ - //console.log( "%s : handling key %s!", _this.tooltip, key); - if( 13 === key ){ + keyHandler: function( tracker, eventData ){ + //console.log( "%s : handling key %s!", _this.tooltip, eventData.keyCode); + if( 13 === eventData.keyCode ){ _this.raiseEvent( "onClick", _this ); _this.raiseEvent( "onRelease", _this ); return false; diff --git a/src/buttongroup.js b/src/buttongroup.js index 17c08267..550a2ac1 100644 --- a/src/buttongroup.js +++ b/src/buttongroup.js @@ -85,29 +85,23 @@ $.ButtonGroup = function( options ) { element: this.element, clickTimeThreshold: this.clickTimeThreshold, clickDistThreshold: this.clickDistThreshold, - enterHandler: function() { + enterHandler: function ( tracker, eventData ) { var i; for ( i = 0; i < _this.buttons.length; i++ ) { _this.buttons[ i ].notifyGroupEnter(); } }, - exitHandler: function() { - var i, - buttonDownElement = arguments.length > 2 ? - arguments[ 2 ] : - null; - if ( !buttonDownElement ) { + exitHandler: function ( tracker, eventData ) { + var i; + if ( !eventData.buttonDownElement ) { for ( i = 0; i < _this.buttons.length; i++ ) { _this.buttons[ i ].notifyGroupExit(); } } }, - releaseHandler: function() { - var i, - insideElementRelease = arguments.length > 3 ? - arguments[ 3 ] : - null; - if ( !insideElementRelease ) { + releaseHandler: function ( tracker, eventData ) { + var i; + if ( !eventData.insideElementRelease ) { for ( i = 0; i < _this.buttons.length; i++ ) { _this.buttons[ i ].notifyGroupExit(); } diff --git a/src/eventhandler.js b/src/eventhandler.js index 56fbf080..1595bd54 100644 --- a/src/eventhandler.js +++ b/src/eventhandler.js @@ -55,7 +55,7 @@ $.EventHandler.prototype = { * @function * @param {String} eventName - Name of event to register. * @param {Function} handler - Function to call when event is triggered. - * @param {Object} optional userData - Arbitrary object to be passed to the handler. + * @param {Object} optional userData - Arbitrary object to be passed unchanged to the handler. */ addHandler: function ( eventName, handler, userData ) { var events = this.events[ eventName ]; diff --git a/src/mousetracker.js b/src/mousetracker.js index f2dd53f8..36492d6a 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -32,72 +32,82 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -(function( $ ){ +(function ( $ ) { - // is any button currently being pressed while mouse events occur - var IS_BUTTON_DOWN = false, - // is any tracker currently capturing? - IS_CAPTURING = false, - // dictionary from hash to MouseTracker - ACTIVE = {}, - // list of trackers interested in capture - CAPTURING = [], - // dictionary from hash to private properties - THIS = {}; + // is any button currently being pressed while mouse events occur + var IS_BUTTON_DOWN = false, + // is any tracker currently capturing? + IS_CAPTURING = false, + // dictionary from hash to MouseTracker + ACTIVE = {}, + // list of trackers interested in capture + CAPTURING = [], + // dictionary from hash to private properties + THIS = {}; /** - * The MouseTracker allows other classes to set handlers for common mouse - * events on a specific element like, 'enter', 'exit', 'press', 'release', - * 'scroll', 'click', and 'drag'. - * @class - * @param {Object} options - * Allows configurable properties to be entirely specified by passing - * an options object to the constructor. The constructor also supports - * the original positional arguments 'elements', 'clickTimeThreshold', - * and 'clickDistThreshold' in that order. - * @param {Element|String} options.element - * A reference to an element or an element id for which the mouse - * events will be monitored. - * @param {Number} options.clickTimeThreshold - * The number of milliseconds within which mutliple mouse clicks - * will be treated as a single event. - * @param {Number} options.clickDistThreshold - * The distance between mouse click within multiple mouse clicks - * will be treated as a single event. - * @param {Function} options.enterHandler - * An optional handler for mouse enter. - * @param {Function} options.exitHandler - * An optional handler for mouse exit. - * @param {Function} options.pressHandler - * An optional handler for mouse press. - * @param {Function} options.releaseHandler - * An optional handler for mouse release. - * @param {Function} options.scrollHandler - * An optional handler for mouse scroll. - * @param {Function} options.clickHandler - * An optional handler for mouse click. - * @param {Function} options.dragHandler - * An optional handler for mouse drag. - * @property {Number} hash - * An unique hash for this tracker. - * @property {Element} element - * The element for which mouse event are being monitored. - * @property {Number} clickTimeThreshold - * The number of milliseconds within which mutliple mouse clicks - * will be treated as a single event. - * @property {Number} clickDistThreshold - * The distance between mouse click within multiple mouse clicks - * will be treated as a single event. - */ + * The MouseTracker allows other classes to set handlers for common mouse + * events on a specific element like, 'enter', 'exit', 'press', 'release', + * 'scroll', 'click', and 'drag'. + * @class + * @param {Object} options + * Allows configurable properties to be entirely specified by passing + * an options object to the constructor. The constructor also supports + * the original positional arguments 'elements', 'clickTimeThreshold', + * and 'clickDistThreshold' in that order. + * @param {Element|String} options.element + * A reference to an element or an element id for which the mouse + * events will be monitored. + * @param {Number} options.clickTimeThreshold + * The number of milliseconds within which mutliple mouse clicks + * will be treated as a single event. + * @param {Number} options.clickDistThreshold + * The distance between mouse click within multiple mouse clicks + * will be treated as a single event. + * @param {Function} options.enterHandler + * An optional handler for mouse enter. + * @param {Function} options.exitHandler + * An optional handler for mouse exit. + * @param {Function} options.pressHandler + * An optional handler for mouse press. + * @param {Function} options.releaseHandler + * An optional handler for mouse release. + * @param {Function} options.moveHandler + * An optional handler for mouse move. + * @param {Function} options.scrollHandler + * An optional handler for mouse scroll. + * @param {Function} options.clickHandler + * An optional handler for mouse click. + * @param {Function} options.dragHandler + * An optional handler for mouse drag. + * @param {Function} options.keyHandler + * An optional handler for keypress. + * @param {Function} options.focusHandler + * An optional handler for focus. + * @param {Function} options.blurHandler + * An optional handler for blur. + * @property {Number} hash + * An unique hash for this tracker. + * @property {Element} element + * The element for which mouse event are being monitored. + * @property {Number} clickTimeThreshold + * The number of milliseconds within which mutliple mouse clicks + * will be treated as a single event. + * @property {Number} clickDistThreshold + * The distance between mouse click within multiple mouse clicks + * will be treated as a single event. + * @property {Object} optional userData + * Arbitrary object to be passed unchanged to any attached handler methods. + */ $.MouseTracker = function ( options ) { - var args = arguments; + var args = arguments; - if( !$.isPlainObject( options ) ){ + if ( !$.isPlainObject( options ) ) { options = { - element: args[ 0 ], - clickTimeThreshold: args[ 1 ], - clickDistThreshold: args[ 2 ] + element: args[0], + clickTimeThreshold: args[1], + clickDistThreshold: args[2] }; } @@ -105,66 +115,68 @@ this.element = $.getElement( options.element ); this.clickTimeThreshold = options.clickTimeThreshold; this.clickDistThreshold = options.clickDistThreshold; + this.userData = options.userData || null; - - this.enterHandler = options.enterHandler || null; - this.exitHandler = options.exitHandler || null; - this.pressHandler = options.pressHandler || null; + this.enterHandler = options.enterHandler || null; + this.exitHandler = options.exitHandler || null; + this.pressHandler = options.pressHandler || null; this.releaseHandler = options.releaseHandler || null; - this.scrollHandler = options.scrollHandler || null; - this.clickHandler = options.clickHandler || null; - this.dragHandler = options.dragHandler || null; - this.keyHandler = options.keyHandler || null; - this.focusHandler = options.focusHandler || null; - this.blurHandler = options.blurHandler || null; + this.moveHandler = options.moveHandler || null; + this.scrollHandler = options.scrollHandler || null; + this.clickHandler = options.clickHandler || null; + this.dragHandler = options.dragHandler || null; + this.keyHandler = options.keyHandler || null; + this.focusHandler = options.focusHandler || null; + this.blurHandler = options.blurHandler || null; //Store private properties in a scope sealed hash map var _this = this; /** - * @private - * @property {Boolean} tracking - * Are we currently tracking mouse events. - * @property {Boolean} capturing - * Are we curruently capturing mouse events. - * @property {Boolean} buttonDown - * True if the left mouse button is currently being pressed and was - * initiated inside the tracked element, otherwise false. - * @property {Boolean} insideElement - * Are we currently inside the screen area of the tracked element. - * @property {OpenSeadragon.Point} lastPoint - * Position of last mouse down/move - * @property {Number} lastMouseDownTime - * Time of last mouse down. - * @property {OpenSeadragon.Point} lastMouseDownPoint - * Position of last mouse down - */ - THIS[ this.hash ] = { - mouseover: function( event ){ onMouseOver( _this, event ); }, - mouseout: function( event ){ onMouseOut( _this, event ); }, - mousedown: function( event ){ onMouseDown( _this, event ); }, - mouseup: function( event ){ onMouseUp( _this, event ); }, - click: function( event ){ onMouseClick( _this, event ); }, - DOMMouseScroll: function( event ){ onMouseWheelSpin( _this, event ); }, - mousewheel: function( event ){ onMouseWheelSpin( _this, event ); }, - mouseupie: function( event ){ onMouseUpIE( _this, event ); }, - mousemoveie: function( event ){ onMouseMoveIE( _this, event ); }, - mouseupwindow: function( event ){ onMouseUpWindow( _this, event ); }, - mousemove: function( event ){ onMouseMove( _this, event ); }, - touchstart: function( event ){ onTouchStart( _this, event ); }, - touchmove: function( event ){ onTouchMove( _this, event ); }, - touchend: function( event ){ onTouchEnd( _this, event ); }, - keypress: function( event ){ onKeyPress( _this, event ); }, - focus: function( event ){ onFocus( _this, event ); }, - blur: function( event ){ onBlur( _this, event ); }, - tracking: false, - capturing: false, - buttonDown: false, - insideElement: false, - lastPoint: null, - lastMouseDownTime: null, + * @private + * @property {Boolean} tracking + * Are we currently tracking mouse events. + * @property {Boolean} capturing + * Are we curruently capturing mouse events. + * @property {Boolean} buttonDownElement + * True if the left mouse button is currently being pressed and was + * initiated inside the tracked element, otherwise false. + * @property {Boolean} insideElement + * Are we currently inside the screen area of the tracked element. + * @property {OpenSeadragon.Point} lastPoint + * Position of last mouse down/move + * @property {Number} lastMouseDownTime + * Time of last mouse down. + * @property {OpenSeadragon.Point} lastMouseDownPoint + * Position of last mouse down + */ + THIS[this.hash] = { + mouseover: function ( event ) { onMouseOver( _this, event, false ); }, + mouseout: function ( event ) { onMouseOut( _this, event, false ); }, + mousedown: function ( event ) { onMouseDown( _this, event ); }, + mouseup: function ( event ) { onMouseUp( _this, event, false ); }, + mousemove: function ( event ) { onMouseMove( _this, event ); }, + click: function ( event ) { onMouseClick( _this, event ); }, + DOMMouseScroll: function ( event ) { onMouseWheelSpin( _this, event, false ); }, + mousewheel: function ( event ) { onMouseWheelSpin( _this, event, false ); }, + mouseupie: function ( event ) { onMouseUpIE( _this, event ); }, + mousemoveie: function ( event ) { onMouseMoveIE( _this, event ); }, + mouseupwindow: function ( event ) { onMouseUpWindow( _this, event ); }, + mousemovewindow: function ( event ) { onMouseMoveWindow( _this, event, false ); }, + touchstart: function ( event ) { onTouchStart( _this, event ); }, + touchmove: function ( event ) { onTouchMove( _this, event ); }, + touchend: function ( event ) { onTouchEnd( _this, event ); }, + keypress: function ( event ) { onKeyPress( _this, event ); }, + focus: function ( event ) { onFocus( _this, event ); }, + blur: function ( event ) { onBlur( _this, event ); }, + tracking: false, + capturing: false, + buttonDownElement: false, + insideElement: false, + lastPoint: null, + lastMouseDownTime: null, lastMouseDownPoint: null, - lastPinchDelta: 0 + lastPinchDelta: 0 }; }; @@ -172,30 +184,30 @@ $.MouseTracker.prototype = { /** - * Clean up any events or objects created by the mouse tracker. - * @function - */ - destroy: function() { + * Clean up any events or objects created by the mouse tracker. + * @function + */ + destroy: function () { stopTracking( this ); this.element = null; }, /** - * Are we currently tracking events on this element. - * @deprecated Just use this.tracking - * @function - * @returns {Boolean} Are we currently tracking events on this element. - */ + * Are we currently tracking events on this element. + * @deprecated Just use this.tracking + * @function + * @returns {Boolean} Are we currently tracking events on this element. + */ isTracking: function () { - return THIS[ this.hash ].tracking; + return THIS[this.hash].tracking; }, /** - * Enable or disable whether or not we are tracking events on this element. - * @function - * @param {Boolean} track True to start tracking, false to stop tracking. - * @returns {OpenSeadragon.MouseTracker} Chainable. - */ + * Enable or disable whether or not we are tracking events on this element. + * @function + * @param {Boolean} track True to start tracking, false to stop tracking. + * @returns {OpenSeadragon.MouseTracker} Chainable. + */ setTracking: function ( track ) { if ( track ) { startTracking( this ); @@ -207,213 +219,276 @@ }, /** - * Implement or assign implmentation to these handlers during or after - * calling the constructor. - * @function - * @param {OpenSeadragon.MouseTracker} tracker - * A reference to the tracker instance. - * @param {OpenSeadragon.Point} position - * The poistion of the event on the screen. - * @param {Boolean} buttonDown - * True if the left mouse button is currently being pressed and was - * initiated inside the tracked element, otherwise false. - * @param {Boolean} buttonDownAny - * Was the button down anywhere in the screen during the event. - */ - enterHandler: function(){}, + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * position: The position of the event relative to the tracked element. + * buttonDownElement: True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * buttonDownAny: Was the button down anywhere in the screen during the event. + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + enterHandler: function () { }, /** - * Implement or assign implmentation to these handlers during or after - * calling the constructor. - * @function - * @param {OpenSeadragon.MouseTracker} tracker - * A reference to the tracker instance. - * @param {OpenSeadragon.Point} position - * The poistion of the event on the screen. - * @param {Boolean} buttonDown - * True if the left mouse button is currently being pressed and was - * initiated inside the tracked element, otherwise false. - * @param {Boolean} buttonDownAny - * Was the button down anywhere in the screen during the event. - */ - exitHandler: function(){}, + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * position: The position of the event relative to the tracked element. + * buttonDownElement: True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * buttonDownAny: Was the button down anywhere in the screen during the event. + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + exitHandler: function () { }, /** - * Implement or assign implmentation to these handlers during or after - * calling the constructor. - * @function - * @param {OpenSeadragon.MouseTracker} tracker - * A reference to the tracker instance. - * @param {OpenSeadragon.Point} position - * The poistion of the event on the screen. - */ - pressHandler: function(){}, + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * position: The position of the event relative to the tracked element. + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + pressHandler: function () { }, /** - * Implement or assign implmentation to these handlers during or after - * calling the constructor. - * @function - * @param {OpenSeadragon.MouseTracker} tracker - * A reference to the tracker instance. - * @param {OpenSeadragon.Point} position - * The poistion of the event on the screen. - * @param {Boolean} buttonDown - * True if the left mouse button is currently being pressed and was - * initiated inside the tracked element, otherwise false. - * @param {Boolean} insideElementRelease - * Was the mouse still inside the tracked element when the button - * was released. - */ - releaseHandler: function(){}, + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * position: The position of the event relative to the tracked element. + * insideElementPress: True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * insideElementRelease: Was the mouse still inside the tracked element when the button was released. + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + releaseHandler: function () { }, /** - * Implement or assign implmentation to these handlers during or after - * calling the constructor. - * @function - * @param {OpenSeadragon.MouseTracker} tracker - * A reference to the tracker instance. - * @param {OpenSeadragon.Point} position - * The poistion of the event on the screen. - * @param {Number} scroll - * The scroll delta for the event. - * @param {Boolean} shift - * Was the shift key being pressed during this event? - */ - scrollHandler: function(){}, + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * position: The position of the event relative to the tracked element. + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + moveHandler: function () { }, /** - * Implement or assign implmentation to these handlers during or after - * calling the constructor. - * @function - * @param {OpenSeadragon.MouseTracker} tracker - * A reference to the tracker instance. - * @param {OpenSeadragon.Point} position - * The poistion of the event on the screen. - * @param {Boolean} quick - * True only if the clickDistThreshold and clickDeltaThreshold are - * both pased. Useful for ignoring events. - * @param {Boolean} shift - * Was the shift key being pressed during this event? - */ - clickHandler: function(){}, + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * position: The position of the event relative to the tracked element. + * scroll: The scroll delta for the event. + * shift: Was the shift key being pressed during this event? + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + scrollHandler: function () { }, /** - * Implement or assign implmentation to these handlers during or after - * calling the constructor. - * @function - * @param {OpenSeadragon.MouseTracker} tracker - * A reference to the tracker instance. - * @param {OpenSeadragon.Point} position - * The poistion of the event on the screen. - * @param {OpenSeadragon.Point} delta - * The x,y components of the difference between start drag and - * end drag. Usefule for ignoring or weighting the events. - * @param {Boolean} shift - * Was the shift key being pressed during this event? - */ - dragHandler: function(){}, + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * position: The position of the event relative to the tracked element. + * quick: True only if the clickDistThreshold and clickDeltaThreshold are both pased. Useful for ignoring events. + * shift: Was the shift key being pressed during this event? + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + clickHandler: function () { }, /** - * Implement or assign implmentation to these handlers during or after - * calling the constructor. - * @function - * @param {OpenSeadragon.MouseTracker} tracker - * A reference to the tracker instance. - * @param {Number} keyCode - * The key code that was pressed. - * @param {Boolean} shift - * Was the shift key being pressed during this event? - */ - keyHandler: function(){}, + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * position: The position of the event relative to the tracked element. + * delta: The x,y components of the difference between start drag and end drag. Usefule for ignoring or weighting the events. + * shift: Was the shift key being pressed during this event? + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + dragHandler: function () { }, - focusHandler: function(){}, + /** + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * keyCode: The key code that was pressed. + * shift: Was the shift key being pressed during this event? + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + keyHandler: function () { }, - blurHandler: function(){} + /** + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + focusHandler: function () { }, + + /** + * Implement or assign implmentation to these handlers during or after + * calling the constructor. + * @function + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the tracker instance. + * @param {Object} eventData + * { + * isTouchEvent: True if the original event is a touch event, otherwise false. + * originalEvent: The original event object. + * userData: Arbitrary user-defined object. + * } + */ + blurHandler: function () { } }; /** - * Starts tracking mouse events on this element. - * @private - * @inner - */ + * Starts tracking mouse events on this element. + * @private + * @inner + */ function startTracking( tracker ) { var events = [ - "mouseover", "mouseout", "mousedown", "mouseup", + "mouseover", "mouseout", "mousedown", "mouseup", "mousemove", "click", "DOMMouseScroll", "mousewheel", "touchstart", "touchmove", "touchend", "keypress", "focus", "blur" ], - delegate = THIS[ tracker.hash ], + delegate = THIS[tracker.hash], event, i; if ( !delegate.tracking ) { - for( i = 0; i < events.length; i++ ){ - event = events[ i ]; + for ( i = 0; i < events.length; i++ ) { + event = events[i]; $.addEvent( tracker.element, event, - delegate[ event ], + delegate[event], false ); } delegate.tracking = true; - ACTIVE[ tracker.hash ] = tracker; + ACTIVE[tracker.hash] = tracker; } } /** - * Stops tracking mouse events on this element. - * @private - * @inner - */ + * Stops tracking mouse events on this element. + * @private + * @inner + */ function stopTracking( tracker ) { var events = [ - "mouseover", "mouseout", "mousedown", "mouseup", + "mouseover", "mouseout", "mousedown", "mouseup", "mousemove", "click", "DOMMouseScroll", "mousewheel", "touchstart", "touchmove", "touchend", "keypress", "focus", "blur" ], - delegate = THIS[ tracker.hash ], + delegate = THIS[tracker.hash], event, i; if ( delegate.tracking ) { - for( i = 0; i < events.length; i++ ){ - event = events[ i ]; + for ( i = 0; i < events.length; i++ ) { + event = events[i]; $.removeEvent( tracker.element, event, - delegate[ event ], + delegate[event], false ); } releaseMouse( tracker ); delegate.tracking = false; - delete ACTIVE[ tracker.hash ]; + delete ACTIVE[tracker.hash]; } } /** - * @private - * @inner - */ + * @private + * @inner + */ function hasMouse( tracker ) { - return THIS[ tracker.hash ].insideElement; + return THIS[tracker.hash].insideElement; } /** - * Begin capturing mouse events on this element. - * @private - * @inner - */ + * Begin capturing mouse events on this element. + * @private + * @inner + */ function captureMouse( tracker ) { - var delegate = THIS[ tracker.hash ]; + var delegate = THIS[tracker.hash]; if ( !delegate.capturing ) { if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 9 ) { @@ -445,7 +520,7 @@ $.addEvent( window, "mousemove", - delegate.mousemove, + delegate.mousemovewindow, true ); } @@ -455,12 +530,12 @@ /** - * Stop capturing mouse events on this element. - * @private - * @inner - */ + * Stop capturing mouse events on this element. + * @private + * @inner + */ function releaseMouse( tracker ) { - var delegate = THIS[ tracker.hash ]; + var delegate = THIS[tracker.hash]; if ( delegate.capturing ) { if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 9 ) { @@ -486,7 +561,7 @@ $.removeEvent( window, "mousemove", - delegate.mousemove, + delegate.mousemovewindow, true ); $.removeEvent( @@ -502,32 +577,36 @@ /** - * @private - * @inner - */ - function triggerOthers( tracker, handler, event ) { + * @private + * @inner + */ + function triggerOthers( tracker, handler, event, isTouch ) { var otherHash; for ( otherHash in ACTIVE ) { if ( ACTIVE.hasOwnProperty( otherHash ) && tracker.hash != otherHash ) { - handler( ACTIVE[ otherHash ], event ); + handler( ACTIVE[otherHash], event, isTouch ); } } } /** - * @private - * @inner - */ - function onFocus( tracker, event ){ + * @private + * @inner + */ + function onFocus( tracker, event ) { //console.log( "focus %s", event ); var propagate; if ( tracker.focusHandler ) { propagate = tracker.focusHandler( tracker, - event + { + isTouchEvent: false, + originalEvent: event, + userData: tracker.userData + } ); - if( propagate === false ){ + if ( propagate === false ) { $.cancelEvent( event ); } } @@ -535,18 +614,22 @@ /** - * @private - * @inner - */ - function onBlur( tracker, event ){ + * @private + * @inner + */ + function onBlur( tracker, event ) { //console.log( "blur %s", event ); var propagate; if ( tracker.blurHandler ) { propagate = tracker.blurHandler( tracker, - event + { + isTouchEvent: false, + originalEvent: event, + userData: tracker.userData + } ); - if( propagate === false ){ + if ( propagate === false ) { $.cancelEvent( event ); } } @@ -554,19 +637,25 @@ /** - * @private - * @inner - */ - function onKeyPress( tracker, event ){ + * @private + * @inner + */ + function onKeyPress( tracker, event ) { //console.log( "keypress %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); var propagate; if ( tracker.keyHandler ) { propagate = tracker.keyHandler( tracker, - event.keyCode ? event.keyCode : event.charCode, - event.shiftKey + { + position: getMouseRelative( event, tracker.element ), + keyCode: event.keyCode ? event.keyCode : event.charCode, + shift: event.shiftKey, + isTouchEvent: false, + originalEvent: event, + userData: tracker.userData + } ); - if( !propagate ){ + if ( !propagate ) { $.cancelEvent( event ); } } @@ -574,14 +663,16 @@ /** - * @private - * @inner - */ - function onMouseOver( tracker, event ) { + * @private + * @inner + */ + function onMouseOver( tracker, event, isTouch ) { - var delegate = THIS[ tracker.hash ], + var delegate = THIS[tracker.hash], propagate; + isTouch = ( isTouch !== undefined ) ? isTouch : false; + event = $.getEvent( event ); if ( $.Browser.vendor == $.BROWSERS.IE && @@ -589,7 +680,7 @@ delegate.capturing && !isChild( event.srcElement, tracker.element ) ) { - triggerOthers( tracker, onMouseOver, event ); + triggerOthers( tracker, onMouseOver, event, isTouch ); } var to = event.target ? @@ -609,11 +700,16 @@ if ( tracker.enterHandler ) { propagate = tracker.enterHandler( tracker, - getMouseRelative( event, tracker.element ), - delegate.buttonDown, - IS_BUTTON_DOWN + { + position: getMouseRelative( event, tracker.element ), + buttonDownElement: delegate.buttonDownElement, + buttonDownAny: IS_BUTTON_DOWN, + isTouchEvent: isTouch, + originalEvent: event, + userData: tracker.userData + } ); - if( propagate === false ){ + if ( propagate === false ) { $.cancelEvent( event ); } } @@ -621,13 +717,15 @@ /** - * @private - * @inner - */ - function onMouseOut( tracker, event ) { - var delegate = THIS[ tracker.hash ], + * @private + * @inner + */ + function onMouseOut( tracker, event, isTouch ) { + var delegate = THIS[tracker.hash], propagate; + isTouch = ( isTouch !== undefined ) ? isTouch : false; + event = $.getEvent( event ); if ( $.Browser.vendor == $.BROWSERS.IE && @@ -635,7 +733,7 @@ delegate.capturing && !isChild( event.srcElement, tracker.element ) ) { - triggerOthers( tracker, onMouseOut, event ); + triggerOthers( tracker, onMouseOut, event, isTouch ); } @@ -656,12 +754,17 @@ if ( tracker.exitHandler ) { propagate = tracker.exitHandler( tracker, - getMouseRelative( event, tracker.element ), - delegate.buttonDown, - IS_BUTTON_DOWN + { + position: getMouseRelative( event, tracker.element ), + buttonDownElement: delegate.buttonDownElement, + buttonDownAny: IS_BUTTON_DOWN, + isTouchEvent: isTouch, + originalEvent: event, + userData: tracker.userData + } ); - if( propagate === false ){ + if ( propagate === false ) { $.cancelEvent( event ); } } @@ -669,20 +772,22 @@ /** - * @private - * @inner - */ - function onMouseDown( tracker, event, noCapture ) { - var delegate = THIS[ tracker.hash ], + * @private + * @inner + */ + function onMouseDown( tracker, event, noCapture, isTouch ) { + var delegate = THIS[tracker.hash], propagate; + isTouch = ( isTouch !== undefined ) ? isTouch : false; + event = $.getEvent( event ); if ( event.button == 2 ) { return; } - delegate.buttonDown = true; + delegate.buttonDownElement = true; delegate.lastPoint = getMouseAbsolute( event ); delegate.lastMouseDownPoint = delegate.lastPoint; @@ -691,9 +796,14 @@ if ( tracker.pressHandler ) { propagate = tracker.pressHandler( tracker, - getMouseRelative( event, tracker.element ) + { + position: getMouseRelative( event, tracker.element ), + isTouchEvent: isTouch, + originalEvent: event, + userData: tracker.userData + } ); - if( propagate === false ){ + if ( propagate === false ) { $.cancelEvent( event ); } } @@ -705,47 +815,47 @@ if ( noCapture ) { return; } - + if ( !( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 9 ) || !IS_CAPTURING ) { captureMouse( tracker ); IS_CAPTURING = true; // reset to empty & add us - CAPTURING = [ tracker ]; - } else if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 9 ) { + CAPTURING = [tracker]; + } else if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 9 ) { // add us to the list CAPTURING.push( tracker ); } } /** - * @private - * @inner - */ + * @private + * @inner + */ function onTouchStart( tracker, event ) { var touchA, touchB; - if( event.touches.length == 1 && + if ( event.touches.length == 1 && event.targetTouches.length == 1 && - event.changedTouches.length == 1 ){ + event.changedTouches.length == 1 ) { - THIS[ tracker.hash ].lastTouch = event.touches[ 0 ]; - onMouseOver( tracker, event.changedTouches[ 0 ] ); - // call with no capture as the onMouseMove will + THIS[tracker.hash].lastTouch = event.touches[0]; + onMouseOver( tracker, event.changedTouches[0], true ); + // call with no capture as the onMouseMoveWindow will // be triggered by onTouchMove - onMouseDown( tracker, event.touches[ 0 ], true ); + onMouseDown( tracker, event.touches[0], true, true ); } - if( event.touches.length == 2 ){ + if ( event.touches.length == 2 ) { - touchA = getMouseAbsolute( event.touches[ 0 ] ); - touchB = getMouseAbsolute( event.touches[ 1 ] ); - THIS[ tracker.hash ].lastPinchDelta = + touchA = getMouseAbsolute( event.touches[0] ); + touchB = getMouseAbsolute( event.touches[1] ); + THIS[tracker.hash].lastPinchDelta = Math.abs( touchA.x - touchB.x ) + Math.abs( touchA.y - touchB.y ); - THIS[ tracker.hash ].pinchMidpoint = new $.Point( - ( touchA.x + touchB.x ) / 2 , + THIS[tracker.hash].pinchMidpoint = new $.Point( + ( touchA.x + touchB.x ) / 2, ( touchA.y + touchB.y ) / 2 ); //$.console.debug("pinch start : "+THIS[ tracker.hash ].lastPinchDelta); @@ -756,33 +866,40 @@ /** - * @private - * @inner - */ - function onMouseUp( tracker, event ) { - var delegate = THIS[ tracker.hash ], - //were we inside the tracked element when we were pressed - insideElementPress = delegate.buttonDown, - //are we still inside the tracked element when we released + * @private + * @inner + */ + function onMouseUp( tracker, event, isTouch ) { + var delegate = THIS[tracker.hash], + //were we inside the tracked element when we were pressed + insideElementPress = delegate.buttonDownElement, + //are we still inside the tracked element when we released insideElementRelease = delegate.insideElement, propagate; + isTouch = ( isTouch !== undefined ) ? isTouch : false; + event = $.getEvent( event ); if ( event.button == 2 ) { return; } - delegate.buttonDown = false; + delegate.buttonDownElement = false; if ( tracker.releaseHandler ) { propagate = tracker.releaseHandler( tracker, - getMouseRelative( event, tracker.element ), - insideElementPress, - insideElementRelease + { + position: getMouseRelative( event, tracker.element ), + insideElementPress: insideElementPress, + insideElementRelease: insideElementRelease, + isTouchEvent: isTouch, + originalEvent: event, + userData: tracker.userData + } ); - if( propagate === false ){ + if ( propagate === false ) { $.cancelEvent( event ); } } @@ -794,25 +911,25 @@ /** - * @private - * @inner - */ + * @private + * @inner + */ function onTouchEnd( tracker, event ) { - if( event.touches.length === 0 && + if ( event.touches.length === 0 && event.targetTouches.length === 0 && - event.changedTouches.length == 1 ){ + event.changedTouches.length == 1 ) { + + THIS[tracker.hash].lastTouch = null; - THIS[ tracker.hash ].lastTouch = null; - // call with no release, as the mouse events are // not registered in onTouchStart - onMouseUpWindow( tracker, event.changedTouches[ 0 ], true ); - onMouseOut( tracker, event.changedTouches[ 0 ] ); + onMouseUpWindow( tracker, event.changedTouches[0], true ); + onMouseOut( tracker, event.changedTouches[0], true ); } - if( event.touches.length + event.changedTouches.length == 2 ){ - THIS[ tracker.hash ].lastPinchDelta = null; - THIS[ tracker.hash ].pinchMidpoint = null; + if ( event.touches.length + event.changedTouches.length == 2 ) { + THIS[tracker.hash].lastPinchDelta = null; + THIS[tracker.hash].pinchMidpoint = null; //$.console.debug("pinch end"); } event.preventDefault(); @@ -820,15 +937,15 @@ /** - * Only triggered once by the deepest element that initially received - * the mouse down event. We want to make sure THIS event doesn't bubble. - * Instead, we want to trigger the elements that initially received the - * mouse down event (including this one) only if the mouse is no longer - * inside them. Then, we want to release capture, and emulate a regular - * mouseup on the event that this event was meant for. - * @private - * @inner - */ + * Only triggered once by the deepest element that initially received + * the mouse down event. We want to make sure THIS event doesn't bubble. + * Instead, we want to trigger the elements that initially received the + * mouse down event (including this one) only if the mouse is no longer + * inside them. Then, we want to release capture, and emulate a regular + * mouseup on the event that this event was meant for. + * @private + * @inner + */ function onMouseUpIE( tracker, event ) { var othertracker, i; @@ -840,9 +957,9 @@ } for ( i = 0; i < CAPTURING.length; i++ ) { - othertracker = CAPTURING[ i ]; + othertracker = CAPTURING[i]; if ( !hasMouse( othertracker ) ) { - onMouseUp( othertracker, event ); + onMouseUp( othertracker, event, false ); } } @@ -858,20 +975,20 @@ /** - * Only triggered in W3C browsers by elements within which the mouse was - * initially pressed, since they are now listening to the window for - * mouseup during the capture phase. We shouldn't handle the mouseup - * here if the mouse is still inside this element, since the regular - * mouseup handler will still fire. - * @private - * @inner - */ + * Only triggered in W3C browsers by elements within which the mouse was + * initially pressed, since they are now listening to the window for + * mouseup during the capture phase. We shouldn't handle the mouseup + * here if the mouse is still inside this element, since the regular + * mouseup handler will still fire. + * @private + * @inner + */ function onMouseUpWindow( tracker, event, noRelease ) { - if ( ! THIS[ tracker.hash ].insideElement ) { - onMouseUp( tracker, event ); + if ( !THIS[tracker.hash].insideElement ) { + onMouseUp( tracker, event, false ); } - if (noRelease) { + if ( noRelease ) { return; } @@ -880,9 +997,33 @@ /** - * @private - * @inner - */ + * @private + * @inner + */ + function onMouseMove( tracker, event ) { + if ( tracker.moveHandler ) { + event = $.getEvent( event ); + + var propagate = tracker.moveHandler( + tracker, + { + position: getMouseRelative( event, tracker.element ), + isTouchEvent: false, + originalEvent: event, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ function onMouseClick( tracker, event ) { if ( tracker.clickHandler ) { $.cancelEvent( event ); @@ -891,13 +1032,15 @@ /** - * @private - * @inner - */ - function onMouseWheelSpin( tracker, event ) { + * @private + * @inner + */ + function onMouseWheelSpin( tracker, event, isTouch ) { var nDelta = 0, propagate; + isTouch = ( isTouch !== undefined ) ? isTouch : false; + if ( !event ) { // For IE, access the global (window) event object event = window.event; } @@ -907,7 +1050,7 @@ if ( window.opera ) { // Opera has the values reversed nDelta = -nDelta; } - } else if (event.detail) { // Mozilla FireFox + } else if ( event.detail ) { // Mozilla FireFox nDelta = -event.detail; } //The nDelta variable is gated to provide smooth z-index scrolling @@ -918,11 +1061,16 @@ if ( tracker.scrollHandler ) { propagate = tracker.scrollHandler( tracker, - getMouseRelative( event, tracker.element ), - nDelta, - event.shiftKey + { + position: getMouseRelative( event, tracker.element ), + scroll: nDelta, + shift: event.shiftKey, + isTouchEvent: isTouch, + originalEvent: event, + userData: tracker.userData + } ); - if( propagate === false ){ + if ( propagate === false ) { $.cancelEvent( event ); } } @@ -930,11 +1078,11 @@ /** - * @private - * @inner - */ + * @private + * @inner + */ function handleMouseClick( tracker, event ) { - var delegate = THIS[ tracker.hash ], + var delegate = THIS[tracker.hash], propagate; event = $.getEvent( event ); @@ -943,20 +1091,25 @@ return; } - var time = $.now() - delegate.lastMouseDownTime, - point = getMouseAbsolute( event ), + var time = $.now() - delegate.lastMouseDownTime, + point = getMouseAbsolute( event ), distance = delegate.lastMouseDownPoint.distanceTo( point ), - quick = time <= tracker.clickTimeThreshold && + quick = time <= tracker.clickTimeThreshold && distance <= tracker.clickDistThreshold; if ( tracker.clickHandler ) { propagate = tracker.clickHandler( tracker, - getMouseRelative( event, tracker.element ), - quick, - event.shiftKey + { + position: getMouseRelative( event, tracker.element ), + quick: quick, + shift: event.shiftKey, + isTouchEvent: false, + originalEvent: event, + userData: tracker.userData + } ); - if( propagate === false ){ + if ( propagate === false ) { $.cancelEvent( event ); } } @@ -964,15 +1117,17 @@ /** - * @private - * @inner - */ - function onMouseMove( tracker, event ) { - var delegate = THIS[ tracker.hash ], + * @private + * @inner + */ + function onMouseMoveWindow( tracker, event, isTouch ) { + var delegate = THIS[tracker.hash], delta, propagate, point; + isTouch = ( isTouch !== undefined ) ? isTouch : false; + event = $.getEvent( event ); point = getMouseAbsolute( event ); delta = point.minus( delegate.lastPoint ); @@ -982,11 +1137,16 @@ if ( tracker.dragHandler ) { propagate = tracker.dragHandler( tracker, - getMouseRelative( event, tracker.element ), - delta, - event.shiftKey + { + position: getMouseRelative( event, tracker.element ), + delta: delta, + shift: event.shiftKey, + isTouchEvent: isTouch, + originalEvent: event, + userData: tracker.userData + } ); - if( propagate === false ){ + if ( propagate === false ) { $.cancelEvent( event ); } } @@ -994,74 +1154,75 @@ /** - * @private - * @inner - */ + * @private + * @inner + */ function onTouchMove( tracker, event ) { var touchA, touchB, pinchDelta; - if ( !THIS[ tracker.hash ].lastTouch ) { - return; + if ( !THIS[tracker.hash].lastTouch ) { + return; } - if( event.touches.length === 1 && + if ( event.touches.length === 1 && event.targetTouches.length === 1 && event.changedTouches.length === 1 && - THIS[ tracker.hash ].lastTouch.identifier === event.touches[ 0 ].identifier){ + THIS[tracker.hash].lastTouch.identifier === event.touches[0].identifier ) { - onMouseMove( tracker, event.touches[ 0 ] ); + onMouseMoveWindow( tracker, event.touches[0], true ); - } else if ( event.touches.length === 2 ){ + } else if ( event.touches.length === 2 ) { - touchA = getMouseAbsolute( event.touches[ 0 ] ); - touchB = getMouseAbsolute( event.touches[ 1 ] ); + touchA = getMouseAbsolute( event.touches[0] ); + touchB = getMouseAbsolute( event.touches[1] ); pinchDelta = Math.abs( touchA.x - touchB.x ) + Math.abs( touchA.y - touchB.y ); //TODO: make the 75px pinch threshold configurable - if( Math.abs( THIS[ tracker.hash ].lastPinchDelta - pinchDelta ) > 75 ){ + if ( Math.abs( THIS[tracker.hash].lastPinchDelta - pinchDelta ) > 75 ) { //$.console.debug( "pinch delta : " + pinchDelta + " | previous : " + THIS[ tracker.hash ].lastPinchDelta); onMouseWheelSpin( tracker, { shift: false, - pageX: THIS[ tracker.hash ].pinchMidpoint.x, - pageY: THIS[ tracker.hash ].pinchMidpoint.y, - detail:( - THIS[ tracker.hash ].lastPinchDelta > pinchDelta + shiftKey: false, + pageX: THIS[tracker.hash].pinchMidpoint.x, + pageY: THIS[tracker.hash].pinchMidpoint.y, + detail: ( + THIS[tracker.hash].lastPinchDelta > pinchDelta ) ? 1 : -1 - }); + }, true ); - THIS[ tracker.hash ].lastPinchDelta = pinchDelta; + THIS[tracker.hash].lastPinchDelta = pinchDelta; } } event.preventDefault(); } /** - * Only triggered once by the deepest element that initially received - * the mouse down event. Since no other element has captured the mouse, - * we want to trigger the elements that initially received the mouse - * down event (including this one). The the param tracker isn't used - * but for consistency with the other event handlers we include it. - * @private - * @inner - */ + * Only triggered once by the deepest element that initially received + * the mouse down event. Since no other element has captured the mouse, + * we want to trigger the elements that initially received the mouse + * down event (including this one). The the param tracker isn't used + * but for consistency with the other event handlers we include it. + * @private + * @inner + */ function onMouseMoveIE( tracker, event ) { var i; for ( i = 0; i < CAPTURING.length; i++ ) { - onMouseMove( CAPTURING[ i ], event ); + onMouseMoveWindow( CAPTURING[i], event, false ); } $.stopEvent( event ); } /** - * @private - * @inner - */ + * @private + * @inner + */ function getMouseAbsolute( event ) { return $.getMousePosition( event ); } @@ -1071,8 +1232,8 @@ * @inner */ function getMouseRelative( event, element ) { - var mouse = $.getMousePosition( event ), - offset = $.getElementPosition( element ); + var mouse = $.getMousePosition( event ), + offset = $.getElementOffset( element ); return mouse.minus( offset ); } @@ -1087,7 +1248,7 @@ while ( elementB && elementA != elementB && body != elementB ) { try { elementB = elementB.parentNode; - } catch (e) { + } catch ( e ) { return false; } } @@ -1119,6 +1280,6 @@ $.addEvent( window, "mousedown", onGlobalMouseDown, true ); $.addEvent( window, "mouseup", onGlobalMouseUp, true ); } - })(); + } )(); -}( OpenSeadragon )); +} ( OpenSeadragon ) ); diff --git a/src/navigator.js b/src/navigator.js index cd64f953..f1999831 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -251,13 +251,13 @@ $.extend( $.Navigator.prototype, $.EventHandler.prototype, $.Viewer.prototype, { * @inner * @function */ -function onCanvasClick( tracker, position, quick, shift ) { +function onCanvasClick( tracker, eventData ) { var newBounds, viewerPosition, dimensions; if (! this.drag) { if ( this.viewer.viewport ) { - viewerPosition = this.viewport.deltaPointsFromPixels(position); + viewerPosition = this.viewport.deltaPointsFromPixels( eventData.position ); dimensions = this.viewer.viewport.getBounds().getSize(); newBounds = new $.Rect( viewerPosition.x - dimensions.x/2, @@ -285,18 +285,18 @@ function onCanvasClick( tracker, position, quick, shift ) { * @inner * @function */ -function onCanvasDrag( tracker, position, delta, shift ) { +function onCanvasDrag( tracker, eventData ) { if ( this.viewer.viewport ) { this.drag = true; if( !this.panHorizontal ){ - delta.x = 0; + eventData.delta.x = 0; } if( !this.panVertical ){ - delta.y = 0; + eventData.delta.y = 0; } this.viewer.viewport.panBy( this.viewport.deltaPointsFromPixels( - delta + eventData.delta ) ); } @@ -308,8 +308,8 @@ function onCanvasDrag( tracker, position, delta, shift ) { * @inner * @function */ -function onCanvasRelease( tracker, position, insideElementPress, insideElementRelease ) { - if ( insideElementPress && this.viewer.viewport ) { +function onCanvasRelease( tracker, eventData ) {//position, insideElementPress, insideElementRelease + if ( eventData.insideElementPress && this.viewer.viewport ) { this.viewer.viewport.applyConstraints(); } } diff --git a/src/openseadragon.js b/src/openseadragon.js index e5913772..6da43be9 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -699,6 +699,48 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ }, + /** + * Determines the position of the upper-left corner of the element adjusted for current page and/or element scroll. + * @function + * @name OpenSeadragon.getElementOffset + * @param {Element|String} element - the element we want the position for. + * @returns {Point} - the position of the upper left corner of the element adjusted for current page and/or element scroll. + * Inspired by jQuery.fn.offset() (jquery 1.10.1) + */ + getElementOffset: function( element ) { + var doc = element && element.ownerDocument, + docElement, + win, + boundingRect = { top: 0, left: 0 }; + + if ( !doc ) { + return new $.Point(); + } + + docElement = doc.documentElement; + + // Make sure it's not a disconnected DOM node + //if ( !jQuery.contains( docElement, element ) ) { + // return new $.Point(); + //} + + if ( typeof element.getBoundingClientRect !== typeof undefined ) { + boundingRect = element.getBoundingClientRect(); + } + + win = ( doc == doc.window ) ? + doc : + ( doc.nodeType === 9 ) ? + doc.defaultView || doc.parentWindow : + false; + + return new $.Point( + boundingRect.left + ( win.pageXOffset || docElement.scrollLeft ) - ( docElement.clientLeft || 0 ), + boundingRect.top + ( win.pageYOffset || docElement.scrollTop ) - ( docElement.clientTop || 0 ) + ); + }, + + /** * Determines the height and width of the given element. * @function diff --git a/src/referencestrip.js b/src/referencestrip.js index cfa053da..f822e98a 100644 --- a/src/referencestrip.js +++ b/src/referencestrip.js @@ -32,511 +32,511 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -(function( $ ){ +(function ( $ ) { -// dictionary from id to private properties -var THIS = {}; + // dictionary from id to private properties + var THIS = {}; -/** - * The CollectionDrawer is a reimplementation if the Drawer API that - * focuses on allowing a viewport to be redefined as a collection - * of smaller viewports, defined by a clear number of rows and / or - * columns of which each item in the matrix of viewports has its own - * source. - * - * This idea is a reexpression of the idea of dzi collections - * which allows a clearer algorithm to reuse the tile sources already - * supported by OpenSeadragon, in heterogenious or homogenious - * sequences just like mixed groups already supported by the viewer - * for the purpose of image sequnces. - * - * TODO: The difficult part of this feature is figuring out how to express - * this functionality as a combination of the functionality already - * provided by Drawer, Viewport, TileSource, and Navigator. It may - * require better abstraction at those points in order to effeciently - * reuse those paradigms. - */ -$.ReferenceStrip = function( options ){ + /** + * The CollectionDrawer is a reimplementation if the Drawer API that + * focuses on allowing a viewport to be redefined as a collection + * of smaller viewports, defined by a clear number of rows and / or + * columns of which each item in the matrix of viewports has its own + * source. + * + * This idea is a reexpression of the idea of dzi collections + * which allows a clearer algorithm to reuse the tile sources already + * supported by OpenSeadragon, in heterogenious or homogenious + * sequences just like mixed groups already supported by the viewer + * for the purpose of image sequnces. + * + * TODO: The difficult part of this feature is figuring out how to express + * this functionality as a combination of the functionality already + * provided by Drawer, Viewport, TileSource, and Navigator. It may + * require better abstraction at those points in order to effeciently + * reuse those paradigms. + */ + $.ReferenceStrip = function ( options ) { - var _this = this, - viewer = options.viewer, - viewerSize = $.getElementSize( viewer.element ), + var _this = this, + viewer = options.viewer, + viewerSize = $.getElementSize( viewer.element ), element, style, i; - //We may need to create a new element and id if they did not - //provide the id for the existing element - if( !options.id ){ - options.id = 'referencestrip-' + $.now(); - this.element = $.makeNeutralElement( "div" ); - this.element.id = options.id; - this.element.className = 'referencestrip'; - } - - options = $.extend( true, { - sizeRatio: $.DEFAULT_SETTINGS.referenceStripSizeRatio, - position: $.DEFAULT_SETTINGS.referenceStripPosition, - scroll: $.DEFAULT_SETTINGS.referenceStripScroll, - clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold - }, options, { - //required overrides - element: this.element, - //These need to be overridden to prevent recursion since - //the navigator is a viewer and a viewer has a navigator - showNavigator: false, - mouseNavEnabled: false, - showNavigationControl: false, - showSequenceControl: false - }); - - $.extend( this, options ); - //Private state properties - THIS[ this.id ] = { - "animating": false - }; - - this.minPixelRatio = this.viewer.minPixelRatio; - - style = this.element.style; - style.marginTop = '0px'; - style.marginRight = '0px'; - style.marginBottom = '0px'; - style.marginLeft = '0px'; - style.left = '0px'; - style.bottom = '0px'; - style.border = '0px'; - style.background = '#000'; - style.position = 'relative'; - - $.setElementOpacity( this.element, 0.8 ); - - this.viewer = viewer; - this.innerTracker = new $.MouseTracker({ - element: this.element, - dragHandler: $.delegate( this, onStripDrag ), - scrollHandler: $.delegate( this, onStripScroll ), - enterHandler: $.delegate( this, onStripEnter ), - exitHandler: $.delegate( this, onStripExit ), - keyHandler: $.delegate( this, onKeyPress ) - }).setTracking( true ); - - //Controls the position and orientation of the reference strip and sets the - //appropriate width and height - if( options.width && options.height ){ - this.element.style.width = options.width + 'px'; - this.element.style.height = options.height + 'px'; - viewer.addControl( - this.element, - {anchor: $.ControlAnchor.BOTTOM_LEFT} - ); - } else { - if( "horizontal" == options.scroll ){ - this.element.style.width = ( - viewerSize.x * - options.sizeRatio * - viewer.tileSources.length - ) + ( 12 * viewer.tileSources.length ) + 'px'; - - this.element.style.height = ( - viewerSize.y * - options.sizeRatio - ) + 'px'; - - viewer.addControl( - this.element, - {anchor: $.ControlAnchor.BOTTOM_LEFT} - ); - }else { - this.element.style.height = ( - viewerSize.y * - options.sizeRatio * - viewer.tileSources.length - ) + ( 12 * viewer.tileSources.length ) + 'px'; - - this.element.style.width = ( - viewerSize.x * - options.sizeRatio - ) + 'px'; - - viewer.addControl( - this.element, - {anchor: $.ControlAnchor.TOP_LEFT} - ); - + //We may need to create a new element and id if they did not + //provide the id for the existing element + if ( !options.id ) { + options.id = 'referencestrip-' + $.now(); + this.element = $.makeNeutralElement( "div" ); + this.element.id = options.id; + this.element.className = 'referencestrip'; } - } - this.panelWidth = ( viewerSize.x * this.sizeRatio ) + 8; - this.panelHeight = ( viewerSize.y * this.sizeRatio ) + 8; - this.panels = []; + options = $.extend( true, { + sizeRatio: $.DEFAULT_SETTINGS.referenceStripSizeRatio, + position: $.DEFAULT_SETTINGS.referenceStripPosition, + scroll: $.DEFAULT_SETTINGS.referenceStripScroll, + clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold + }, options, { + //required overrides + element: this.element, + //These need to be overridden to prevent recursion since + //the navigator is a viewer and a viewer has a navigator + showNavigator: false, + mouseNavEnabled: false, + showNavigationControl: false, + showSequenceControl: false + } ); - /*jshint loopfunc:true*/ - for( i = 0; i < viewer.tileSources.length; i++ ){ + $.extend( this, options ); + //Private state properties + THIS[this.id] = { + "animating": false + }; - element = $.makeNeutralElement('div'); - element.id = this.element.id + "-" + i; + this.minPixelRatio = this.viewer.minPixelRatio; - element.style.width = _this.panelWidth + 'px'; - element.style.height = _this.panelHeight + 'px'; - element.style.display = 'inline'; - element.style.float = 'left'; //Webkit - element.style.cssFloat = 'left'; //Firefox - element.style.styleFloat = 'left'; //IE - element.style.padding = '2px'; + style = this.element.style; + style.marginTop = '0px'; + style.marginRight = '0px'; + style.marginBottom = '0px'; + style.marginLeft = '0px'; + style.left = '0px'; + style.bottom = '0px'; + style.border = '0px'; + style.background = '#000'; + style.position = 'relative'; - element.innerTracker = new $.MouseTracker({ - element: element, - clickTimeThreshold: this.clickTimeThreshold, - clickDistThreshold: this.clickDistThreshold, - pressHandler: function( tracker ){ - tracker.dragging = $.now(); - }, - releaseHandler: function( tracker, position, insideElementPress, insideElementRelease ){ - var id = tracker.element.id, - page = Number( id.split( '-' )[ 2 ] ), + $.setElementOpacity( this.element, 0.8 ); + + this.viewer = viewer; + this.innerTracker = new $.MouseTracker( { + element: this.element, + dragHandler: $.delegate( this, onStripDrag ), + scrollHandler: $.delegate( this, onStripScroll ), + enterHandler: $.delegate( this, onStripEnter ), + exitHandler: $.delegate( this, onStripExit ), + keyHandler: $.delegate( this, onKeyPress ) + } ).setTracking( true ); + + //Controls the position and orientation of the reference strip and sets the + //appropriate width and height + if ( options.width && options.height ) { + this.element.style.width = options.width + 'px'; + this.element.style.height = options.height + 'px'; + viewer.addControl( + this.element, + { anchor: $.ControlAnchor.BOTTOM_LEFT } + ); + } else { + if ( "horizontal" == options.scroll ) { + this.element.style.width = ( + viewerSize.x * + options.sizeRatio * + viewer.tileSources.length + ) + ( 12 * viewer.tileSources.length ) + 'px'; + + this.element.style.height = ( + viewerSize.y * + options.sizeRatio + ) + 'px'; + + viewer.addControl( + this.element, + { anchor: $.ControlAnchor.BOTTOM_LEFT } + ); + } else { + this.element.style.height = ( + viewerSize.y * + options.sizeRatio * + viewer.tileSources.length + ) + ( 12 * viewer.tileSources.length ) + 'px'; + + this.element.style.width = ( + viewerSize.x * + options.sizeRatio + ) + 'px'; + + viewer.addControl( + this.element, + { anchor: $.ControlAnchor.TOP_LEFT } + ); + + } + } + + this.panelWidth = ( viewerSize.x * this.sizeRatio ) + 8; + this.panelHeight = ( viewerSize.y * this.sizeRatio ) + 8; + this.panels = []; + + /*jshint loopfunc:true*/ + for ( i = 0; i < viewer.tileSources.length; i++ ) { + + element = $.makeNeutralElement( 'div' ); + element.id = this.element.id + "-" + i; + + element.style.width = _this.panelWidth + 'px'; + element.style.height = _this.panelHeight + 'px'; + element.style.display = 'inline'; + element.style.float = 'left'; //Webkit + element.style.cssFloat = 'left'; //Firefox + element.style.styleFloat = 'left'; //IE + element.style.padding = '2px'; + + element.innerTracker = new $.MouseTracker( { + element: element, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + pressHandler: function ( tracker, eventData ) { + tracker.dragging = $.now(); + }, + releaseHandler: function ( tracker, eventData ) { + var id = tracker.element.id, + page = Number( id.split( '-' )[2] ), now = $.now(); - if ( insideElementPress && - insideElementRelease && + if ( eventData.insideElementPress && + eventData.insideElementRelease && tracker.dragging && - ( now - tracker.dragging ) < tracker.clickTimeThreshold ){ - tracker.dragging = null; - viewer.goToPage( page ); + ( now - tracker.dragging ) < tracker.clickTimeThreshold ) { + tracker.dragging = null; + viewer.goToPage( page ); + } } - } - }).setTracking( true ); + } ).setTracking( true ); - this.element.appendChild( element ); + this.element.appendChild( element ); - element.activePanel = false; + element.activePanel = false; - this.panels.push( element ); + this.panels.push( element ); - } - loadPanels( this, this.scroll == 'vertical' ? viewerSize.y : viewerSize.y, 0); - this.setFocus( 0 ); + } + loadPanels( this, this.scroll == 'vertical' ? viewerSize.y : viewerSize.y, 0 ); + this.setFocus( 0 ); -}; + }; -$.extend( $.ReferenceStrip.prototype, $.EventHandler.prototype, $.Viewer.prototype, { + $.extend( $.ReferenceStrip.prototype, $.EventHandler.prototype, $.Viewer.prototype, { - setFocus: function( page ){ - var element = $.getElement( this.element.id + '-' + page ), + setFocus: function ( page ) { + var element = $.getElement( this.element.id + '-' + page ), viewerSize = $.getElementSize( this.viewer.canvas ), - scrollWidth = Number(this.element.style.width.replace('px','')), - scrollHeight = Number(this.element.style.height.replace('px','')), - offsetLeft = -Number(this.element.style.marginLeft.replace('px','')), - offsetTop = -Number(this.element.style.marginTop.replace('px','')), + scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ), + scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ), + offsetLeft = -Number( this.element.style.marginLeft.replace( 'px', '' ) ), + offsetTop = -Number( this.element.style.marginTop.replace( 'px', '' ) ), offset; - if ( this.currentSelected !== element ){ - if( this.currentSelected ){ - this.currentSelected.style.background = '#000'; - } - this.currentSelected = element; - this.currentSelected.style.background = '#999'; - - if( 'horizontal' == this.scroll ){ - //right left - offset = (Number(page)) * ( this.panelWidth + 3 ); - if( offset > offsetLeft + viewerSize.x - this.panelWidth){ - offset = Math.min(offset, (scrollWidth - viewerSize.x)); - this.element.style.marginLeft = -offset + 'px'; - loadPanels( this, viewerSize.x, -offset ); - }else if( offset < offsetLeft ){ - offset = Math.max(0, offset - viewerSize.x / 2); - this.element.style.marginLeft = -offset + 'px'; - loadPanels( this, viewerSize.x, -offset ); + if ( this.currentSelected !== element ) { + if ( this.currentSelected ) { + this.currentSelected.style.background = '#000'; } - }else{ - offset = (Number(page) ) * ( this.panelHeight + 3 ); - if( offset > offsetTop + viewerSize.y - this.panelHeight){ - offset = Math.min(offset, (scrollHeight - viewerSize.y)); - this.element.style.marginTop = -offset + 'px'; - loadPanels( this, viewerSize.y, -offset ); - }else if( offset < offsetTop ){ - offset = Math.max(0, offset - viewerSize.y / 2); - this.element.style.marginTop = -offset + 'px'; - loadPanels( this, viewerSize.y, -offset ); - } - } + this.currentSelected = element; + this.currentSelected.style.background = '#999'; - this.currentPage = page; - $.getElement( element.id + '-displayregion' ).focus(); - onStripEnter.call( this, this.innerTracker ); + if ( 'horizontal' == this.scroll ) { + //right left + offset = ( Number( page ) ) * ( this.panelWidth + 3 ); + if ( offset > offsetLeft + viewerSize.x - this.panelWidth ) { + offset = Math.min( offset, ( scrollWidth - viewerSize.x ) ); + this.element.style.marginLeft = -offset + 'px'; + loadPanels( this, viewerSize.x, -offset ); + } else if ( offset < offsetLeft ) { + offset = Math.max( 0, offset - viewerSize.x / 2 ); + this.element.style.marginLeft = -offset + 'px'; + loadPanels( this, viewerSize.x, -offset ); + } + } else { + offset = ( Number( page ) ) * ( this.panelHeight + 3 ); + if ( offset > offsetTop + viewerSize.y - this.panelHeight ) { + offset = Math.min( offset, ( scrollHeight - viewerSize.y ) ); + this.element.style.marginTop = -offset + 'px'; + loadPanels( this, viewerSize.y, -offset ); + } else if ( offset < offsetTop ) { + offset = Math.max( 0, offset - viewerSize.y / 2 ); + this.element.style.marginTop = -offset + 'px'; + loadPanels( this, viewerSize.y, -offset ); + } + } + + this.currentPage = page; + $.getElement( element.id + '-displayregion' ).focus(); + onStripEnter.call( this, this.innerTracker, {} ); + } + }, + /** + * @function + * @name OpenSeadragon.ReferenceStrip.prototype.update + */ + update: function () { + if ( THIS[this.id].animating ) { + $.console.log( 'image reference strip update' ); + return true; + } + return false; } - }, + + } ); + + + + /** - * @function - * @name OpenSeadragon.ReferenceStrip.prototype.update - */ - update: function() { - if ( THIS[ this.id ].animating ) { - $.console.log('image reference strip update'); - return true; + * @private + * @inner + * @function + */ + function onStripDrag( tracker, eventData ) { + + var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ), + offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ), + scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ), + scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ), + viewerSize = $.getElementSize( this.viewer.canvas ); + this.dragging = true; + if ( this.element ) { + if ( 'horizontal' == this.scroll ) { + if ( -eventData.delta.x > 0 ) { + //forward + if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) { + this.element.style.marginLeft = ( offsetLeft + ( eventData.delta.x * 2 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft + ( eventData.delta.x * 2 ) ); + } + } else if ( -eventData.delta.x < 0 ) { + //reverse + if ( offsetLeft < 0 ) { + this.element.style.marginLeft = ( offsetLeft + ( eventData.delta.x * 2 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft + ( eventData.delta.x * 2 ) ); + } + } + } else { + if ( -eventData.delta.y > 0 ) { + //forward + if ( offsetTop > -( scrollHeight - viewerSize.y ) ) { + this.element.style.marginTop = ( offsetTop + ( eventData.delta.y * 2 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( eventData.delta.y * 2 ) ); + } + } else if ( -eventData.delta.y < 0 ) { + //reverse + if ( offsetTop < 0 ) { + this.element.style.marginTop = ( offsetTop + ( eventData.delta.y * 2 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( eventData.delta.y * 2 ) ); + } + } + } } return false; + + } + + + + /** + * @private + * @inner + * @function + */ + function onStripScroll( tracker, eventData ) { + var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ), + offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ), + scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ), + scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ), + viewerSize = $.getElementSize( this.viewer.canvas ); + if ( this.element ) { + if ( 'horizontal' == this.scroll ) { + if ( eventData.scroll > 0 ) { + //forward + if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) { + this.element.style.marginLeft = ( offsetLeft - ( eventData.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft - ( eventData.scroll * 60 ) ); + } + } else if ( eventData.scroll < 0 ) { + //reverse + if ( offsetLeft < 0 ) { + this.element.style.marginLeft = ( offsetLeft - ( eventData.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft - ( eventData.scroll * 60 ) ); + } + } + } else { + if ( eventData.scroll < 0 ) { + //scroll up + if ( offsetTop > viewerSize.y - scrollHeight ) { + this.element.style.marginTop = ( offsetTop + ( eventData.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( eventData.scroll * 60 ) ); + } + } else if ( eventData.scroll > 0 ) { + //scroll dowm + if ( offsetTop < 0 ) { + this.element.style.marginTop = ( offsetTop + ( eventData.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( eventData.scroll * 60 ) ); + } + } + } + } + //cancels event + return false; } -}); - - - -/** - * @private - * @inner - * @function - */ -function onStripDrag( tracker, position, delta, shift ) { - - var offsetLeft = Number(this.element.style.marginLeft.replace('px','')), - offsetTop = Number(this.element.style.marginTop.replace('px','')), - scrollWidth = Number(this.element.style.width.replace('px','')), - scrollHeight = Number(this.element.style.height.replace('px','')), - viewerSize = $.getElementSize( this.viewer.canvas ); - this.dragging = true; - if ( this.element ) { - if( 'horizontal' == this.scroll ){ - if ( -delta.x > 0 ) { - //forward - if( offsetLeft > -(scrollWidth - viewerSize.x)){ - this.element.style.marginLeft = ( offsetLeft + (delta.x * 2) ) + 'px'; - loadPanels( this, viewerSize.x, offsetLeft + (delta.x * 2) ); - } - } else if ( -delta.x < 0 ) { - //reverse - if( offsetLeft < 0 ){ - this.element.style.marginLeft = ( offsetLeft + (delta.x * 2) ) + 'px'; - loadPanels( this, viewerSize.x, offsetLeft + (delta.x * 2) ); - } - } - }else{ - if ( -delta.y > 0 ) { - //forward - if( offsetTop > -(scrollHeight - viewerSize.y)){ - this.element.style.marginTop = ( offsetTop + (delta.y * 2) ) + 'px'; - loadPanels( this, viewerSize.y, offsetTop + (delta.y * 2) ); - } - } else if ( -delta.y < 0 ) { - //reverse - if( offsetTop < 0 ){ - this.element.style.marginTop = ( offsetTop + (delta.y * 2) ) + 'px'; - loadPanels( this, viewerSize.y, offsetTop + (delta.y * 2) ); - } - } - } - } - return false; - -} - - - -/** - * @private - * @inner - * @function - */ -function onStripScroll( tracker, position, scroll, shift ) { - var offsetLeft = Number(this.element.style.marginLeft.replace('px','')), - offsetTop = Number(this.element.style.marginTop.replace('px','')), - scrollWidth = Number(this.element.style.width.replace('px','')), - scrollHeight = Number(this.element.style.height.replace('px','')), - viewerSize = $.getElementSize( this.viewer.canvas ); - if ( this.element ) { - if( 'horizontal' == this.scroll ){ - if ( scroll > 0 ) { - //forward - if( offsetLeft > -(scrollWidth - viewerSize.x)){ - this.element.style.marginLeft = ( offsetLeft - (scroll * 60) ) + 'px'; - loadPanels( this, viewerSize.x, offsetLeft - (scroll * 60) ); - } - } else if ( scroll < 0 ) { - //reverse - if( offsetLeft < 0 ){ - this.element.style.marginLeft = ( offsetLeft - (scroll * 60) ) + 'px'; - loadPanels( this, viewerSize.x, offsetLeft - (scroll * 60) ); - } - } - }else{ - if ( scroll < 0 ) { - //scroll up - if( offsetTop > viewerSize.y - scrollHeight ){ - this.element.style.marginTop = ( offsetTop + (scroll * 60) ) + 'px'; - loadPanels( this, viewerSize.y, offsetTop + (scroll * 60) ); - } - } else if ( scroll > 0 ) { - //scroll dowm - if( offsetTop < 0 ){ - this.element.style.marginTop = ( offsetTop + (scroll * 60) ) + 'px'; - loadPanels( this, viewerSize.y, offsetTop + (scroll * 60) ); - } - } - } - } - //cancels event - return false; -} - - -function loadPanels(strip, viewerSize, scroll){ - var panelSize, + function loadPanels( strip, viewerSize, scroll ) { + var panelSize, activePanelsStart, activePanelsEnd, miniViewer, style, i, element; - if( 'horizontal' == strip.scroll ){ - panelSize = strip.panelWidth; - }else{ - panelSize = strip.panelHeight; - } - activePanelsStart = Math.ceil( viewerSize / panelSize ) + 5; - activePanelsEnd = Math.ceil( (Math.abs(scroll) + viewerSize ) / panelSize ) + 1; - activePanelsStart = activePanelsEnd - activePanelsStart; - activePanelsStart = activePanelsStart < 0 ? 0 : activePanelsStart; + if ( 'horizontal' == strip.scroll ) { + panelSize = strip.panelWidth; + } else { + panelSize = strip.panelHeight; + } + activePanelsStart = Math.ceil( viewerSize / panelSize ) + 5; + activePanelsEnd = Math.ceil( ( Math.abs( scroll ) + viewerSize ) / panelSize ) + 1; + activePanelsStart = activePanelsEnd - activePanelsStart; + activePanelsStart = activePanelsStart < 0 ? 0 : activePanelsStart; - for( i = activePanelsStart; i < activePanelsEnd && i < strip.panels.length; i++ ){ - element = strip.panels[ i ]; - if ( !element.activePanel ){ - miniViewer = new $.Viewer( { - id: element.id, - tileSources: [ strip.viewer.tileSources[ i ] ], - element: element, - navigatorSizeRatio: strip.sizeRatio, - showNavigator: false, - mouseNavEnabled: false, - showNavigationControl: false, - showSequenceControl: false, - immediateRender: true, - blendTime: 0, - animationTime: 0 - } ); + for ( i = activePanelsStart; i < activePanelsEnd && i < strip.panels.length; i++ ) { + element = strip.panels[i]; + if ( !element.activePanel ) { + miniViewer = new $.Viewer( { + id: element.id, + tileSources: [strip.viewer.tileSources[i]], + element: element, + navigatorSizeRatio: strip.sizeRatio, + showNavigator: false, + mouseNavEnabled: false, + showNavigationControl: false, + showSequenceControl: false, + immediateRender: true, + blendTime: 0, + animationTime: 0 + } ); - miniViewer.displayRegion = $.makeNeutralElement( "textarea" ); - miniViewer.displayRegion.id = element.id + '-displayregion'; - miniViewer.displayRegion.className = 'displayregion'; + miniViewer.displayRegion = $.makeNeutralElement( "textarea" ); + miniViewer.displayRegion.id = element.id + '-displayregion'; + miniViewer.displayRegion.className = 'displayregion'; - style = miniViewer.displayRegion.style; - style.position = 'relative'; - style.top = '0px'; - style.left = '0px'; - style.fontSize = '0px'; - style.overflow = 'hidden'; - style.float = 'left'; //Webkit - style.cssFloat = 'left'; //Firefox - style.styleFloat = 'left'; //IE - style.zIndex = 999999999; - style.cursor = 'default'; - style.width = ( strip.panelWidth - 4 ) + 'px'; - style.height = ( strip.panelHeight - 4 ) + 'px'; + style = miniViewer.displayRegion.style; + style.position = 'relative'; + style.top = '0px'; + style.left = '0px'; + style.fontSize = '0px'; + style.overflow = 'hidden'; + style.float = 'left'; //Webkit + style.cssFloat = 'left'; //Firefox + style.styleFloat = 'left'; //IE + style.zIndex = 999999999; + style.cursor = 'default'; + style.width = ( strip.panelWidth - 4 ) + 'px'; + style.height = ( strip.panelHeight - 4 ) + 'px'; - miniViewer.displayRegion.innerTracker = new $.MouseTracker({ - element: miniViewer.displayRegion - }); + miniViewer.displayRegion.innerTracker = new $.MouseTracker( { + element: miniViewer.displayRegion + } ); - element.getElementsByTagName('form')[ 0 ].appendChild( + element.getElementsByTagName( 'form' )[0].appendChild( miniViewer.displayRegion ); - element.activePanel = true; + element.activePanel = true; + } } } -} -/** - * @private - * @inner - * @function - */ -function onStripEnter( tracker ) { + /** + * @private + * @inner + * @function + */ + function onStripEnter( tracker, eventData ) { - //$.setElementOpacity(tracker.element, 0.8); + //$.setElementOpacity(tracker.element, 0.8); - //tracker.element.style.border = '1px solid #555'; - //tracker.element.style.background = '#000'; + //tracker.element.style.border = '1px solid #555'; + //tracker.element.style.background = '#000'; - if( 'horizontal' == this.scroll ){ + if ( 'horizontal' == this.scroll ) { - //tracker.element.style.paddingTop = "0px"; - tracker.element.style.marginBottom = "0px"; + //tracker.element.style.paddingTop = "0px"; + tracker.element.style.marginBottom = "0px"; - } else { + } else { - //tracker.element.style.paddingRight = "0px"; - tracker.element.style.marginLeft = "0px"; + //tracker.element.style.paddingRight = "0px"; + tracker.element.style.marginLeft = "0px"; + } + return false; } - return false; -} -/** - * @private - * @inner - * @function - */ -function onStripExit( tracker ) { - if ( 'horizontal' == this.scroll ) { + /** + * @private + * @inner + * @function + */ + function onStripExit( tracker, eventData ) { + if ( 'horizontal' == this.scroll ) { - //tracker.element.style.paddingTop = "10px"; - tracker.element.style.marginBottom = "-" + ( $.getElementSize( tracker.element ).y / 2 ) + "px"; + //tracker.element.style.paddingTop = "10px"; + tracker.element.style.marginBottom = "-" + ( $.getElementSize( tracker.element ).y / 2 ) + "px"; - } else { + } else { - //tracker.element.style.paddingRight = "10px"; - tracker.element.style.marginLeft = "-" + ( $.getElementSize( tracker.element ).x / 2 )+ "px"; + //tracker.element.style.paddingRight = "10px"; + tracker.element.style.marginLeft = "-" + ( $.getElementSize( tracker.element ).x / 2 ) + "px"; + } + return false; } - return false; -} -/** - * @private - * @inner - * @function - */ -function onKeyPress( tracker, keyCode, shiftKey ){ - //console.log( keyCode ); + /** + * @private + * @inner + * @function + */ + function onKeyPress( tracker, eventData ) { + //console.log( eventData.keyCode ); - switch( keyCode ){ - case 61://=|+ - onStripScroll.call(this, this.tracker, null, 1, null); - return false; - case 45://-|_ - onStripScroll.call(this, this.tracker, null, -1, null); - return false; - case 48://0|) - case 119://w - case 87://W - case 38://up arrow - onStripScroll.call(this, this.tracker, null, 1, null); - return false; - case 115://s - case 83://S - case 40://down arrow - onStripScroll.call(this, this.tracker, null, -1, null); - return false; - case 97://a - case 37://left arrow - onStripScroll.call(this, this.tracker, null, -1, null); - return false; - case 100://d - case 39://right arrow - onStripScroll.call(this, this.tracker, null, 1, null); - return false; - default: - //console.log( 'navigator keycode %s', keyCode ); - return true; + switch ( eventData.keyCode ) { + case 61: //=|+ + onStripScroll.call( this, this.tracker, { position: null, scroll: 1, shift: null } ); + return false; + case 45: //-|_ + onStripScroll.call( this, this.tracker, { position: null, scroll: -1, shift: null } ); + return false; + case 48: //0|) + case 119: //w + case 87: //W + case 38: //up arrow + onStripScroll.call( this, this.tracker, { position: null, scroll: 1, shift: null } ); + return false; + case 115: //s + case 83: //S + case 40: //down arrow + onStripScroll.call( this, this.tracker, { position: null, scroll: -1, shift: null } ); + return false; + case 97: //a + case 37: //left arrow + onStripScroll.call( this, this.tracker, { position: null, scroll: -1, shift: null } ); + return false; + case 100: //d + case 39: //right arrow + onStripScroll.call( this, this.tracker, { position: null, scroll: 1, shift: null } ); + return false; + default: + //console.log( 'navigator keycode %s', eventData.keyCode ); + return true; + } } -} -}( OpenSeadragon )); +} ( OpenSeadragon ) ); diff --git a/src/viewer.js b/src/viewer.js index f1880afc..7c374daa 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -265,8 +265,8 @@ $.Viewer = function( options ) { window.scrollTo( 0, point.y ); }, - keyHandler: function(tracker, keyCode, shiftKey){ - switch( keyCode ){ + keyHandler: function( tracker, eventData ){ + switch( eventData.keyCode ){ case 61://=|+ _this.viewport.zoomBy(1.1); _this.viewport.applyConstraints(); @@ -282,7 +282,7 @@ $.Viewer = function( options ) { case 119://w case 87://W case 38://up arrow - if (shiftKey) { + if ( eventData.shift ) { _this.viewport.zoomBy(1.1); } else { _this.viewport.panBy(new $.Point(0, -0.05)); @@ -292,7 +292,7 @@ $.Viewer = function( options ) { case 115://s case 83://S case 40://down arrow - if (shiftKey) { + if ( eventData.shift ) { _this.viewport.zoomBy(0.9); } else { _this.viewport.panBy(new $.Point(0, 0.05)); @@ -310,7 +310,7 @@ $.Viewer = function( options ) { _this.viewport.applyConstraints(); return false; default: - //console.log( 'navigator keycode %s', keyCode ); + //console.log( 'navigator keycode %s', eventData.keyCode ); return true; } } @@ -1426,37 +1426,37 @@ function onBlur(){ } -function onCanvasClick( tracker, position, quick, shift ) { +function onCanvasClick( tracker, eventData ) { var zoomPerClick, factor; - if ( this.viewport && quick ) { // ignore clicks where mouse moved + if ( this.viewport && eventData.quick ) { // ignore clicks where mouse moved zoomPerClick = this.zoomPerClick; - factor = shift ? 1.0 / zoomPerClick : zoomPerClick; + factor = eventData.shift ? 1.0 / zoomPerClick : zoomPerClick; this.viewport.zoomBy( factor, - this.viewport.pointFromPixel( position, true ) + this.viewport.pointFromPixel( eventData.position, true ) ); this.viewport.applyConstraints(); } this.raiseEvent( 'canvas-click', { tracker: tracker, - position: position, - quick: quick, - shift: shift + position: eventData.position, + quick: eventData.quick, + shift: eventData.shift }); } -function onCanvasDrag( tracker, position, delta, shift ) { +function onCanvasDrag( tracker, eventData ) { if ( this.viewport ) { if( !this.panHorizontal ){ - delta.x = 0; + eventData.delta.x = 0; } if( !this.panVertical ){ - delta.y = 0; + eventData.delta.y = 0; } this.viewport.panBy( this.viewport.deltaPointsFromPixels( - delta.negate() + eventData.delta.negate() ) ); if( this.constrainDuringPan ){ @@ -1465,46 +1465,46 @@ function onCanvasDrag( tracker, position, delta, shift ) { } this.raiseEvent( 'canvas-drag', { tracker: tracker, - position: position, - delta: delta, - shift: shift + position: eventData.position, + delta: eventData.delta, + shift: eventData.shift }); } -function onCanvasRelease( tracker, position, insideElementPress, insideElementRelease ) { - if ( insideElementPress && this.viewport ) { +function onCanvasRelease( tracker, eventData ) { + if ( eventData.insideElementPress && this.viewport ) { this.viewport.applyConstraints(); } this.raiseEvent( 'canvas-release', { tracker: tracker, - position: position, - insideElementPress: insideElementPress, - insideElementRelease: insideElementRelease + position: eventData.position, + insideElementPress: eventData.insideElementPress, + insideElementRelease: eventData.insideElementRelease }); } -function onCanvasScroll( tracker, position, scroll, shift ) { +function onCanvasScroll( tracker, eventData ) { var factor; if ( this.viewport ) { - factor = Math.pow( this.zoomPerScroll, scroll ); + factor = Math.pow( this.zoomPerScroll, eventData.scroll ); this.viewport.zoomBy( factor, - this.viewport.pointFromPixel( position, true ) + this.viewport.pointFromPixel( eventData.position, true ) ); this.viewport.applyConstraints(); } this.raiseEvent( 'canvas-scroll', { tracker: tracker, - position: position, - scroll: scroll, - shift: shift + position: eventData.position, + scroll: eventData.scroll, + shift: eventData.shift }); //cancels event return false; } -function onContainerExit( tracker, position, buttonDownElement, buttonDownAny ) { - if ( !buttonDownElement ) { +function onContainerExit( tracker, eventData ) { + if ( !eventData.buttonDownElement ) { THIS[ this.hash ].mouseInside = false; if ( !THIS[ this.hash ].animating ) { beginControlsAutoHide( this ); @@ -1512,14 +1512,14 @@ function onContainerExit( tracker, position, buttonDownElement, buttonDownAny ) } this.raiseEvent( 'container-exit', { tracker: tracker, - position: position, - buttonDownElement: buttonDownElement, - buttonDownAny: buttonDownAny + position: eventData.position, + buttonDownElement: eventData.buttonDownElement, + buttonDownAny: eventData.buttonDownAny }); } -function onContainerRelease( tracker, position, insideElementPress, insideElementRelease ) { - if ( !insideElementRelease ) { +function onContainerRelease( tracker, eventData ) { + if ( !eventData.insideElementRelease ) { THIS[ this.hash ].mouseInside = false; if ( !THIS[ this.hash ].animating ) { beginControlsAutoHide( this ); @@ -1527,20 +1527,20 @@ function onContainerRelease( tracker, position, insideElementPress, insideElemen } this.raiseEvent( 'container-release', { tracker: tracker, - position: position, - insideElementPress: insideElementPress, - insideElementRelease: insideElementRelease + position: eventData.position, + insideElementPress: eventData.insideElementPress, + insideElementRelease: eventData.insideElementRelease }); } -function onContainerEnter( tracker, position, buttonDownElement, buttonDownAny ) { +function onContainerEnter( tracker, eventData ) { THIS[ this.hash ].mouseInside = true; abortControlsAutoHide( this ); this.raiseEvent( 'container-enter', { tracker: tracker, - position: position, - buttonDownElement: buttonDownElement, - buttonDownAny: buttonDownAny + position: eventData.position, + buttonDownElement: eventData.buttonDownElement, + buttonDownAny: eventData.buttonDownAny }); }