From 7567a657bd225cb6fa6112bebb525be631a8ed67 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 22 Apr 2014 09:23:56 -0700 Subject: [PATCH 1/2] Add Double-Click/Tap Gesture to MouseTracker (#300) Fix for enhancement #300 Added double-click/tap gesture detection to MouseTracker.with corresponding dblClickHandler event callback. Added unit test for double-click detection. Added Viewer dblClickHandler handling to optionally zoom on double-click. --- src/mousetracker.js | 207 ++++++++++++++++++++++++++++---------- src/openseadragon.js | 35 +++++-- src/viewer.js | 71 ++++++++++--- test/events.js | 52 +++++++++- test/legacy.mouse.shim.js | 2 +- 5 files changed, 289 insertions(+), 78 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 4405e93e..1331f60b 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -40,10 +40,8 @@ /** * @class MouseTracker - * @classdesc Provides simplified handling of common pointer device (mouse, touch, pen, etc.) and keyboard - * events on a specific element, like 'enter', 'exit', 'press', 'release', - * 'scroll', 'click', and 'drag'. - * + * @classdesc Provides simplified handling of common pointer device (mouse, touch, pen, etc.) gestures + * and keyboard events on a specified element. * @memberof OpenSeadragon * @param {Object} options * Allows configurable properties to be entirely specified by passing @@ -54,11 +52,17 @@ * A reference to an element or an element id for which the pointer/key * events will be monitored. * @param {Number} options.clickTimeThreshold - * The number of milliseconds within which multiple pointer clicks - * will be treated as a single event. + * The number of milliseconds within which a pointer down-up event combination + * will be treated as a click gesture. * @param {Number} options.clickDistThreshold - * The distance between pointer click within multiple pointer clicks - * will be treated as a single event. + * The maximum distance allowed between a pointer down event and a pointer up event + * to be treated as a click gesture. + * @param {Number} options.dblClickTimeThreshold + * The number of milliseconds within which two pointer down-up event combinations + * will be treated as a double-click gesture. + * @param {Number} options.dblClickDistThreshold + * The maximum distance allowed between two pointer click events + * to be treated as a click gesture. * @param {Number} [options.stopDelay=50] * The number of milliseconds without pointer move before the stop * event is fired. @@ -76,6 +80,8 @@ * An optional handler for mouse wheel scroll. * @param {OpenSeadragon.EventHandler} [options.clickHandler=null] * An optional handler for pointer click. + * @param {OpenSeadragon.EventHandler} [options.dblClickHandler=null] + * An optional handler for pointer double-click. * @param {OpenSeadragon.EventHandler} [options.dragHandler=null] * An optional handler for the drag gesture. * @param {OpenSeadragon.EventHandler} [options.dragEndHandler=null] @@ -111,34 +117,51 @@ */ this.element = $.getElement( options.element ); /** - * The number of milliseconds within which mutliple pointer clicks will be treated as a single event. + * The number of milliseconds within which a pointer down-up event combination + * will be treated as a click gesture. * @member {Number} clickTimeThreshold * @memberof OpenSeadragon.MouseTracker# */ this.clickTimeThreshold = options.clickTimeThreshold; /** - * The distance between pointer click within multiple pointer clicks will be treated as a single event. + * The maximum distance allowed between a pointer down event and a pointer up event + * to be treated as a click gesture. * @member {Number} clickDistThreshold * @memberof OpenSeadragon.MouseTracker# */ this.clickDistThreshold = options.clickDistThreshold; - this.userData = options.userData || null; - this.stopDelay = options.stopDelay || 50; + /** + * The number of milliseconds within which two pointer down-up event combinations + * will be treated as a double-click gesture. + * @member {Number} dblClickTimeThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.dblClickTimeThreshold = options.dblClickTimeThreshold; + /** + * The maximum distance allowed between two pointer click events + * to be treated as a click gesture. + * @member {Number} clickDistThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.dblClickDistThreshold = options.dblClickDistThreshold; + this.userData = options.userData || null; + this.stopDelay = options.stopDelay || 50; - this.enterHandler = options.enterHandler || null; - this.exitHandler = options.exitHandler || null; - this.pressHandler = options.pressHandler || null; - this.releaseHandler = options.releaseHandler || null; - this.moveHandler = options.moveHandler || null; - this.scrollHandler = options.scrollHandler || null; - this.clickHandler = options.clickHandler || null; - this.dragHandler = options.dragHandler || null; - this.dragEndHandler = options.dragEndHandler || null; - this.pinchHandler = options.pinchHandler || null; - this.stopHandler = options.stopHandler || null; - this.keyHandler = options.keyHandler || null; - this.focusHandler = options.focusHandler || null; - this.blurHandler = options.blurHandler || null; + this.enterHandler = options.enterHandler || null; + this.exitHandler = options.exitHandler || null; + this.pressHandler = options.pressHandler || null; + this.releaseHandler = options.releaseHandler || null; + this.moveHandler = options.moveHandler || null; + this.scrollHandler = options.scrollHandler || null; + this.clickHandler = options.clickHandler || null; + this.dblClickHandler = options.dblClickHandler || null; + this.dragHandler = options.dragHandler || null; + this.dragEndHandler = options.dragEndHandler || null; + this.pinchHandler = options.pinchHandler || null; + this.stopHandler = options.stopHandler || 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; @@ -154,6 +177,7 @@ setCaptureCapable: !!this.element.setCapture && !!this.element.releaseCapture, click: function ( event ) { onClick( _this, event ); }, + dblclick: function ( event ) { onDblClick( _this, event ); }, keypress: function ( event ) { onKeyPress( _this, event ); }, focus: function ( event ) { onFocus( _this, event ); }, blur: function ( event ) { onBlur( _this, event ); }, @@ -207,6 +231,10 @@ // Legacy mouse event tracking capturing: false, + // Tracking for double-click gesture + lastClickPos: null, + dblClickTimeOut: null, + // Tracking for pinch gesture pinchGPoints: [], lastPinchDist: 0, @@ -456,7 +484,7 @@ * @param {OpenSeadragon.Point} event.position * The position of the event relative to the tracked element. * @param {Boolean} event.quick - * True only if the clickDistThreshold and clickDeltaThreshold are both passed. Useful for ignoring events. + * True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for ignoring drag events. * @param {Boolean} event.shift * True if the shift key was pressed during this event. * @param {Boolean} event.isTouchEvent @@ -470,6 +498,30 @@ */ clickHandler: function () { }, + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + dblClickHandler: function () { }, + /** * Implement or assign implementation to these handlers during or after * calling the constructor. @@ -746,7 +798,7 @@ /** * Detect browser pointer device event model(s) and build appropriate list of events to subscribe to. */ - $.MouseTracker.subscribeEvents = [ "click", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ]; + $.MouseTracker.subscribeEvents = [ "click", "dblclick", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ]; if( $.MouseTracker.wheelEventName == "DOMMouseScroll" ) { // Older Firefox @@ -877,6 +929,12 @@ * @memberof OpenSeadragon.MouseTracker.GesturePointList# */ this.contacts = 0; + /** + * Current number of clicks for the device. Used for multiple click gesture tracking. + * @member {Number} clicks + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.clicks = 0; }; $.MouseTracker.GesturePointList.prototype = /** @lends OpenSeadragon.MouseTracker.GesturePointList.prototype */{ /** @@ -1164,6 +1222,17 @@ } + /** + * @private + * @inner + */ + function onDblClick( tracker, event ) { + if ( tracker.dblClickHandler ) { + $.cancelEvent( event ); + } + } + + /** * @private * @inner @@ -1453,7 +1522,7 @@ captureMouse( tracker ); } - if ( tracker.clickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) { + if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) { $.cancelEvent( event ); } } @@ -1798,7 +1867,7 @@ $.stopEvent( event ); } - if ( tracker.clickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { + if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { $.cancelEvent( event ); } } @@ -2213,7 +2282,8 @@ curGPoint, updateGPoint, releaseCapture = false, - wasCaptured = false; + wasCaptured = false, + quick; if ( typeof event.buttons !== 'undefined' ) { pointsList.buttons = event.buttons; @@ -2320,28 +2390,63 @@ } } - // Click - if ( tracker.clickHandler && updateGPoint.insideElementPressed && updateGPoint.insideElement ) { - var time = releaseTime - updateGPoint.contactTime, - distance = updateGPoint.contactPos.distanceTo( releasePoint ), - quick = time <= tracker.clickTimeThreshold && - distance <= tracker.clickDistThreshold; + // Click / Double-Click + if ( ( tracker.clickHandler || tracker.dblClickHandler ) && updateGPoint.insideElement ) { + quick = releaseTime - updateGPoint.contactTime <= tracker.clickTimeThreshold && + updateGPoint.contactPos.distanceTo( releasePoint ) <= tracker.clickDistThreshold; - propagate = tracker.clickHandler( - { - eventSource: tracker, - pointerType: updateGPoint.type, - position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), - quick: quick, - shift: event.shiftKey, - isTouchEvent: updateGPoint.type === 'touch', - originalEvent: event, - preventDefaultAction: false, - userData: tracker.userData + // Click + if ( tracker.clickHandler ) { + propagate = tracker.clickHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + quick: quick, + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Double-Click + if ( tracker.dblClickHandler && quick ) { + pointsList.clicks++; + if ( pointsList.clicks === 1 ) { + delegate.lastClickPos = releasePoint; + /*jshint loopfunc:true*/ + delegate.dblClickTimeOut = setTimeout( function() { + pointsList.clicks = 0; + }, tracker.dblClickTimeThreshold ); + /*jshint loopfunc:false*/ + } else if ( pointsList.clicks === 2 ) { + clearTimeout( delegate.dblClickTimeOut ); + pointsList.clicks = 0; + if ( delegate.lastClickPos.distanceTo( releasePoint ) <= tracker.dblClickDistThreshold ) { + propagate = tracker.dblClickHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + delegate.lastClickPos = null; } - ); - if ( propagate === false ) { - $.cancelEvent( event ); } } } else if ( pointsList.contacts === 2 ) { diff --git a/src/openseadragon.js b/src/openseadragon.js index c7f69749..1956c3f0 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -267,12 +267,20 @@ * image requests in parallel as allowed by the browsers policy. * * @property {Number} [clickTimeThreshold=300] - * If multiple mouse clicks occurs within less than this number of - * milliseconds, treat them as a single click. + * The number of milliseconds within which a pointer down-up event combination + * will be treated as a click gesture. * * @property {Number} [clickDistThreshold=5] - * 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. + * The maximum distance allowed between a pointer down event and a pointer up event + * to be treated as a click gesture. + * + * @property {Number} [dblClickTimeThreshold=300] + * The number of milliseconds within which two pointer down-up event combinations + * will be treated as a double-click gesture. + * + * @property {Number} [dblClickDistThreshold=20] + * The maximum distance allowed between two pointer click events + * to be treated as a double-click gesture. * * @property {Number} [springStiffness=5.0] * @@ -284,6 +292,7 @@ * Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings}) * @property {Boolean} [gestureSettingsMouse.scrollToZoom=true] - Zoom on scroll gesture * @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture + * @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture * @property {Boolean} [gestureSettingsMouse.pinchToZoom=false] - Zoom on pinch gesture * @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick gesture * @property {Number} [gestureSettingsMouse.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) @@ -293,6 +302,7 @@ * Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings}) * @property {Boolean} [gestureSettingsTouch.scrollToZoom=false] - Zoom on scroll gesture * @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture + * @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture * @property {Boolean} [gestureSettingsTouch.pinchToZoom=true] - Zoom on pinch gesture * @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick gesture * @property {Number} [gestureSettingsTouch.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) @@ -302,6 +312,7 @@ * Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings}) * @property {Boolean} [gestureSettingsPen.scrollToZoom=false] - Zoom on scroll gesture * @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture + * @property {Boolean} [gestureSettingsPen.dblClickToZoom=false] - Zoom on double-click gesture * @property {Boolean} [gestureSettingsPen.pinchToZoom=false] - Zoom on pinch gesture * @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick gesture * @property {Number} [gestureSettingsPen.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) @@ -311,13 +322,14 @@ * Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings}) * @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture * @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture + * @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture * @property {Boolean} [gestureSettingsUnknown.pinchToZoom=true] - Zoom on pinch gesture * @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick gesture * @property {Number} [gestureSettingsUnknown.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) * @property {Number} [gestureSettingsUnknown.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture * * @property {Number} [zoomPerClick=2.0] - * The "zoom distance" per mouse click or touch tap. Note: Setting this to 1.0 effectively disables the click-to-zoom feature (also see gestureSettings[Mouse|Touch|Pen].clickToZoom). + * The "zoom distance" per mouse click or touch tap. Note: Setting this to 1.0 effectively disables the click-to-zoom feature (also see gestureSettings[Mouse|Touch|Pen].clickToZoom/dblClickToZoom). * * @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 (also see gestureSettings[Mouse|Touch|Pen].scrollToZoom}). @@ -534,6 +546,9 @@ * @property {Boolean} clickToZoom * Set to false to disable zooming on click gestures. * + * @property {Boolean} dblClickToZoom + * Set to false to disable zooming on double-click gestures. + * * @property {Boolean} pinchToZoom * Set to false to disable zooming on pinch gestures. * @@ -891,12 +906,14 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ //UI RESPONSIVENESS AND FEEL clickTimeThreshold: 300, clickDistThreshold: 5, + dblClickTimeThreshold: 300, + dblClickDistThreshold: 20, springStiffness: 5.0, animationTime: 1.2, - gestureSettingsMouse: { scrollToZoom: true, clickToZoom: true, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 }, - gestureSettingsTouch: { scrollToZoom: false, clickToZoom: false, pinchToZoom: true, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 }, - gestureSettingsPen: { scrollToZoom: false, clickToZoom: true, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 }, - gestureSettingsUnknown: { scrollToZoom: false, clickToZoom: false, pinchToZoom: true, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 }, + gestureSettingsMouse: { scrollToZoom: true, clickToZoom: true, dblClickToZoom: false, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 }, + gestureSettingsTouch: { scrollToZoom: false, clickToZoom: false, dblClickToZoom: true, pinchToZoom: true, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 }, + gestureSettingsPen: { scrollToZoom: false, clickToZoom: true, dblClickToZoom: false, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 }, + gestureSettingsUnknown: { scrollToZoom: false, clickToZoom: false, dblClickToZoom: true, pinchToZoom: true, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 }, zoomPerClick: 2, zoomPerScroll: 1.2, zoomPerSecond: 1.0, diff --git a/src/viewer.js b/src/viewer.js index bd01afe3..0451c305 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -385,24 +385,29 @@ $.Viewer = function( options ) { this.innerTracker = new $.MouseTracker({ - element: this.canvas, - clickTimeThreshold: this.clickTimeThreshold, - clickDistThreshold: this.clickDistThreshold, - clickHandler: $.delegate( this, onCanvasClick ), - dragHandler: $.delegate( this, onCanvasDrag ), - dragEndHandler: $.delegate( this, onCanvasDragEnd ), - releaseHandler: $.delegate( this, onCanvasRelease ), - scrollHandler: $.delegate( this, onCanvasScroll ), - pinchHandler: $.delegate( this, onCanvasPinch ) + element: this.canvas, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + dblClickTimeThreshold: this.dblClickTimeThreshold, + dblClickDistThreshold: this.dblClickDistThreshold, + clickHandler: $.delegate( this, onCanvasClick ), + dblClickHandler: $.delegate( this, onCanvasDblClick ), + dragHandler: $.delegate( this, onCanvasDrag ), + dragEndHandler: $.delegate( this, onCanvasDragEnd ), + releaseHandler: $.delegate( this, onCanvasRelease ), + scrollHandler: $.delegate( this, onCanvasScroll ), + pinchHandler: $.delegate( this, onCanvasPinch ) }).setTracking( this.mouseNavEnabled ? true : false ); // default state this.outerTracker = new $.MouseTracker({ - element: this.container, - clickTimeThreshold: this.clickTimeThreshold, - clickDistThreshold: this.clickDistThreshold, - enterHandler: $.delegate( this, onContainerEnter ), - exitHandler: $.delegate( this, onContainerExit ), - releaseHandler: $.delegate( this, onContainerRelease ) + element: this.container, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + dblClickTimeThreshold: this.dblClickTimeThreshold, + dblClickDistThreshold: this.dblClickDistThreshold, + enterHandler: $.delegate( this, onContainerEnter ), + exitHandler: $.delegate( this, onContainerExit ), + releaseHandler: $.delegate( this, onContainerRelease ) }).setTracking( this.mouseNavEnabled ? true : false ); // always tracking if( this.toolbar ){ @@ -2253,7 +2258,7 @@ function onCanvasClick( event ) { * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. - * @property {Boolean} quick - True only if the clickDistThreshold and clickDeltaThreshold are both passed. Useful for differentiating between clicks and drags. + * @property {Boolean} quick - True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for differentiating between clicks and drags. * @property {Boolean} shift - True if the shift key was pressed during this event. * @property {Object} originalEvent - The original DOM event. * @property {?Object} userData - Arbitrary subscriber-defined object. @@ -2267,6 +2272,40 @@ function onCanvasClick( event ) { }); } +function onCanvasDblClick( event ) { + var gestureSettings; + + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.dblClickToZoom ) { + this.viewport.zoomBy( + event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick, + this.viewport.pointFromPixel( event.position, true ) + ); + this.viewport.applyConstraints(); + } + } + /** + * Raised when a double mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-double-click + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-double-click', { + tracker: event.eventSource, + position: event.position, + shift: event.shift, + originalEvent: event.originalEvent + }); +} + function onCanvasDrag( event ) { var gestureSettings; diff --git a/test/events.js b/test/events.js index 61137046..36a49b17 100644 --- a/test/events.js +++ b/test/events.js @@ -37,6 +37,7 @@ origReleaseHandler, origMoveHandler, origClickHandler, + origDblClickHandler, origDragHandler, origDragEndHandler, enterCount, @@ -45,6 +46,7 @@ releaseCount, moveCount, clickCount, + dblClickCount, dragCount, dragEndCount, insideElementPressed, @@ -111,6 +113,15 @@ return true; } }; + origDblClickHandler = tracker.dblClickHandler; + tracker.dblClickHandler = function ( event ) { + dblClickCount++; + if (origDblClickHandler) { + return origDblClickHandler( event ); + } else { + return true; + } + }; origDragHandler = tracker.dragHandler; tracker.dragHandler = function ( event ) { dragCount++; @@ -140,6 +151,7 @@ tracker.releaseHandler = origReleaseHandler; tracker.moveHandler = origMoveHandler; tracker.clickHandler = origClickHandler; + tracker.dblClickHandler = origDblClickHandler; tracker.dragHandler = origDragHandler; tracker.dragEndHandler = origDragEndHandler; }; @@ -188,6 +200,7 @@ releaseCount = 0; moveCount = 0; clickCount = 0; + dblClickCount = 0; dragCount = 0; dragEndCount = 0; insideElementPressed = false; @@ -217,6 +230,9 @@ if ('clickCount' in expected) { equal( clickCount, expected.clickCount, expected.description + 'clickHandler event count matches expected (' + expected.clickCount + ')' ); } + if ('dblClickCount' in expected) { + equal( dblClickCount, expected.dblClickCount, expected.description + 'dblClickHandler event count matches expected (' + expected.dblClickCount + ')' ); + } if ('dragCount' in expected) { equal( dragCount, expected.dragCount, expected.description + 'dragHandler event count matches expected (' + expected.dragCount + ')' ); } @@ -269,6 +285,7 @@ releaseCount: 1, moveCount: 20, clickCount: 0, + dblClickCount: 0, dragCount: 0, dragEndCount: 0, insideElementPressed: false, @@ -293,6 +310,7 @@ releaseCount: 0, moveCount: 20, clickCount: 0, + dblClickCount: 0, dragCount: 0, dragEndCount: 0, //insideElementPressed: false, @@ -315,6 +333,7 @@ releaseCount: 0, moveCount: 20, clickCount: 0, + dblClickCount: 0, dragCount: 0, dragEndCount: 0, //insideElementPressed: false, @@ -324,7 +343,33 @@ //quickClick: false }); - // enter-press-release-exit + // enter-press-release-press-release-exit (double click) + resetForAssessment(); + simulateEnter(0, 0); + simulateDown(0, 0); + simulateUp(0, 0); + simulateDown(0, 0); + simulateUp(0, 0); + simulateLeave(-1, -1); + assessGestureExpectations({ + description: 'enter-press-release-press-release-exit (double click): ', + enterCount: 1, + exitCount: 1, + pressCount: 2, + releaseCount: 2, + moveCount: 0, + clickCount: 2, + dblClickCount: 1, + dragCount: 0, + dragEndCount: 0, + insideElementPressed: true, + insideElementReleased: true, + contacts: 0, + trackedPointers: 0 + //quickClick: true + }); + + // enter-press-release-exit (click) resetForAssessment(); simulateEnter(0, 0); simulateDown(0, 0); @@ -338,6 +383,7 @@ releaseCount: 1, moveCount: 0, clickCount: 1, + dblClickCount: 0, dragCount: 0, dragEndCount: 0, insideElementPressed: true, @@ -363,6 +409,7 @@ releaseCount: 1, moveCount: 200, clickCount: 1, + dblClickCount: 0, dragCount: 100, dragEndCount: 1, insideElementPressed: true, @@ -389,6 +436,7 @@ releaseCount: 1, moveCount: 15, clickCount: 0, + dblClickCount: 0, dragCount: 15, dragEndCount: 1, insideElementPressed: true, @@ -509,6 +557,8 @@ userData: userData, clickTimeThreshold: OpenSeadragon.DEFAULT_SETTINGS.clickTimeThreshold, clickDistThreshold: OpenSeadragon.DEFAULT_SETTINGS.clickDistThreshold, + dblClickTimeThreshold: OpenSeadragon.DEFAULT_SETTINGS.dblClickTimeThreshold, + dblClickDistThreshold: OpenSeadragon.DEFAULT_SETTINGS.dblClickDistThreshold, focusHandler: onMouseTrackerFocus, blurHandler: onMouseTrackerBlur, enterHandler: onMouseTrackerEnter, diff --git a/test/legacy.mouse.shim.js b/test/legacy.mouse.shim.js index 9643d610..460a8dfe 100644 --- a/test/legacy.mouse.shim.js +++ b/test/legacy.mouse.shim.js @@ -4,7 +4,7 @@ * Plugin to force OpenSeadragon to use the legacy mouse pointer event model */ - $.MouseTracker.subscribeEvents = [ "click", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ]; + $.MouseTracker.subscribeEvents = [ "click", "dblclick", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ]; if( $.MouseTracker.wheelEventName == "DOMMouseScroll" ) { // Older Firefox From e900b605af34800a5caf35d40727be9b04851cf3 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 22 Apr 2014 09:41:29 -0700 Subject: [PATCH 2/2] Update changelog.txt Updated changelog. Misc documentation fixes. --- changelog.txt | 2 ++ src/openseadragon.js | 15 ++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3206e6f7..36e4b065 100644 --- a/changelog.txt +++ b/changelog.txt @@ -48,6 +48,8 @@ OPENSEADRAGON CHANGELOG * Added a GestureSettings class for per-device gesture options. Currently has settings to enable/disable zoom-on-scroll, zoom-on-pinch, zoom-on-click, and flick gesture settings. * Added GestureSettings objects for mouse, touch, and pen devices to the Viewer options giving users the ability to customize gesture handling in the viewer * Added velocity (speed and direction) properties to the "canvas-drag" event +* Added double-click gesture detection to MouseTracker with corresponding dblClickHandler event callback (#392) +* Added zoom on double-click feature to Viewer, with corresponding dblClickToZoom option added to the GestureSettings class (#392) 1.0.0: diff --git a/src/openseadragon.js b/src/openseadragon.js index 1956c3f0..f9a5640e 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -292,7 +292,8 @@ * Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings}) * @property {Boolean} [gestureSettingsMouse.scrollToZoom=true] - Zoom on scroll gesture * @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture - * @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture + * @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. * @property {Boolean} [gestureSettingsMouse.pinchToZoom=false] - Zoom on pinch gesture * @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick gesture * @property {Number} [gestureSettingsMouse.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) @@ -302,7 +303,8 @@ * Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings}) * @property {Boolean} [gestureSettingsTouch.scrollToZoom=false] - Zoom on scroll gesture * @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture - * @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture + * @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. * @property {Boolean} [gestureSettingsTouch.pinchToZoom=true] - Zoom on pinch gesture * @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick gesture * @property {Number} [gestureSettingsTouch.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) @@ -312,7 +314,8 @@ * Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings}) * @property {Boolean} [gestureSettingsPen.scrollToZoom=false] - Zoom on scroll gesture * @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture - * @property {Boolean} [gestureSettingsPen.dblClickToZoom=false] - Zoom on double-click gesture + * @property {Boolean} [gestureSettingsPen.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. * @property {Boolean} [gestureSettingsPen.pinchToZoom=false] - Zoom on pinch gesture * @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick gesture * @property {Number} [gestureSettingsPen.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) @@ -322,7 +325,8 @@ * Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings}) * @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture * @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture - * @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture + * @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. * @property {Boolean} [gestureSettingsUnknown.pinchToZoom=true] - Zoom on pinch gesture * @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick gesture * @property {Number} [gestureSettingsUnknown.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) @@ -547,7 +551,8 @@ * Set to false to disable zooming on click gestures. * * @property {Boolean} dblClickToZoom - * Set to false to disable zooming on double-click gestures. + * Set to false to disable zooming on double-click gestures. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. * * @property {Boolean} pinchToZoom * Set to false to disable zooming on pinch gestures.