diff --git a/changelog.txt b/changelog.txt index 8c4c773c..9e3cff47 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,7 @@ OPENSEADRAGON CHANGELOG * Fix for IIPServer-style urls when using DZI (#413) * Fix memory leak while destroying the viewer (#421) * Added fitBoundsWithConstraints() to the viewport (#423) +* Fixed MouseTracker cross-browser issues with tracking pointers over and out of the tracked element (pull request #448, fix for #152, #404, #420, and #427) 1.1.1: diff --git a/src/button.js b/src/button.js index a83d40a6..104955e0 100644 --- a/src/button.js +++ b/src/button.js @@ -137,6 +137,7 @@ $.Button = function( options ) { this.tooltip; this.element.style.position = "relative"; + $.setElementTouchActionNone( this.element ); this.imgGroup.style.position = this.imgHover.style.position = diff --git a/src/buttongroup.js b/src/buttongroup.js index a05e9084..2837805a 100644 --- a/src/buttongroup.js +++ b/src/buttongroup.js @@ -80,6 +80,8 @@ $.ButtonGroup = function( options ) { } } + $.setElementTouchActionNone( this.element ); + /** * Tracks mouse/touch/key events accross the group of buttons. * @member {OpenSeadragon.MouseTracker} tracker diff --git a/src/iiiftilesource.js b/src/iiiftilesource.js index a18a9a2b..8c1da291 100644 --- a/src/iiiftilesource.js +++ b/src/iiiftilesource.js @@ -98,9 +98,9 @@ $.IIIFTileSource = function( options ){ } if ( !options.maxLevel ) { - if ( !this.scale_factors ) { - options.maxLevel = Number( Math.ceil( Math.log( Math.max( this.width, this.height ), 2 ) ) ); - } else { + if ( !this.scale_factors ) { + options.maxLevel = Number( Math.ceil( Math.log( Math.max( this.width, this.height ), 2 ) ) ); + } else { options.maxLevel = Math.floor( Math.pow( Math.max.apply(null, this.scale_factors), 0.5) ); } } @@ -128,7 +128,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea return true; // Version 1.0 - } else if ( data.profile && + } else if ( data.profile && data.profile.indexOf("http://library.stanford.edu/iiif/image-api/compliance.html") === 0) { return true; } else if ( data.identifier && data.width && data.height ) { @@ -166,7 +166,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea configure: function( data, url ){ // Try to deduce our version and fake it upwards if needed if ( !$.isPlainObject(data) ) { - var options = configureFromXml10( data ); + var options = configureFromXml10( data ); options['@context'] = "http://iiif.io/api/image/1.0/context.json"; options['@id'] = url.replace('/info.xml', ''); return options; diff --git a/src/mousetracker.js b/src/mousetracker.js index fd4a1877..7a4df604 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -122,28 +122,28 @@ * @member {Number} clickTimeThreshold * @memberof OpenSeadragon.MouseTracker# */ - this.clickTimeThreshold = options.clickTimeThreshold; + this.clickTimeThreshold = options.clickTimeThreshold || $.DEFAULT_SETTINGS.clickTimeThreshold; /** * 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.clickDistThreshold = options.clickDistThreshold || $.DEFAULT_SETTINGS.clickDistThreshold; /** * 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; + this.dblClickTimeThreshold = options.dblClickTimeThreshold || $.DEFAULT_SETTINGS.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.dblClickDistThreshold = options.dblClickDistThreshold || $.DEFAULT_SETTINGS.dblClickDistThreshold; this.userData = options.userData || null; this.stopDelay = options.stopDelay || 50; @@ -187,8 +187,6 @@ mouseover: function ( event ) { onMouseOver( _this, event ); }, mouseout: function ( event ) { onMouseOut( _this, event ); }, - mouseenter: function ( event ) { onMouseEnter( _this, event ); }, - mouseleave: function ( event ) { onMouseLeave( _this, event ); }, mousedown: function ( event ) { onMouseDown( _this, event ); }, mouseup: function ( event ) { onMouseUp( _this, event ); }, mouseupcaptured: function ( event ) { onMouseUpCaptured( _this, event ); }, @@ -205,10 +203,10 @@ gesturestart: function ( event ) { onGestureStart( _this, event ); }, gesturechange: function ( event ) { onGestureChange( _this, event ); }, - pointerenter: function ( event ) { onPointerEnter( _this, event ); }, - MSPointerEnter: function ( event ) { onPointerEnter( _this, event ); }, - pointerleave: function ( event ) { onPointerLeave( _this, event ); }, - MSPointerLeave: function ( event ) { onPointerLeave( _this, event ); }, + pointerover: function ( event ) { onPointerOver( _this, event ); }, + MSPointerOver: function ( event ) { onPointerOver( _this, event ); }, + pointerout: function ( event ) { onPointerOut( _this, event ); }, + MSPointerOut: function ( event ) { onPointerOut( _this, event ); }, pointerdown: function ( event ) { onPointerDown( _this, event ); }, MSPointerDown: function ( event ) { onPointerDown( _this, event ); }, pointerup: function ( event ) { onPointerUp( _this, event ); }, @@ -217,6 +215,8 @@ MSPointerMove: function ( event ) { onPointerMove( _this, event ); }, pointercancel: function ( event ) { onPointerCancel( _this, event ); }, MSPointerCancel: function ( event ) { onPointerCancel( _this, event ); }, + pointerupcaptured: function ( event ) { onPointerUpCaptured( _this, event ); }, + pointermovecaptured: function ( event ) { onPointerMoveCaptured( _this, event ); }, tracking: false, @@ -226,9 +226,12 @@ // of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. activePointersLists: [], - // Legacy mouse event tracking + // Legacy mouse capture tracking capturing: false, + // Pointer event model capture tracking + pointerCaptureCount: 0, + // Tracking for double-click gesture lastClickPos: null, dblClickTimeOut: null, @@ -816,29 +819,28 @@ if ( window.PointerEvent ) { // IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents) - $.MouseTracker.subscribeEvents.push( "pointerenter", "pointerleave", "pointerdown", "pointerup", "pointermove", "pointercancel" ); + $.MouseTracker.subscribeEvents.push( "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" ); $.MouseTracker.unprefixedPointerEvents = true; if( navigator.maxTouchPoints ) { $.MouseTracker.maxTouchPoints = navigator.maxTouchPoints; } else { $.MouseTracker.maxTouchPoints = 0; } - $.MouseTracker.haveTouchEnter = true; - $.MouseTracker.haveMouseEnter = true; + $.MouseTracker.haveTouchEnter = false; + $.MouseTracker.haveMouseEnter = false; } else if ( window.MSPointerEvent ) { // IE10 - $.MouseTracker.subscribeEvents.push( "MSPointerEnter", "MSPointerLeave", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" ); + $.MouseTracker.subscribeEvents.push( "MSPointerOver", "MSPointerOut", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" ); $.MouseTracker.unprefixedPointerEvents = false; if( navigator.msMaxTouchPoints ) { $.MouseTracker.maxTouchPoints = navigator.msMaxTouchPoints; } else { $.MouseTracker.maxTouchPoints = 0; } - $.MouseTracker.haveTouchEnter = true; - $.MouseTracker.haveMouseEnter = true; + $.MouseTracker.haveTouchEnter = false; + $.MouseTracker.haveMouseEnter = false; } else { // Legacy W3C mouse events - // TODO: Favor mouseenter/mouseleave over mouseover/mouseout when Webkit browser support is better $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" ); $.MouseTracker.haveMouseEnter = false; if ( 'ontouchstart' in window ) { @@ -1072,73 +1074,66 @@ ); } - releaseMouse( tracker ); delegate.tracking = false; } } /** - * Begin capturing mouse events to the tracked element (legacy mouse events only). + * Begin capturing pointer events to the tracked element. * @private * @inner */ - function captureMouse( tracker ) { + function capturePointer( tracker, isLegacyMouse ) { var delegate = THIS[ tracker.hash ]; - if ( !delegate.capturing ) { - if ( $.MouseTracker.supportsMouseCapture ) { - // IE<10, Firefox, other browsers with setCapture()/releaseCapture() - tracker.element.setCapture( true ); - } else { - // For browsers without setCapture()/releaseCapture(), we emulate mouse capture by hanging listeners on the window object. - // (Note we listen on the capture phase so the captured handlers will get called first) - $.addEvent( - window, - "mouseup", - delegate.mouseupcaptured, - true - ); - $.addEvent( - window, - "mousemove", - delegate.mousemovecaptured, - true - ); - } - delegate.capturing = true; + delegate.pointerCaptureCount++; + //$.console.log('pointerCaptureCount++ ', delegate.pointerCaptureCount); + + if ( delegate.pointerCaptureCount === 1 ) { + // We emulate mouse capture by hanging listeners on the window object. + // (Note we listen on the capture phase so the captured handlers will get called first) + $.addEvent( + window, + isLegacyMouse ? 'mouseup' : ($.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp'), + isLegacyMouse ? delegate.mouseupcaptured : delegate.pointerupcaptured, + true + ); + $.addEvent( + window, + isLegacyMouse ? 'mousemove' : ($.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove'), + isLegacyMouse ? delegate.mousemovecaptured : delegate.pointermovecaptured, + true + ); } } /** - * Stop capturing mouse events to the tracked element (legacy mouse events only). + * Stop capturing pointer events to the tracked element. * @private * @inner */ - function releaseMouse( tracker ) { + function releasePointer( tracker, isLegacyMouse ) { var delegate = THIS[ tracker.hash ]; - if ( delegate.capturing ) { - if ( $.MouseTracker.supportsMouseCapture ) { - // IE<10, Firefox, other browsers with setCapture()/releaseCapture() - tracker.element.releaseCapture(); - } else { - // For browsers without setCapture()/releaseCapture(), we emulate mouse capture by hanging listeners on the window object. - // (Note we listen on the capture phase so the captured handlers will get called first) - $.removeEvent( - window, - "mousemove", - delegate.mousemovecaptured, - true - ); - $.removeEvent( - window, - "mouseup", - delegate.mouseupcaptured, - true - ); - } - delegate.capturing = false; + delegate.pointerCaptureCount--; + //$.console.log('pointerCaptureCount-- ', delegate.pointerCaptureCount); + + if ( delegate.pointerCaptureCount === 0 ) { + // We emulate mouse capture by hanging listeners on the window object. + // (Note we listen on the capture phase so the captured handlers will get called first) + $.removeEvent( + window, + isLegacyMouse ? 'mousemove' : ($.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove'), + isLegacyMouse ? delegate.mousemovecaptured : delegate.pointermovecaptured, + true + ); + $.removeEvent( + window, + isLegacyMouse ? 'mouseup' : ($.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp'), + isLegacyMouse ? delegate.mouseupcaptured : delegate.pointerupcaptured, + true + ); } } @@ -1421,7 +1416,7 @@ event = $.getEvent( event ); - if ( this === event.relatedTarget || isParentChild( this, event.relatedTarget ) ) { + if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { return; } @@ -1446,7 +1441,7 @@ event = $.getEvent( event ); - if ( this === event.relatedTarget || isParentChild( this, event.relatedTarget ) ) { + if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { return; } @@ -1462,48 +1457,6 @@ } - /** - * @private - * @inner - */ - function onMouseEnter( tracker, event ) { - var gPoint; - - event = $.getEvent( event ); - - gPoint = { - id: $.MouseTracker.mousePointerId, - type: 'mouse', - isPrimary: true, - currentPos: getMouseAbsolute( event ), - currentTime: $.now() - }; - - updatePointersEnter( tracker, event, [ gPoint ] ); - } - - - /** - * @private - * @inner - */ - function onMouseLeave( tracker, event ) { - var gPoint; - - event = $.getEvent( event ); - - gPoint = { - id: $.MouseTracker.mousePointerId, - type: 'mouse', - isPrimary: true, - currentPos: getMouseAbsolute( event ), - currentTime: $.now() - }; - - updatePointersExit( tracker, event, [ gPoint ] ); - } - - /** * @private * @inner @@ -1523,7 +1476,7 @@ if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { $.stopEvent( event ); - captureMouse( tracker ); + capturePointer( tracker, true ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) { @@ -1542,8 +1495,6 @@ /** * This handler is attached to the window object (on the capture phase) to emulate mouse capture. - * Only triggered in W3C browsers that don't have setCapture/releaseCapture - * methods or don't support the new pointer events model. * onMouseUp is still attached to the tracked element, so stop propagation to avoid processing twice. * * @private @@ -1573,7 +1524,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - releaseMouse( tracker ); + releasePointer( tracker, true ); } } @@ -1589,8 +1540,6 @@ /** * This handler is attached to the window object (on the capture phase) to emulate mouse capture. - * Only triggered in W3C browsers that don't have setCapture/releaseCapture - * methods or don't support the new pointer events model. * onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice. * * @private @@ -1810,9 +1759,13 @@ * @private * @inner */ - function onPointerEnter( tracker, event ) { + function onPointerOver( tracker, event ) { var gPoint; + if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + gPoint = { id: event.pointerId, type: getPointerType( event ), @@ -1829,9 +1782,13 @@ * @private * @inner */ - function onPointerLeave( tracker, event ) { + function onPointerOut( tracker, event ) { var gPoint; + if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + gPoint = { id: event.pointerId, type: getPointerType( event ), @@ -1860,11 +1817,7 @@ }; if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { - if ( $.MouseTracker.unprefixedPointerEvents ) { - event.currentTarget.setPointerCapture( event.pointerId ); - } else { - event.currentTarget.msSetPointerCapture( event.pointerId ); - } + capturePointer( tracker, false ); $.stopEvent( event ); } @@ -1879,6 +1832,31 @@ * @inner */ function onPointerUp( tracker, event ) { + handlePointerUp( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onPointerUp is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onPointerUpCaptured( tracker, event ) { + var pointsList = tracker.getActivePointersListByType( getPointerType( event ) ); + if ( pointsList.getById( event.pointerId ) ) { + handlePointerUp( tracker, event ); + } + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handlePointerUp( tracker, event ) { var gPoint; gPoint = { @@ -1890,11 +1868,8 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - if ( $.MouseTracker.unprefixedPointerEvents ) { - event.currentTarget.releasePointerCapture( event.pointerId ); - } else { - event.currentTarget.msReleasePointerCapture( event.pointerId ); - } + releasePointer( tracker, false ); + //$.stopEvent( event ); } } @@ -1904,6 +1879,31 @@ * @inner */ function onPointerMove( tracker, event ) { + handlePointerMove( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onPointerMove is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onPointerMoveCaptured( tracker, event ) { + var pointsList = tracker.getActivePointersListByType( getPointerType( event ) ); + if ( pointsList.getById( event.pointerId ) ) { + handlePointerMove( tracker, event ); + } + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handlePointerMove( tracker, event ) { // Pointer changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height) var gPoint; @@ -2216,6 +2216,7 @@ } pointsList.contacts++; + //$.console.log('contacts++ ', pointsList.contacts); if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, curGPoint ); @@ -2342,6 +2343,7 @@ // Pointer was activated in our element but could have been removed in any element since events are captured to our element pointsList.contacts--; + //$.console.log('contacts-- ', pointsList.contacts); if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, updateGPoint ); diff --git a/src/navigator.js b/src/navigator.js index e04c6a60..24d35a3d 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -112,6 +112,8 @@ $.Navigator = function( options ){ options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio; + $.setElementTouchActionNone( this.element ); + this.borderWidth = 2; //At some browser magnification levels the display regions lines up correctly, but at some there appears to //be a one pixel gap. @@ -315,17 +317,9 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /* * @function */ function onCanvasClick( event ) { - var newBounds, - viewerPosition, - dimensions; - if (! this.drag) { - if ( this.viewer.viewport ) { - this.viewer.viewport.panTo( this.viewport.pointFromPixel( event.position ) ); - this.viewer.viewport.applyConstraints(); - } - } - else { - this.drag = false; + if ( event.quick && this.viewer.viewport ) { + this.viewer.viewport.panTo( this.viewport.pointFromPixel( event.position ) ); + this.viewer.viewport.applyConstraints(); } } @@ -336,7 +330,6 @@ function onCanvasClick( event ) { */ function onCanvasDrag( event ) { if ( this.viewer.viewport ) { - this.drag = true; if( !this.panHorizontal ){ event.delta.x = 0; } diff --git a/src/openseadragon.js b/src/openseadragon.js index 0c167934..5bccc84b 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -1585,6 +1585,21 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ }, + /** + * Sets the specified element's touch-action style attribute to 'none'. + * @function + * @param {Element|String} element + */ + setElementTouchActionNone: function( element ) { + element = $.getElement( element ); + if ( typeof element.style.touchAction !== 'undefined' ) { + element.style.touchAction = 'none'; + } else if ( typeof element.style.msTouchAction !== 'undefined' ) { + element.style.msTouchAction = 'none'; + } + }, + + /** * Add the specified CSS class to the element if not present. * @function @@ -2159,7 +2174,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ ) ); } else { - regex = new RegExp( "Trident/.*rv:([0-9]{1,}[.0-9]{0,}) "); + regex = new RegExp( "Trident/.*rv:([0-9]{1,}[.0-9]{0,})"); if ( regex.exec( ua ) !== null ) { $.Browser.vendor = $.BROWSERS.IE; $.Browser.version = parseFloat( RegExp.$1 ); diff --git a/src/referencestrip.js b/src/referencestrip.js index b7192517..f68744b2 100644 --- a/src/referencestrip.js +++ b/src/referencestrip.js @@ -114,6 +114,8 @@ $.ReferenceStrip = function ( options ) { style.background = '#000'; style.position = 'relative'; + $.setElementTouchActionNone( this.element ); + $.setElementOpacity( this.element, 0.8 ); this.viewer = viewer; @@ -189,6 +191,7 @@ $.ReferenceStrip = function ( options ) { element.style.cssFloat = 'left'; //Firefox element.style.styleFloat = 'left'; //IE element.style.padding = '2px'; + $.setElementTouchActionNone( element ); element.innerTracker = new $.MouseTracker( { element: element, diff --git a/src/tilesource.js b/src/tilesource.js index 9fc1f7d8..deecc742 100644 --- a/src/tilesource.js +++ b/src/tilesource.js @@ -263,7 +263,7 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{ tiles; for( i = this.minLevel; i < this.maxLevel; i++ ){ tiles = this.getNumTiles( i ); - tilesPerSide = Math.floor( Math.max( rect.x, rect.y ) / this.getTileSize(i) ); + tilesPerSide = Math.floor( Math.max( rect.x, rect.y ) / this.getTileSize(i) ); if( Math.max( tiles.x, tiles.y ) + 1 >= tilesPerSide ){ break; } diff --git a/src/viewer.js b/src/viewer.js index 7ba1e7c0..fca5d6de 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -275,13 +275,8 @@ $.Viewer = function( options ) { style.position = "absolute"; style.top = "0px"; style.left = "0px"; - // Disable browser default touch handling - if (style["touch-action"] !== undefined) { - style["touch-action"] = "none"; - } else if (style["-ms-touch-action"] !== undefined) { - style["-ms-touch-action"] = "none"; - } }(this.canvas.style)); + $.setElementTouchActionNone( this.canvas ); //the container is created through applying the ControlDock constructor above this.container.className = "openseadragon-container"; @@ -2393,8 +2388,8 @@ function onCanvasDragEnd( event ) { target.y = center.y; } this.viewport.panTo( target, false ); - this.viewport.applyConstraints(); } + this.viewport.applyConstraints(); } /** * Raised when a mouse or touch drag operation ends on the {@link OpenSeadragon.Viewer#canvas} element. @@ -2422,15 +2417,6 @@ function onCanvasDragEnd( event ) { } function onCanvasRelease( event ) { - 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. * diff --git a/src/viewport.js b/src/viewport.js index 7bceb9d8..38ecfa27 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -326,7 +326,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ * @param {OpenSeadragon.Rect} bounds * @param {Boolean} immediately * @return {OpenSeadragon.Rect} constrained bounds. - */ + */ _applyBoundaryConstraints: function( bounds, immediately ) { var horizontalThreshold, verticalThreshold, @@ -402,9 +402,9 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ this.viewer.raiseEvent( 'constrain', { immediately: immediately }); - } + } - return newBounds; + return newBounds; }, /** @@ -523,7 +523,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ ); return this.zoomTo( newZoom, referencePoint, immediately ); - }, + }, /** * @function