Merge pull request #423 from henri-astre-msft/fitBoundsWithConstraints

add fitBoundsWithConstraints() to the viewport.
This commit is contained in:
iangilman 2014-07-24 09:28:53 -07:00
commit 1e4288f770
2 changed files with 238 additions and 47 deletions

View File

@ -322,38 +322,34 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/** /**
* @function * @function
* @return {OpenSeadragon.Viewport} Chainable. * @private
* @fires OpenSeadragon.Viewer.event:constrain * @param {OpenSeadragon.Rect} bounds
* @param {Boolean} immediately
* @return {OpenSeadragon.Rect} constrained bounds.
*/ */
applyConstraints: function( immediately ) { _applyBoundaryConstraints: function( bounds, immediately ) {
var actualZoom = this.getZoom(), var horizontalThreshold,
constrainedZoom = Math.max(
Math.min( actualZoom, this.getMaxZoom() ),
this.getMinZoom()
),
bounds,
horizontalThreshold,
verticalThreshold, verticalThreshold,
left, left,
right, right,
top, top,
bottom, bottom,
dx = 0, dx = 0,
dy = 0; dy = 0,
newBounds = new $.Rect(
bounds.x,
bounds.y,
bounds.width,
bounds.height
);
if ( actualZoom != constrainedZoom ) { horizontalThreshold = this.visibilityRatio * newBounds.width;
this.zoomTo( constrainedZoom, this.zoomPoint, immediately ); verticalThreshold = this.visibilityRatio * newBounds.height;
}
bounds = this.getBounds(); left = newBounds.x + newBounds.width;
right = 1 - newBounds.x;
horizontalThreshold = this.visibilityRatio * bounds.width; top = newBounds.y + newBounds.height;
verticalThreshold = this.visibilityRatio * bounds.height; bottom = this.contentAspectY - newBounds.y;
left = bounds.x + bounds.width;
right = 1 - bounds.x;
top = bounds.y + bounds.height;
bottom = this.contentAspectY - bounds.y;
if ( this.wrapHorizontal ) { if ( this.wrapHorizontal ) {
//do nothing //do nothing
@ -382,15 +378,14 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
} }
if ( dx || dy || immediately ) { if ( dx || dy || immediately ) {
bounds.x += dx; newBounds.x += dx;
bounds.y += dy; newBounds.y += dy;
if( bounds.width > 1 ){ if( newBounds.width > 1 ){
bounds.x = 0.5 - bounds.width/2; newBounds.x = 0.5 - newBounds.width/2;
} }
if( bounds.height > this.contentAspectY ){ if( newBounds.height > this.contentAspectY ){
bounds.y = this.contentAspectY/2 - bounds.height/2; newBounds.y = this.contentAspectY/2 - newBounds.height/2;
} }
this.fitBounds( bounds, immediately );
} }
if( this.viewer ){ if( this.viewer ){
@ -409,6 +404,35 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
}); });
} }
return newBounds;
},
/**
* @function
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:constrain
*/
applyConstraints: function( immediately ) {
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; return this;
}, },
@ -422,11 +446,16 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/** /**
* @function * @function
* @private
* @param {OpenSeadragon.Rect} bounds * @param {OpenSeadragon.Rect} bounds
* @param {Boolean} immediately * @param {Object} options (immediately=false, constraints=false)
* @return {OpenSeadragon.Viewport} Chainable. * @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(), var aspect = this.getAspectRatio(),
center = bounds.getCenter(), center = bounds.getCenter(),
newBounds = new $.Rect( newBounds = new $.Rect(
@ -438,7 +467,9 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
oldBounds, oldBounds,
oldZoom, oldZoom,
newZoom, newZoom,
referencePoint; referencePoint,
newBoundsAspectRatio,
newConstrainedZoom;
if ( newBounds.getAspectRatio() >= aspect ) { if ( newBounds.getAspectRatio() >= aspect ) {
newBounds.height = bounds.width / aspect; newBounds.height = bounds.width / aspect;
@ -448,14 +479,36 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
newBounds.x = center.x - newBounds.width / 2; newBounds.x = center.x - newBounds.width / 2;
} }
if ( constraints ) {
newBoundsAspectRatio = newBounds.getAspectRatio();
}
this.panTo( this.getCenter( true ), true ); this.panTo( this.getCenter( true ), true );
this.zoomTo( this.getZoom( true ), null, true ); this.zoomTo( this.getZoom( true ), null, true );
oldBounds = this.getBounds(); oldBounds = this.getBounds();
oldZoom = this.getZoom(); oldZoom = this.getZoom();
newZoom = 1.0 / newBounds.width; 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 ) { if ( newZoom == oldZoom || newBounds.width == oldBounds.width ) {
return this.panTo( center, immediately ); return this.panTo( constraints ? newBounds.getCenter() : center, immediately );
} }
referencePoint = oldBounds.getTopLeft().times( referencePoint = oldBounds.getTopLeft().times(
@ -472,6 +525,31 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
return this.zoomTo( newZoom, referencePoint, immediately ); 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 * @function

View File

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html>
<head>
<title>OpenSeadragon fitBoundsWithConstraints() Demo</title>
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
<style type="text/css">
.openseadragon1 {
width: 800px;
height: 600px;
}
#highlights li {
cursor: pointer;
}
</style>
</head>
<body>
<div>
Simple demo page to show 'viewport.fitBounds().applyConstraints()' issue.
</div>
<div id="contentDiv" class="openseadragon1"></div>
<div id="highlights"></div>
<select onchange="changeMethod(this.value);">
<option value=0>viewport.fitBoundsWithConstraints(bounds);</option>
<option value=1>viewport.fitBounds(bounds);</option>
<option value=2>viewport.fitBounds(bounds).applyConstraints();</option>
</select>
<input type="button" value="Go home" onclick="goHome()"/>
<script type="text/javascript">
var _viewer;
var _fittingMethod = 0;
var _highlights = [
{"queryPoint":[0.13789887359998443,0.43710575899579285], "radius":0.004479581945070337,"text":"Pipe"},
{"queryPoint":[0.5923298766583593,0.6461653354541856], "radius":0.013175241014912752,"text":"Fuel here"},
{"queryPoint":[0.43920338711232304,0.7483181389302148], "radius":0.09222668710438928, "text":"Wheel"},
{"queryPoint":[0.07341677959486298,0.9028719921872319], "radius":0.08996845561083797, "text":"Nothing special"}
];
var generateUniqueHash = (function() {
var counter = 0;
return function() {
return "openseadragon_" + (counter++);
};
})();
var _viewer = OpenSeadragon({
element: document.getElementById("contentDiv"),
showNavigationControl: false,
prefixUrl: "../../build/openseadragon/images/",
hash: generateUniqueHash(), //this is only needed if you want to instantiate more than one viewer at a time.
tileSources: {
Image: {
xmlns: "http://schemas.microsoft.com/deepzoom/2008",
Url: 'http://cdn.photosynth.net/ps2/19d5cf2b-77ed-439f-ac21-d3046320384c/packet/undistorted/img0043/',
Format: "jpg",
Overlap: 1,
TileSize: 510,
Size: {
Width: 4592,
Height: 3448
}
}
}
});
_viewer.addHandler("open", function() {
var str = "<ul>";
for (var i=0; i<_highlights.length; ++i) {
var highlight = _highlights[i];
str += "<li onclick='gotoHighlight("+i+")'>"+highlight.text+"</li>";
}
str += "</ul>";
document.getElementById("highlights").innerHTML = str;
});
function gotoHighlight(index) {
var highlight = _highlights[index];
var viewport = _viewer.viewport;
var contentSize = viewport.contentSize;
var scaling = 1.0 / viewport.viewportToImageZoom(viewport.getZoom());
var radius = highlight.radius*Math.min(contentSize.x, contentSize.y);/*annotation.accurateRadius*scaling;*/
var center = new OpenSeadragon.Point(contentSize.x*highlight.queryPoint[0], contentSize.y*highlight.queryPoint[1]);
var bounds = viewport.imageToViewportRectangle(new OpenSeadragon.Rect(center.x-radius, center.y-radius, radius*2, radius*2));
if (_fittingMethod === 0) {
viewport.fitBoundsWithConstraints(bounds, false);
}
else if (_fittingMethod === 1) {
viewport.fitBounds(bounds, false);
}
else if (_fittingMethod === 2) {
viewport.fitBounds(bounds, false).applyConstraints();
}
}
function changeMethod(value) {
_fittingMethod = parseInt(value, 10);
}
function goHome() {
_viewer.viewport.goHome();
}
</script>
</body>
</html>