pinchToZoom gesture option added, misc. fixes

changelog update.
pinchToZoom gesture option added.
Event unit tests cleaned up.
This commit is contained in:
Mark Salsbery 2014-04-15 19:19:47 -07:00
parent b897959cff
commit c2e7b376b0
5 changed files with 73 additions and 92 deletions

View File

@ -41,11 +41,11 @@ OPENSEADRAGON CHANGELOG
* Added a pinchHandler event callback, called as a pinch gesture (2 touch points) is occurring * 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 * Added real-time velocity (speed and direction) tracking to drag operations. 'speed' and 'direction' values are passed in the dragHandler and dragEndHandler event data
* Enhanced Viewer for multi-touch (#369) * Enhanced Viewer for multi-touch (#369)
* Added pinch zoom with the new MouseTracker pinchHandler * Added pinch zoom with the new MouseTracker pinchHandler. The 'pan' and 'zoom' Viewer events can be used to detect changes resulting in pinch gestures
* Added a "canvas-pinch" event fired by the pinch event handler * Added a "canvas-pinch" event fired by the pinch event handler
* Added flick gesture with the new MouseTracker dragEndHandler * Added flick gesture with the new MouseTracker dragEndHandler
* Added a "canvas-drag-end" event fired by the drag-end event handler * Added a "canvas-drag-end" event fired by the drag-end event handler
* Added a GestureSettings class for per-device gesture options. Currently has settings to enable/disable zoom-on-scroll, zoom-on-click, and flick gesture settings. * 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 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 velocity (speed and direction) properties to the "canvas-drag" event

View File

@ -2116,7 +2116,7 @@
// Only capture and track primary button, pen, and touch contacts // Only capture and track primary button, pen, and touch contacts
//if ( buttonChanged !== 0 ) { //if ( buttonChanged !== 0 ) {
if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the line above if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the commented line above
return false; return false;
} }
@ -2241,7 +2241,7 @@
// Only capture and track primary button, pen, and touch contacts // Only capture and track primary button, pen, and touch contacts
//if ( buttonChanged !== 0 ) { //if ( buttonChanged !== 0 ) {
if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the line above if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the commented line above
return false; return false;
} }
@ -2570,7 +2570,8 @@
* Gesture points associated with the event. * Gesture points associated with the event.
*/ */
function updatePointersCancel( tracker, event, gPoints ) { function updatePointersCancel( tracker, event, gPoints ) {
//removePointers( tracker, event, gPoints ); updatePointersUp( tracker, event, gPoints, 0 );
updatePointersExit( tracker, event, gPoints );
} }

View File

@ -284,6 +284,7 @@
* Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings}) * 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.scrollToZoom=true] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture * @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture
* @property {Boolean} [gestureSettingsMouse.pinchToZoom=false] - Zoom on pinch gesture
* @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick 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) * @property {Number} [gestureSettingsMouse.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
* @property {Number} [gestureSettingsMouse.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture * @property {Number} [gestureSettingsMouse.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture
@ -292,6 +293,7 @@
* Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings}) * 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.scrollToZoom=false] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture * @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture
* @property {Boolean} [gestureSettingsTouch.pinchToZoom=true] - Zoom on pinch gesture
* @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick 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) * @property {Number} [gestureSettingsTouch.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
* @property {Number} [gestureSettingsTouch.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture * @property {Number} [gestureSettingsTouch.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture
@ -300,6 +302,7 @@
* Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings}) * 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.scrollToZoom=false] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture * @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture
* @property {Boolean} [gestureSettingsPen.pinchToZoom=false] - Zoom on pinch gesture
* @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick 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) * @property {Number} [gestureSettingsPen.flickMinSpeed=20] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
* @property {Number} [gestureSettingsPen.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture * @property {Number} [gestureSettingsPen.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture
@ -308,6 +311,7 @@
* Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings}) * Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings})
* @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture * @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture
* @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture * @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture
* @property {Boolean} [gestureSettingsUnknown.pinchToZoom=true] - Zoom on pinch gesture
* @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick 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.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} [gestureSettingsUnknown.flickMomentum=0.40] - If flickEnabled is true, the momentum factor for the flick gesture
@ -530,6 +534,9 @@
* @property {Boolean} clickToZoom * @property {Boolean} clickToZoom
* Set to false to disable zooming on click gestures. * Set to false to disable zooming on click gestures.
* *
* @property {Boolean} pinchToZoom
* Set to false to disable zooming on pinch gestures.
*
* @property {Boolean} flickEnabled * @property {Boolean} flickEnabled
* Set to false to disable the kinetic panning effect (flick) at the end of a drag gesture. * Set to false to disable the kinetic panning effect (flick) at the end of a drag gesture.
* *
@ -886,10 +893,10 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
clickDistThreshold: 5, clickDistThreshold: 5,
springStiffness: 5.0, springStiffness: 5.0,
animationTime: 1.2, animationTime: 1.2,
gestureSettingsMouse: { scrollToZoom: true, clickToZoom: true, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 }, gestureSettingsMouse: { scrollToZoom: true, clickToZoom: true, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 },
gestureSettingsTouch: { scrollToZoom: false, clickToZoom: false, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 }, gestureSettingsTouch: { scrollToZoom: false, clickToZoom: false, pinchToZoom: true, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 },
gestureSettingsPen: { scrollToZoom: false, clickToZoom: true, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 }, gestureSettingsPen: { scrollToZoom: false, clickToZoom: true, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 20, flickMomentum: 0.40 },
gestureSettingsUnknown: { scrollToZoom: false, clickToZoom: false, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 }, gestureSettingsUnknown: { scrollToZoom: false, clickToZoom: false, pinchToZoom: true, flickEnabled: true, flickMinSpeed: 20, flickMomentum: 0.40 },
zoomPerClick: 2, zoomPerClick: 2,
zoomPerScroll: 1.2, zoomPerScroll: 1.2,
zoomPerSecond: 1.0, zoomPerSecond: 1.0,

