From dc48a3141287fd5c1f5d761771fe4d6e5c51a0dd Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Thu, 3 Apr 2014 08:50:25 -0700 Subject: [PATCH] Exposed gesture settings as options --- changelog.txt | 9 ++++- src/mousetracker.js | 36 +++++++++++++++++--- src/openseadragon.js | 64 ++++++++++++++++++++++++++++++----- src/viewer.js | 80 ++++++++++++++++++++++++++++++++------------ 4 files changed, 152 insertions(+), 37 deletions(-) diff --git a/changelog.txt b/changelog.txt index b276e92c..8034bf57 100644 --- a/changelog.txt +++ b/changelog.txt @@ -9,6 +9,7 @@ OPENSEADRAGON CHANGELOG * 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. * 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) * 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) @@ -16,7 +17,7 @@ OPENSEADRAGON CHANGELOG * Enabled basic cross-domain tile loading without tainting canvas (works in Chrome and Firefox) (#308) * Added crossOriginPolicy drawer configuration to enable or disable CORS image requests (#364) * Added a ControlAnchor.ABSOLUTE enumeration. Enables absolute positioning of control elements in the viewer (#310) -* Added a 'navigator-scroll' event to Navigator. Fired when mousewheel/pinch events occur in the navigator (#310) +* Added a 'navigator-scroll' event to Navigator. Fired when mousewheel events occur in the navigator (#310) * Added a navigatorMaintainSizeRatio option. If set to true, the navigator minimap resizes when the viewer element is resized (#310) * Added 'ABSOLUTE' as a navigatorPosition option, along with corresponding navigatorTop, navigatorLeft options. Allows the navigator minimap to be placed anywhere in the viewer (#310) * Enhanced the navigatorTop, navigatorLeft, navigatorHeight, and navigatorWidth options to allow a number for pixel units or a string for other element units (%, em, etc.) (#310) @@ -26,6 +27,12 @@ OPENSEADRAGON CHANGELOG * Added optional Rotate Left/Right buttons to standard controls (#341) * 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 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 + * Added real-time velocity (speed and direction) tracking to drag operations. 'speed' and 'direction' values are passed in the dragHandler and dragEndHandler event data 1.0.0: diff --git a/src/mousetracker.js b/src/mousetracker.js index 8affd458..d7e4cb1c 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -684,6 +684,10 @@ } )(); +/////////////////////////////////////////////////////////////////////////////// +// Event model detection +/////////////////////////////////////////////////////////////////////////////// + /** * Detect available mouse wheel event name. */ @@ -748,6 +752,10 @@ } +/////////////////////////////////////////////////////////////////////////////// +// Classes and typedefs +/////////////////////////////////////////////////////////////////////////////// + /** * Represents a point of contact on the screen made by a mouse cursor, pen, touch, or other pointing device. * @@ -875,8 +883,12 @@ }; +/////////////////////////////////////////////////////////////////////////////// +// Utility functions +/////////////////////////////////////////////////////////////////////////////// + /** - * Starts tracking pointer events on this element. + * Starts tracking pointer events on the tracked element. * @private * @inner */ @@ -900,7 +912,7 @@ } /** - * Stops tracking pointer events on this element. + * Stops tracking pointer events on the tracked element. * @private * @inner */ @@ -926,7 +938,7 @@ } /** - * Begin capturing mouse events on this element (legacy mouse events only). + * Begin capturing mouse events to the tracked element (legacy mouse events only). * @private * @inner */ @@ -958,7 +970,7 @@ /** - * Stop capturing mouse events on this element (legacy mouse events only). + * Stop capturing mouse events to the tracked element (legacy mouse events only). * @private * @inner */ @@ -1013,6 +1025,8 @@ /** + * 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 "". * @private * @inner */ @@ -1079,6 +1093,10 @@ } +/////////////////////////////////////////////////////////////////////////////// +// DOM event handlers +/////////////////////////////////////////////////////////////////////////////// + /** * @private * @inner @@ -1726,6 +1744,10 @@ } +/////////////////////////////////////////////////////////////////////////////// +// DOM event handler utility functions +/////////////////////////////////////////////////////////////////////////////// + /** * Handles 'wheel' events. * The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()). @@ -2294,7 +2316,11 @@ } - // TODO Do we really need these anymore (used as buttonDownAny in enterHandler/exitHandler callbacks)? +/////////////////////////////////////////////////////////////////////////////// +// Deprecated +/////////////////////////////////////////////////////////////////////////////// + + // TODO Do we really need these anymore (used as buttonDownAny in enterHandler/exitHandler callbacks)? // Surely there's a more robust and elegant solution... /** diff --git a/src/openseadragon.js b/src/openseadragon.js index d8c3d973..a85130bd 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -185,10 +185,6 @@ * * @property {String} [debugGridColor='#437AB2'] * - * @property {Number} [animationTime=1.2] - * Specifies the animation duration per each {@link OpenSeadragon.Spring} - * which occur when the image is dragged or zoomed. - * * @property {Number} [blendTime=0] * Specifies the duration of animation as higher or lower level tiles are * replacing the existing tile. @@ -265,8 +261,6 @@ * achieved. Setting this to 0 and wrapHorizontal ( or wrapVertical ) to * true will provide the effect of an infinitely scrolling viewport. * - * @property {Number} [springStiffness=7.0] - * * @property {Number} [imageLoaderLimit=0] * The maximum number of image requests to make concurrently. By default * it is set to 0 allowing the browser to make the maximum number of @@ -280,8 +274,35 @@ * If a mouse or touch drag occurs and the distance to the starting drag * point is less than this many pixels, ignore the drag event. * + * @property {Number} [springStiffness=5.0] + * + * @property {Number} [animationTime=1.2] + * Specifies the animation duration per each {@link OpenSeadragon.Spring} + * which occur when the image is dragged or zoomed. + * + * @property {OpenSeadragon.GestureSettings} [gestureSettingsMouse] + * Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings}) + * @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 {OpenSeadragon.GestureSettings} [gestureSettingsTouch] + * Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings}) + * @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 {OpenSeadragon.GestureSettings} [gestureSettingsPen] + * Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings}) + * @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} [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. + * The "zoom distance" per mouse click or touch tap. Note: Setting this to 1.0 effectively disables the click-to-zoom feature (also see {@link OpenSeadragon.GestureSettings.clickToZoom}). * * @property {Number} [zoomPerScroll=1.2] * The "zoom distance" per mouse scroll or touch pinch. Note: Setting this to 1.0 effectively disables the mouse-wheel zoom feature. @@ -415,6 +436,28 @@ * */ + /** + * Settings for gestures generated by a pointer device. + * + * @typedef {Object} GestureSettings + * @memberof OpenSeadragon + * + * @property {Boolean} clickToZoom + * Set to false to disable zooming on click gestures. + * + * @property {Boolean} flickEnabled + * 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. + * + * @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. + * 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. + * + */ + /** * The names for the image resources used for the image navigation buttons. * @@ -742,13 +785,16 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ maxZoomLevel: null, //UI RESPONSIVENESS AND FEEL - springStiffness: 5.0, clickTimeThreshold: 300, clickDistThreshold: 5, + springStiffness: 5.0, + animationTime: 1.2, + gestureSettingsMouse: { clickToZoom: true, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 }, + gestureSettingsTouch: { clickToZoom: false, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 }, + gestureSettingsPen: { clickToZoom: true, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 }, zoomPerClick: 2, zoomPerScroll: 1.2, zoomPerSecond: 1.0, - animationTime: 1.2, blendTime: 0, alwaysBlend: false, autoHideControls: true, diff --git a/src/viewer.js b/src/viewer.js index 7e834f2b..254ccca2 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -1771,7 +1771,29 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, div.parentNode.removeChild(div); delete this.messageDiv; } + }, + + /** + * 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 "". + * @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 { clickToZoom: false, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.35 }; + } } + }); @@ -2205,16 +2227,17 @@ function onBlur(){ } function onCanvasClick( event ) { - var zoomPerClick, - factor; - if ( event.pointerType !== 'touch' && !event.preventDefaultAction && this.viewport && event.quick ) { - zoomPerClick = this.zoomPerClick; - factor = event.shift ? 1.0 / zoomPerClick : zoomPerClick; - this.viewport.zoomBy( - factor, - this.viewport.pointFromPixel( event.position, true ) - ); - this.viewport.applyConstraints(); + var gestureSettings; + + if ( !event.preventDefaultAction && this.viewport && event.quick ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.clickToZoom ) { + this.viewport.zoomBy( + event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick, + this.viewport.pointFromPixel( event.position, true ) + ); + this.viewport.applyConstraints(); + } } /** * Raised when a mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element. @@ -2240,15 +2263,18 @@ function onCanvasClick( event ) { } function onCanvasDrag( event ) { + var gestureSettings; + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); if( !this.panHorizontal ){ event.delta.x = 0; } if( !this.panVertical ){ event.delta.y = 0; } - this.viewport.panBy( this.viewport.deltaPointsFromPixels( event.delta.negate() ), ( event.pointerType !== 'mouse' ) ? true : false ); - if( this.constrainDuringPan ){ + this.viewport.panBy( this.viewport.deltaPointsFromPixels( event.delta.negate() ), gestureSettings.flickEnabled ); + if( this.constrainDuringPan && !gestureSettings.flickEnabled ){ this.viewport.applyConstraints(); } } @@ -2280,14 +2306,18 @@ function onCanvasDrag( event ) { } function onCanvasDragEnd( event ) { - // TODO: Make the magic numbers configurable (20 pixels-per-second speed threshold and 0.35 momentum dampener). - if ( event.pointerType !== 'mouse' && !event.preventDefaultAction && this.viewport && event.speed > 20 ) { - var amplitudeX = 0.35 * ( event.speed * Math.cos( event.direction ) ), - amplitudeY = 0.35 * ( event.speed * Math.sin( event.direction ) ), - center = this.viewport.pixelFromPoint( this.viewport.getCenter( true ) ), - target = this.viewport.pointFromPixel( new $.Point( center.x - amplitudeX, center.y - amplitudeY ) ); - this.viewport.panTo( target, false ); - this.viewport.applyConstraints(); + var gestureSettings; + + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.flickEnabled && event.speed >= gestureSettings.flickMinSpeed && !event.preventDefaultAction && this.viewport ) { + var amplitudeX = gestureSettings.flickMomentum * ( event.speed * Math.cos( event.direction ) ), + amplitudeY = gestureSettings.flickMomentum * ( event.speed * Math.sin( event.direction ) ), + center = this.viewport.pixelFromPoint( this.viewport.getCenter( true ) ), + target = this.viewport.pointFromPixel( new $.Point( center.x - amplitudeX, center.y - amplitudeY ) ); + this.viewport.panTo( target, false ); + this.viewport.applyConstraints(); + } } /** * Raised when a mouse or touch drag operation ends on the {@link OpenSeadragon.Viewer#canvas} element. @@ -2315,8 +2345,14 @@ function onCanvasDragEnd( event ) { } function onCanvasRelease( event ) { - if ( event.pointerType === 'mouse' && event.insideElementPressed && this.viewport ) { - this.viewport.applyConstraints(); + var gestureSettings; + + if ( event.insideElementPressed && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + + if ( !gestureSettings.flickEnabled ) { + this.viewport.applyConstraints(); + } } /** * Raised when the mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element.