diff --git a/changelog.txt b/changelog.txt index f66a1eda..d1e02b23 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,6 +5,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) 1.1.1: diff --git a/src/viewport.js b/src/viewport.js index fae70dc9..7b910c49 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -322,42 +322,34 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ /** * @function - * @return {OpenSeadragon.Viewport} Chainable. - * @fires OpenSeadragon.Viewer.event:constrain + * @private + * @param {OpenSeadragon.Rect} bounds + * @param {Boolean} immediately + * @return {OpenSeadragon.Rect} constrained bounds. */ - applyConstraints: function( immediately ) { - if (true) { - return; // TEMP - } - - var actualZoom = this.getZoom(), - constrainedZoom = Math.max( - Math.min( actualZoom, this.getMaxZoom() ), - this.getMinZoom() - ), - bounds, - horizontalThreshold, + _applyBoundaryConstraints: function( bounds, immediately ) { + var horizontalThreshold, verticalThreshold, left, right, top, bottom, dx = 0, - dy = 0; + dy = 0, + newBounds = new $.Rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height + ); - if ( actualZoom != constrainedZoom ) { - this.zoomTo( constrainedZoom, this.zoomPoint, immediately ); - } + horizontalThreshold = this.visibilityRatio * newBounds.width; + verticalThreshold = this.visibilityRatio * newBounds.height; - bounds = this.getBounds(); - - horizontalThreshold = this.visibilityRatio * bounds.width; - verticalThreshold = this.visibilityRatio * bounds.height; - - left = bounds.x + bounds.width; - right = 1 - bounds.x; - top = bounds.y + bounds.height; - bottom = this.contentAspectY - bounds.y; + left = newBounds.x + newBounds.width; + right = 1 - newBounds.x; + top = newBounds.y + newBounds.height; + bottom = this.contentAspectY - newBounds.y; if ( this.wrapHorizontal ) { //do nothing @@ -386,15 +378,14 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ } if ( dx || dy || immediately ) { - bounds.x += dx; - bounds.y += dy; - if( bounds.width > 1 ){ - bounds.x = 0.5 - bounds.width/2; + newBounds.x += dx; + newBounds.y += dy; + if( newBounds.width > 1 ){ + newBounds.x = 0.5 - newBounds.width/2; } - if( bounds.height > this.contentAspectY ){ - bounds.y = this.contentAspectY/2 - bounds.height/2; + if( newBounds.height > this.contentAspectY ){ + newBounds.y = this.contentAspectY/2 - newBounds.height/2; } - this.fitBounds( bounds, immediately ); } if( this.viewer ){ @@ -413,6 +404,39 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ }); } + return newBounds; + }, + + /** + * @function + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:constrain + */ + applyConstraints: function( immediately ) { + if (true) { + return; // TEMP + } + + var actualZoom = this.getZoom(), + constrainedZoom = Math.max( + Math.min( actualZoom, this.getMaxZoom() ), + this.getMinZoom() + ), + bounds, + constrainedBounds; + + if ( actualZoom != constrainedZoom ) { + this.zoomTo( constrainedZoom, this.zoomPoint, immediately ); + } + + bounds = this.getBounds(); + + constrainedBounds = this._applyBoundaryConstraints( bounds, immediately ); + + if ( bounds.x !== constrainedBounds.x || bounds.y !== constrainedBounds.y || immediately ){ + this.fitBounds( constrainedBounds, immediately ); + } + return this; }, @@ -426,11 +450,16 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ /** * @function + * @private * @param {OpenSeadragon.Rect} bounds - * @param {Boolean} immediately + * @param {Object} options (immediately=false, constraints=false) * @return {OpenSeadragon.Viewport} Chainable. */ - fitBounds: function( bounds, immediately ) { + _fitBounds: function( bounds, options ) { + options = options || {}; + var immediately = options.immediately || false; + var constraints = options.constraints || false; + var aspect = this.getAspectRatio(), center = bounds.getCenter(), newBounds = new $.Rect( @@ -442,7 +471,9 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ oldBounds, oldZoom, newZoom, - referencePoint; + referencePoint, + newBoundsAspectRatio, + newConstrainedZoom; if ( newBounds.getAspectRatio() >= aspect ) { newBounds.height = bounds.width / aspect; @@ -452,14 +483,36 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ newBounds.x = center.x - newBounds.width / 2; } + if ( constraints ) { + newBoundsAspectRatio = newBounds.getAspectRatio(); + } + this.panTo( this.getCenter( true ), true ); this.zoomTo( this.getZoom( true ), null, true ); oldBounds = this.getBounds(); oldZoom = this.getZoom(); newZoom = 1.0 / newBounds.width; + + if ( constraints ) { + newConstrainedZoom = Math.max( + Math.min(newZoom, this.getMaxZoom() ), + this.getMinZoom() + ); + + if (newZoom !== newConstrainedZoom) { + newZoom = newConstrainedZoom; + newBounds.width = 1.0 / newZoom; + newBounds.x = center.x - newBounds.width / 2; + newBounds.height = newBounds.width / newBoundsAspectRatio; + newBounds.y = center.y - newBounds.height / 2; + } + + newBounds = this._applyBoundaryConstraints( newBounds, immediately ); + } + if ( newZoom == oldZoom || newBounds.width == oldBounds.width ) { - return this.panTo( center, immediately ); + return this.panTo( constraints ? newBounds.getCenter() : center, immediately ); } referencePoint = oldBounds.getTopLeft().times( @@ -476,6 +529,31 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ return this.zoomTo( newZoom, referencePoint, immediately ); }, + /** + * @function + * @param {OpenSeadragon.Rect} bounds + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitBounds: function( bounds, immediately ) { + return this._fitBounds( bounds, { + immediately: immediately, + constraints: false + } ); + }, + + /** + * @function + * @param {OpenSeadragon.Rect} bounds + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitBoundsWithConstraints: function( bounds, immediately ) { + return this._fitBounds( bounds, { + immediately: immediately, + constraints: true + } ); + }, /** * @function diff --git a/test/demo/fitboundswithconstraints.html b/test/demo/fitboundswithconstraints.html new file mode 100644 index 00000000..c0317c98 --- /dev/null +++ b/test/demo/fitboundswithconstraints.html @@ -0,0 +1,113 @@ + + +
+