View File

@ -2383,12 +2383,17 @@ function onCanvasRelease( event ) {
} }
function onCanvasPinch( event ) { function onCanvasPinch( event ) {
var gestureSettings;
if ( !event.preventDefaultAction && this.viewport ) { if ( !event.preventDefaultAction && this.viewport ) {
var centerPt = this.viewport.pointFromPixel( event.center, true ), gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );
lastCenterPt = this.viewport.pointFromPixel( event.lastCenter, true ); if ( gestureSettings.pinchToZoom ) {
this.viewport.zoomBy( event.distance / event.lastDistance, centerPt, true ); var centerPt = this.viewport.pointFromPixel( event.center, true ),
this.viewport.panBy( lastCenterPt.minus( centerPt ), true ); lastCenterPt = this.viewport.pointFromPixel( event.lastCenter, true );
this.viewport.applyConstraints(); this.viewport.zoomBy( event.distance / event.lastDistance, centerPt, true );
this.viewport.panBy( lastCenterPt.minus( centerPt ), true );
this.viewport.applyConstraints();
}
} }
/** /**
* Raised when a pinch event occurs on the {@link OpenSeadragon.Viewer#canvas} element. * Raised when a pinch event occurs on the {@link OpenSeadragon.Viewer#canvas} element.

View File

@ -144,19 +144,31 @@
tracker.dragEndHandler = origDragEndHandler; tracker.dragEndHandler = origDragEndHandler;
}; };
var simulateEnter = function ($element, x, y) { var simulateEnter = function (x, y) {
simEvent.clientX = offset.left + x; simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y; simEvent.clientY = offset.top + y;
$canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseenter' : 'mouseover', simEvent ); $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseenter' : 'mouseover', simEvent );
}; };
var simulateLeave = function ($element, x, y) { var simulateLeave = function (x, y) {
simEvent.clientX = offset.left + x; simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y; simEvent.clientY = offset.top + y;
$canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent );
}; };
var simulateMove = function ($element, dX, dY, count) { var simulateDown = function (x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mousedown', simEvent );
};
var simulateUp = function (x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mouseup', simEvent );
};
var simulateMove = function (dX, dY, count) {
var i; var i;
for ( i = 0; i < count; i++ ) { for ( i = 0; i < count; i++ ) {
simEvent.clientX += dX; simEvent.clientX += dX;
@ -165,50 +177,6 @@
} }
}; };
var simulateTimedMove = function ($element, dX, dY, count, ms, doneCallback) {
var msInterval = Math.floor(ms / count),
dX = dX,
dY = dY,
i = count,
doneCallback = doneCallback,
moves = 0;
intervalId = window.setInterval(function () {
if (i > 0) {
moves++;
//simEvent.clientX += dX;
//simEvent.clientY += dY;
//$canvas.simulate( 'mousemove', simEvent );
}
i--;
if (i === 0) {
window.clearInterval( intervalId );
doneCallback();
}
}, msInterval );
//for ( i = 0; i < count; i++ ) {
// simEvent.clientX += dX;
// simEvent.clientY += dY;
// $canvas.simulate( 'mousemove', simEvent );
// targetTime = msWait + OpenSeadragon.now();
// while (OpenSeadragon.now() < targetTime) {}
//}
};
var simulateDown = function ($element, x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mousedown', simEvent );
};
var simulateUp = function ($element, x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mouseup', simEvent );
};
var resetForAssessment = function () { var resetForAssessment = function () {
simEvent = { simEvent = {
clientX: offset.left, clientX: offset.left,
@ -271,10 +239,10 @@
equal( quickClick, expected.quickClick, expected.description + 'clickHandler event.quick matches expected (' + expected.quickClick + ')' ); equal( quickClick, expected.quickClick, expected.description + 'clickHandler event.quick matches expected (' + expected.quickClick + ')' );
} }
if ('speed' in expected) { if ('speed' in expected) {
equal( speed, expected.speed, expected.description + 'Drag speed matches expected (' + expected.speed + ')' ); Util.assessNumericValue(expected.speed, speed, 1.0, expected.description + 'Drag speed ');
} }
if ('direction' in expected) { if ('direction' in expected) {
equal( direction, expected.direction, expected.description + 'Drag direction matches expected (' + expected.direction + ')' ); Util.assessNumericValue(expected.direction, direction, 0.2, expected.description + 'Drag direction ');
} }
}; };
@ -289,10 +257,10 @@
// enter-move-release (release in tracked element, press in unknown element) // enter-move-release (release in tracked element, press in unknown element)
// (Note we also test to see if the pointer is still being tracked by not simulating a leave event until after assessment) // (Note we also test to see if the pointer is still being tracked by not simulating a leave event until after assessment)
resetForAssessment(); resetForAssessment();
simulateEnter($canvas, 0, 0); simulateEnter(0, 0);
simulateMove($canvas, 1, 1, 10); simulateMove(1, 1, 10);
simulateMove($canvas, -1, -1, 10); simulateMove(-1, -1, 10);
simulateUp($canvas, 0, 0); simulateUp(0, 0);
assessGestureExpectations({ assessGestureExpectations({
description: 'enter-move-release (release in tracked element, press in unknown element): ', description: 'enter-move-release (release in tracked element, press in unknown element): ',
enterCount: 1, enterCount: 1,
@ -309,14 +277,14 @@
trackedPointers: 1 trackedPointers: 1
//quickClick: false //quickClick: false
}); });
simulateLeave($canvas, -1, -1); // flush tracked pointer simulateLeave(-1, -1); // flush tracked pointer
// enter-move-exit (fly-over) // enter-move-exit (fly-over)
resetForAssessment(); resetForAssessment();
simulateEnter($canvas, 0, 0); simulateEnter(0, 0);
simulateMove($canvas, 1, 1, 10); simulateMove(1, 1, 10);
simulateMove($canvas, -1, -1, 10); simulateMove(-1, -1, 10);
simulateLeave($canvas, -1, -1); simulateLeave(-1, -1);
assessGestureExpectations({ assessGestureExpectations({
description: 'enter-move-exit (fly-over): ', description: 'enter-move-exit (fly-over): ',
enterCount: 1, enterCount: 1,
@ -336,9 +304,9 @@
// move-exit (fly-over, no enter event) // move-exit (fly-over, no enter event)
resetForAssessment(); resetForAssessment();
simulateMove($canvas, 1, 1, 10); simulateMove(1, 1, 10);
simulateMove($canvas, -1, -1, 10); simulateMove(-1, -1, 10);
simulateLeave($canvas, -1, -1); simulateLeave(-1, -1);
assessGestureExpectations({ assessGestureExpectations({
description: 'move-exit (fly-over, no enter event): ', description: 'move-exit (fly-over, no enter event): ',
enterCount: 0, enterCount: 0,
@ -358,10 +326,10 @@
// enter-press-release-exit // enter-press-release-exit
resetForAssessment(); resetForAssessment();
simulateEnter($canvas, 0, 0); simulateEnter(0, 0);
simulateDown($canvas, 0, 0); simulateDown(0, 0);
simulateUp($canvas, 0, 0); simulateUp(0, 0);
simulateLeave($canvas, -1, -1); simulateLeave(-1, -1);
assessGestureExpectations({ assessGestureExpectations({
description: 'enter-press-release-exit (click): ', description: 'enter-press-release-exit (click): ',
enterCount: 1, enterCount: 1,
@ -381,12 +349,12 @@
// enter-press-move-release-move-exit (drag, release in tracked element) // enter-press-move-release-move-exit (drag, release in tracked element)
resetForAssessment(); resetForAssessment();
simulateEnter($canvas, 0, 0); simulateEnter(0, 0);
simulateDown($canvas, 0, 0); simulateDown(0, 0);
simulateMove($canvas, 1, 1, 100); simulateMove(1, 1, 100);
simulateUp($canvas, 10, 10); simulateUp(10, 10);
simulateMove($canvas, -1, -1, 100); simulateMove(-1, -1, 100);
simulateLeave($canvas, -1, -1); simulateLeave(-1, -1);
assessGestureExpectations({ assessGestureExpectations({
description: 'enter-press-move-release-move-exit (drag, release in tracked element): ', description: 'enter-press-move-release-move-exit (drag, release in tracked element): ',
enterCount: 1, enterCount: 1,
@ -406,13 +374,13 @@
// enter-press-move-exit-move-release (drag, release outside tracked element) // enter-press-move-exit-move-release (drag, release outside tracked element)
resetForAssessment(); resetForAssessment();
simulateEnter($canvas, 0, 0); simulateEnter(0, 0);
simulateDown($canvas, 0, 0); simulateDown(0, 0);
simulateMove($canvas, 1, 1, 5); simulateMove(1, 1, 5);
simulateMove($canvas, -1, -1, 5); simulateMove(-1, -1, 5);
simulateLeave($canvas, -1, -1); simulateLeave(-1, -1);
simulateMove($canvas, -1, -1, 5); simulateMove(-1, -1, 5);
simulateUp($canvas, -5, -5); simulateUp(-5, -5);
assessGestureExpectations({ assessGestureExpectations({
description: 'enter-press-move-exit-move-release (drag, release outside tracked element): ', description: 'enter-press-move-exit-move-release (drag, release outside tracked element): ',
enterCount: 1, enterCount: 1,