Merge pull request #934 from avandecreme/fitBounds

Take rotation into account in viewport getBounds and fitBounds methods
This commit is contained in:
Ian Gilman 2016-05-13 11:21:40 -07:00
commit c5fc9a6922
6 changed files with 355 additions and 195 deletions

View File

@ -307,7 +307,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
} }
if (viewport && this.viewport) { if (viewport && this.viewport) {
bounds = viewport.getBounds( true ); bounds = viewport.getBoundsNoRotate(true);
topleft = this.viewport.pixelFromPointNoRotate(bounds.getTopLeft(), false); topleft = this.viewport.pixelFromPointNoRotate(bounds.getTopLeft(), false);
bottomright = this.viewport.pixelFromPointNoRotate(bounds.getBottomRight(), false) bottomright = this.viewport.pixelFromPointNoRotate(bounds.getBottomRight(), false)
.minus( this.totalBorderWidths ); .minus( this.totalBorderWidths );

View File

@ -795,6 +795,7 @@ function updateViewport( tiledImage ) {
levelOpacity, levelOpacity,
levelVisibility; levelVisibility;
viewportBounds = viewportBounds.getBoundingBox();
viewportBounds.x -= tiledImage._xSpring.current.value; viewportBounds.x -= tiledImage._xSpring.current.value;
viewportBounds.y -= tiledImage._ySpring.current.value; viewportBounds.y -= tiledImage._ySpring.current.value;
@ -804,18 +805,6 @@ function updateViewport( tiledImage ) {
tile.beingDrawn = false; tile.beingDrawn = false;
} }
//Change bounds for rotation
if (degrees === 90 || degrees === 270) {
viewportBounds = viewportBounds.rotate( degrees );
} else if (degrees !== 0 && degrees !== 180) {
// This is just an approximation.
var orthBounds = viewportBounds.rotate(90);
viewportBounds.x -= orthBounds.width / 2;
viewportBounds.y -= orthBounds.height / 2;
viewportBounds.width += orthBounds.width;
viewportBounds.height += orthBounds.height;
}
var viewportTL = viewportBounds.getTopLeft(); var viewportTL = viewportBounds.getTopLeft();
var viewportBR = viewportBounds.getBottomRight(); var viewportBR = viewportBounds.getBottomRight();

View File

@ -2975,30 +2975,23 @@ function updateOnce( viewer ) {
return; return;
} }
var containerSize;
if (viewer.autoResize) { if (viewer.autoResize) {
containerSize = _getSafeElemSize( viewer.container ); var containerSize = _getSafeElemSize(viewer.container);
if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) {
if ( viewer.preserveImageSizeOnResize ) {
var prevContainerSize = THIS[viewer.hash].prevContainerSize; var prevContainerSize = THIS[viewer.hash].prevContainerSize;
var bounds = viewer.viewport.getBounds(true); if (!containerSize.equals(prevContainerSize)) {
var deltaX = (containerSize.x - prevContainerSize.x); var viewport = viewer.viewport;
var deltaY = (containerSize.y - prevContainerSize.y); if (viewer.preserveImageSizeOnResize) {
var viewportDiff = viewer.viewport.deltaPointsFromPixels(new OpenSeadragon.Point(deltaX, deltaY), true); var resizeRatio = prevContainerSize.x / containerSize.x;
viewer.viewport.resize(new OpenSeadragon.Point(containerSize.x, containerSize.y), false); var zoom = viewport.getZoom() * resizeRatio;
var center = viewport.getCenter();
// Keep the center of the image in the center and just adjust the amount of image shown viewport.resize(containerSize, false);
bounds.width += viewportDiff.x; viewport.zoomTo(zoom, null, true);
bounds.height += viewportDiff.y; viewport.panTo(center, true);
bounds.x -= (viewportDiff.x / 2); } else {
bounds.y -= (viewportDiff.y / 2);
viewer.viewport.fitBoundsWithConstraints(bounds, true);
}
else {
// maintain image position // maintain image position
var oldBounds = viewer.viewport.getBounds(); var oldBounds = viewport.getBounds();
var oldCenter = viewer.viewport.getCenter(); viewport.resize(containerSize, true);
resizeViewportAndRecenter(viewer, containerSize, oldBounds, oldCenter); viewport.fitBoundsWithConstraints(oldBounds, true);
} }
THIS[viewer.hash].prevContainerSize = containerSize; THIS[viewer.hash].prevContainerSize = containerSize;
THIS[viewer.hash].forceRedraw = true; THIS[viewer.hash].forceRedraw = true;
@ -3086,27 +3079,6 @@ function updateOnce( viewer ) {
//viewer.profiler.endUpdate(); //viewer.profiler.endUpdate();
} }
// This function resizes the viewport and recenters the image
// as it was before resizing.
// TODO: better adjust width and height. The new width and height
// should depend on the image dimensions and on the dimensions
// of the viewport before and after switching mode.
function resizeViewportAndRecenter( viewer, containerSize, oldBounds, oldCenter ) {
var viewport = viewer.viewport;
viewport.resize( containerSize, true );
var newBounds = new $.Rect(
oldCenter.x - ( oldBounds.width / 2.0 ),
oldCenter.y - ( oldBounds.height / 2.0 ),
oldBounds.width,
oldBounds.height
);
// let the viewport decide if the bounds are too big or too small
viewport.fitBoundsWithConstraints( newBounds, true );
}
function drawWorld( viewer ) { function drawWorld( viewer ) {
viewer.imageLoader.clear(); viewer.imageLoader.clear();
viewer.drawer.clear(); viewer.drawer.clear();

View File

@ -237,6 +237,17 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates. * @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates.
*/ */
getHomeBounds: function() { getHomeBounds: function() {
return this.getHomeBoundsNoRotate().rotate(-this.getRotation());
},
/**
* Returns the home bounds in viewport coordinates.
* This method ignores the viewport rotation. Use
* {@link OpenSeadragon.Viewport#getHomeBounds} to take it into account.
* @function
* @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates.
*/
getHomeBoundsNoRotate: function() {
var center = this._contentBounds.getCenter(); var center = this._contentBounds.getCenter();
var width = 1.0 / this.getHomeZoom(); var width = 1.0 / this.getHomeZoom();
var height = width / this.getAspectRatio(); var height = width / this.getAspectRatio();
@ -353,9 +364,21 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates. * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.
*/ */
getBounds: function(current) { getBounds: function(current) {
var center = this.getCenter( current ), return this.getBoundsNoRotate(current).rotate(-this.getRotation());
width = 1.0 / this.getZoom( current ), },
height = width / this.getAspectRatio();
/**
* Returns the bounds of the visible area in viewport coordinates.
* This method ignores the viewport rotation. Use
* {@link OpenSeadragon.Viewport#getBounds} to take it into account.
* @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
* @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.
*/
getBoundsNoRotate: function(current) {
var center = this.getCenter(current);
var width = 1.0 / this.getZoom(current);
var height = width / this.getAspectRatio();
return new $.Rect( return new $.Rect(
center.x - (width / 2.0), center.x - (width / 2.0),
@ -372,7 +395,18 @@ $.Viewport.prototype = {
* including the space taken by margins, in viewport coordinates. * including the space taken by margins, in viewport coordinates.
*/ */
getBoundsWithMargins: function(current) { getBoundsWithMargins: function(current) {
var bounds = this.getBounds(current); return this.getBoundsNoRotateWithMargins(current).rotate(
-this.getRotation(), this.getCenter(current));
},
/**
* @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
* @returns {OpenSeadragon.Rect} The location you are zoomed/panned to,
* including the space taken by margins, in viewport coordinates.
*/
getBoundsNoRotateWithMargins: function(current) {
var bounds = this.getBoundsNoRotate(current);
var factor = this._containerInnerSize.x * this.getZoom(current); var factor = this._containerInnerSize.x * this.getZoom(current);
bounds.x -= this._margins.left / factor; bounds.x -= this._margins.left / factor;
bounds.y -= this._margins.top / factor; bounds.y -= this._margins.top / factor;
@ -440,6 +474,13 @@ $.Viewport.prototype = {
} }
}, },
// private
_applyZoomConstraints: function(zoom) {
return Math.max(
Math.min(zoom, this.getMaxZoom()),
this.getMinZoom());
},
/** /**
* @function * @function
* @private * @private
@ -521,37 +562,41 @@ $.Viewport.prototype = {
}, },
/** /**
* Enforces the minZoom, maxZoom and visibilityRatio constraints by
* zooming and panning to the closest acceptable zoom and location.
* @function * @function
* @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable. * @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:constrain * @fires OpenSeadragon.Viewer.event:constrain
*/ */
applyConstraints: function(immediately) { applyConstraints: function(immediately) {
var actualZoom = this.getZoom(), var actualZoom = this.getZoom();
constrainedZoom = Math.max( var constrainedZoom = this._applyZoomConstraints(actualZoom);
Math.min( actualZoom, this.getMaxZoom() ),
this.getMinZoom()
),
bounds,
constrainedBounds;
if ( actualZoom != constrainedZoom ) { if (actualZoom !== constrainedZoom) {
this.zoomTo(constrainedZoom, this.zoomPoint, immediately); this.zoomTo(constrainedZoom, this.zoomPoint, immediately);
} }
bounds = this.getBounds(); var bounds = this.getBoundsNoRotate();
var constrainedBounds = this._applyBoundaryConstraints(
bounds, immediately);
constrainedBounds = this._applyBoundaryConstraints( bounds, immediately ); if (bounds.x !== constrainedBounds.x ||
bounds.y !== constrainedBounds.y ||
if ( bounds.x !== constrainedBounds.x || bounds.y !== constrainedBounds.y || immediately ){ immediately) {
this.fitBounds( constrainedBounds, immediately ); this.fitBounds(
constrainedBounds.rotate(-this.getRotation()),
immediately);
} }
return this; return this;
}, },
/** /**
* Equivalent to {@link OpenSeadragon.Viewport#applyConstraints}
* @function * @function
* @param {Boolean} immediately * @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:constrain
*/ */
ensureVisible: function(immediately) { ensureVisible: function(immediately) {
return this.applyConstraints(immediately); return this.applyConstraints(immediately);
@ -571,34 +616,30 @@ $.Viewport.prototype = {
var aspect = this.getAspectRatio(); var aspect = this.getAspectRatio();
var center = bounds.getCenter(); var center = bounds.getCenter();
// Compute width and height of bounding box.
var newBounds = new $.Rect( var newBounds = new $.Rect(
bounds.x, bounds.x,
bounds.y, bounds.y,
bounds.width, bounds.width,
bounds.height bounds.height,
); bounds.degrees + this.getRotation())
.getBoundingBox();
if (newBounds.getAspectRatio() >= aspect) { if (newBounds.getAspectRatio() >= aspect) {
newBounds.height = bounds.width / aspect; newBounds.height = newBounds.width / aspect;
newBounds.y = center.y - newBounds.height / 2;
} else { } else {
newBounds.width = bounds.height * aspect; newBounds.width = newBounds.height * aspect;
newBounds.x = center.x - newBounds.width / 2;
} }
this.panTo( this.getCenter( true ), true ); // Compute x and y from width, height and center position
this.zoomTo( this.getZoom( true ), null, true ); newBounds.x = center.x - newBounds.width / 2;
newBounds.y = center.y - newBounds.height / 2;
var oldBounds = this.getBounds();
var oldZoom = this.getZoom();
var newZoom = 1.0 / newBounds.width; var newZoom = 1.0 / newBounds.width;
if (constraints) { if (constraints) {
var newBoundsAspectRatio = newBounds.getAspectRatio(); var newBoundsAspectRatio = newBounds.getAspectRatio();
var newConstrainedZoom = Math.max( var newConstrainedZoom = this._applyZoomConstraints(newZoom);
Math.min(newZoom, this.getMaxZoom() ),
this.getMinZoom()
);
if (newZoom !== newConstrainedZoom) { if (newZoom !== newConstrainedZoom) {
newZoom = newConstrainedZoom; newZoom = newConstrainedZoom;
@ -617,29 +658,35 @@ $.Viewport.prototype = {
return this.zoomTo(newZoom, null, true); return this.zoomTo(newZoom, null, true);
} }
this.panTo(this.getCenter(true), true);
this.zoomTo(this.getZoom(true), null, true);
var oldBounds = this.getBounds();
var oldZoom = this.getZoom();
if (Math.abs(newZoom - oldZoom) < 0.00000001 || if (Math.abs(newZoom - oldZoom) < 0.00000001 ||
Math.abs(newBounds.width - oldBounds.width) < 0.00000001) { Math.abs(newBounds.width - oldBounds.width) < 0.00000001) {
return this.panTo(center, immediately); return this.panTo(center, immediately);
} }
var referencePoint = oldBounds.getTopLeft().times( newBounds = newBounds.rotate(-this.getRotation());
this._containerInnerSize.x / oldBounds.width var referencePoint = newBounds.getTopLeft().divide(newBounds.width)
).minus( .minus(oldBounds.getTopLeft().divide(oldBounds.width))
newBounds.getTopLeft().times( .divide(1 / newBounds.width - 1 / oldBounds.width);
this._containerInnerSize.x / newBounds.width
)
).divide(
this._containerInnerSize.x / oldBounds.width -
this._containerInnerSize.x / newBounds.width
);
return this.zoomTo(newZoom, referencePoint, immediately); return this.zoomTo(newZoom, referencePoint, immediately);
}, },
/** /**
* Makes the viewport zoom and pan so that the specified bounds take
* as much space as possible in the viewport.
* Note: this method ignores the constraints (minZoom, maxZoom and
* visibilityRatio).
* Use {@link OpenSeadragon.Viewport#fitBoundsWithConstraints} to enforce
* them.
* @function * @function
* @param {OpenSeadragon.Rect} bounds * @param {OpenSeadragon.Rect} bounds
* @param {Boolean} immediately * @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable. * @return {OpenSeadragon.Viewport} Chainable.
*/ */
fitBounds: function(bounds, immediately) { fitBounds: function(bounds, immediately) {
@ -650,9 +697,15 @@ $.Viewport.prototype = {
}, },
/** /**
* Makes the viewport zoom and pan so that the specified bounds take
* as much space as possible in the viewport while enforcing the constraints
* (minZoom, maxZoom and visibilityRatio).
* Note: because this method enforces the constraints, part of the
* provided bounds may end up outside of the viewport.
* Use {@link OpenSeadragon.Viewport#fitBounds} to ignore them.
* @function * @function
* @param {OpenSeadragon.Rect} bounds * @param {OpenSeadragon.Rect} bounds
* @param {Boolean} immediately * @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable. * @return {OpenSeadragon.Viewport} Chainable.
*/ */
fitBoundsWithConstraints: function(bounds, immediately) { fitBoundsWithConstraints: function(bounds, immediately) {
@ -754,7 +807,12 @@ $.Viewport.prototype = {
}, },
/** /**
* Zooms to the specified zoom level
* @function * @function
* @param {Number} zoom The zoom level to zoom to.
* @param {OpenSeadragon.Point} [refPoint] The point which will stay at
* the same screen location. Defaults to the viewport center.
* @param {Boolean} [immediately=false]
* @return {OpenSeadragon.Viewport} Chainable. * @return {OpenSeadragon.Viewport} Chainable.
* @fires OpenSeadragon.Viewer.event:zoom * @fires OpenSeadragon.Viewer.event:zoom
*/ */
@ -844,7 +902,7 @@ $.Viewport.prototype = {
* @fires OpenSeadragon.Viewer.event:resize * @fires OpenSeadragon.Viewer.event:resize
*/ */
resize: function( newContainerSize, maintain ) { resize: function( newContainerSize, maintain ) {
var oldBounds = this.getBounds(), var oldBounds = this.getBoundsNoRotate(),
newBounds = oldBounds, newBounds = oldBounds,
widthDeltaFactor; widthDeltaFactor;
@ -996,7 +1054,8 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
pixelFromPointNoRotate: function(point, current) { pixelFromPointNoRotate: function(point, current) {
return this._pixelFromPointNoRotate(point, this.getBounds(current)); return this._pixelFromPointNoRotate(
point, this.getBoundsNoRotate(current));
}, },
/** /**
@ -1007,7 +1066,7 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
pixelFromPoint: function(point, current) { pixelFromPoint: function(point, current) {
return this._pixelFromPoint(point, this.getBounds(current)); return this._pixelFromPoint(point, this.getBoundsNoRotate(current));
}, },
// private // private
@ -1038,7 +1097,7 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
pointFromPixelNoRotate: function(pixel, current) { pointFromPixelNoRotate: function(pixel, current) {
var bounds = this.getBounds( current ); var bounds = this.getBoundsNoRotate(current);
return pixel.minus( return pixel.minus(
new $.Point(this._margins.left, this._margins.top) new $.Point(this._margins.left, this._margins.top)
).divide( ).divide(

View File

@ -679,44 +679,19 @@
// ---------- // ----------
asyncTest('Viewer: preventDefaultAction', function() { asyncTest('Viewer: preventDefaultAction', function() {
var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ), var $canvas = $(viewer.element).find('.openseadragon-canvas')
tracker = viewer.innerTracker, .not('.navigator .openseadragon-canvas');
origClickHandler, var tracker = viewer.innerTracker;
origDragHandler, var epsilon = 0.0000001;
dragCount = 10,
originalZoom = 0,
originalBounds = null;
var onOpen = function ( event ) {
viewer.removeHandler( 'open', onOpen );
// Hook viewer events to set preventDefaultAction
origClickHandler = tracker.clickHandler;
tracker.clickHandler = function ( event ) {
event.preventDefaultAction = true;
return origClickHandler( event );
};
origDragHandler = tracker.dragHandler;
tracker.dragHandler = function ( event ) {
event.preventDefaultAction = true;
return origDragHandler( event );
};
originalZoom = viewer.viewport.getZoom();
originalBounds = viewer.viewport.getBounds();
var event = {
clientX:1,
clientY:1
};
function simulateClickAndDrag() {
$canvas.simulate( 'focus', event ); $canvas.simulate( 'focus', event );
// Drag to pan // Drag to pan
Util.simulateViewerClickWithDrag( { Util.simulateViewerClickWithDrag( {
viewer: viewer, viewer: viewer,
widthFactor: 0.25, widthFactor: 0.25,
heightFactor: 0.25, heightFactor: 0.25,
dragCount: dragCount, dragCount: 10,
dragDx: 1, dragDx: 1,
dragDy: 1 dragDy: 1
} ); } );
@ -730,12 +705,49 @@
dragDy: 0 dragDy: 0
} ); } );
$canvas.simulate( 'blur', event ); $canvas.simulate( 'blur', event );
}
var zoom = viewer.viewport.getZoom(), var onOpen = function() {
bounds = viewer.viewport.getBounds(); viewer.removeHandler('open', onOpen);
equal( zoom, originalZoom, "Zoom prevented" ); // Hook viewer events to set preventDefaultAction
ok( bounds.x == originalBounds.x && bounds.y == originalBounds.y, 'Pan prevented' ); var origClickHandler = tracker.clickHandler;
tracker.clickHandler = function(event) {
event.preventDefaultAction = true;
return origClickHandler(event);
};
var origDragHandler = tracker.dragHandler;
tracker.dragHandler = function(event) {
event.preventDefaultAction = true;
return origDragHandler(event);
};
var originalZoom = viewer.viewport.getZoom();
var originalBounds = viewer.viewport.getBounds();
simulateClickAndDrag();
var zoom = viewer.viewport.getZoom();
var bounds = viewer.viewport.getBounds();
Util.assessNumericValue(zoom, originalZoom, epsilon,
"Zoom should be prevented");
Util.assertRectangleEquals(bounds, originalBounds, epsilon,
'Pan should be prevented');
tracker.clickHandler = origClickHandler;
tracker.dragHandler = origDragHandler;
simulateClickAndDrag();
var zoom = viewer.viewport.getZoom();
var bounds = viewer.viewport.getBounds();
Util.assessNumericValue(zoom, 0.002, epsilon,
"Zoom should not be prevented");
Util.assertRectangleEquals(
bounds,
new OpenSeadragon.Rect(-250, -0.25, 500, 0.5),
epsilon,
'Pan should not be prevented');
viewer.close(); viewer.close();
start(); start();

View File

@ -5,6 +5,7 @@
var VIEWER_ID = "example"; var VIEWER_ID = "example";
var PREFIX_URL = "/build/openseadragon/images/"; var PREFIX_URL = "/build/openseadragon/images/";
var SPRING_STIFFNESS = 100; // Faster animation = faster tests var SPRING_STIFFNESS = 100; // Faster animation = faster tests
var EPSILON = 0.0000000001;
module("viewport", { module("viewport", {
setup: function () { setup: function () {
@ -218,7 +219,27 @@
}); });
}); });
asyncTest('getHomeBoundsWithRotation', function() { asyncTest('getHomeBoundsNoRotate with rotation', function() {
function openHandler() {
viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport;
viewport.setRotation(-675);
Util.assertRectangleEquals(
viewport.getHomeBoundsNoRotate(),
new OpenSeadragon.Rect(
(1 - Math.sqrt(2)) / 2,
(1 - Math.sqrt(2)) / 2,
Math.sqrt(2),
Math.sqrt(2)),
0.00000001,
"Test getHomeBoundsNoRotate with degrees = -675");
start();
}
viewer.addHandler('open', openHandler);
viewer.open(DZI_PATH);
});
asyncTest('getHomeBounds with rotation', function() {
function openHandler() { function openHandler() {
viewer.removeHandler('open', openHandler); viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport; var viewport = viewer.viewport;
@ -226,10 +247,11 @@
Util.assertRectangleEquals( Util.assertRectangleEquals(
viewport.getHomeBounds(), viewport.getHomeBounds(),
new OpenSeadragon.Rect( new OpenSeadragon.Rect(
(1 - Math.sqrt(2)) / 2, 0.5,
(1 - Math.sqrt(2)) / 2, -0.5,
Math.sqrt(2), Math.sqrt(2),
Math.sqrt(2)), Math.sqrt(2),
45),
0.00000001, 0.00000001,
"Test getHomeBounds with degrees = -675"); "Test getHomeBounds with degrees = -675");
start(); start();
@ -405,17 +427,114 @@
viewer.open(DZI_PATH); viewer.open(DZI_PATH);
}); });
asyncTest('applyConstraints', function() {
var openHandler = function() {
viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport;
viewport.fitBounds(new OpenSeadragon.Rect(1, 1, 1, 1), true);
viewport.visibilityRatio = 0.3;
viewport.applyConstraints(true);
var bounds = viewport.getBounds();
Util.assertRectangleEquals(
bounds,
new OpenSeadragon.Rect(0.7, 0.7, 1, 1),
EPSILON,
"Viewport.applyConstraints should move viewport.");
start();
};
viewer.addHandler('open', openHandler);
viewer.open(DZI_PATH);
});
asyncTest('applyConstraints with rotation', function() {
var openHandler = function() {
viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport;
viewport.setRotation(45);
viewport.fitBounds(new OpenSeadragon.Rect(1, 1, 1, 1), true);
viewport.applyConstraints(true);
var bounds = viewport.getBounds();
Util.assertRectangleEquals(
bounds,
new OpenSeadragon.Rect(1, 0, Math.sqrt(2), Math.sqrt(2), 45),
EPSILON,
"Viewport.applyConstraints with rotation should move viewport.");
start();
};
viewer.addHandler('open', openHandler);
viewer.open(DZI_PATH);
});
// Fit bounds tests
var testRectsFitBounds = [
new OpenSeadragon.Rect(0, -0.75, 0.5, 1),
new OpenSeadragon.Rect(0.5, 0, 0.5, 0.8),
new OpenSeadragon.Rect(0.75, 0.75, 0.5, 0.5),
new OpenSeadragon.Rect(-0.3, -0.3, 0.5, 0.5),
new OpenSeadragon.Rect(0.5, 0.25, Math.sqrt(0.125), Math.sqrt(0.125), 45)
];
var expectedRectsFitBounds = [
new OpenSeadragon.Rect(-0.25, -0.75, 1, 1),
new OpenSeadragon.Rect(0.35, 0, 0.8, 0.8),
new OpenSeadragon.Rect(0.75, 0.75, 0.5, 0.5),
new OpenSeadragon.Rect(-0.3, -0.3, 0.5, 0.5),
new OpenSeadragon.Rect(0.25, 0.25, 0.5, 0.5)
];
var expectedRectsFitBoundsWithRotation = [
new OpenSeadragon.Rect(
0.25,
-1,
Math.sqrt(0.125) + Math.sqrt(0.5),
Math.sqrt(0.125) + Math.sqrt(0.5),
45),
new OpenSeadragon.Rect(
0.75,
-0.25,
Math.sqrt(0.125) + Math.sqrt(8 / 25),
Math.sqrt(0.125) + Math.sqrt(8 / 25),
45),
new OpenSeadragon.Rect(
1,
0.5,
Math.sqrt(0.125) * 2,
Math.sqrt(0.125) * 2,
45),
new OpenSeadragon.Rect(
-0.05,
-0.55,
Math.sqrt(0.125) * 2,
Math.sqrt(0.125) * 2,
45),
new OpenSeadragon.Rect(
0.5,
0.25,
Math.sqrt(0.125),
Math.sqrt(0.125),
45)
];
var expectedRectsFitBoundsWithConstraints = [
new OpenSeadragon.Rect(-0.25, -0.5, 1, 1),
new OpenSeadragon.Rect(0.35, 0, 0.8, 0.8),
new OpenSeadragon.Rect(0.75, 0.75, 0.5, 0.5),
new OpenSeadragon.Rect(-0.25, -0.25, 0.5, 0.5),
new OpenSeadragon.Rect(0.25, 0.25, 0.5, 0.5)
];
asyncTest('fitBounds', function(){ asyncTest('fitBounds', function(){
var openHandler = function(event) { var openHandler = function(event) {
viewer.removeHandler('open', openHandler); viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport; var viewport = viewer.viewport;
for(var i = 0; i < testRects.length; i++){ for(var i = 0; i < testRectsFitBounds.length; i++){
var rect = testRects[i].times(viewport.getContainerSize()); var rect = testRectsFitBounds[i];
viewport.fitBounds(rect, true); viewport.fitBounds(rect, true);
propEqual( propEqual(
viewport.getBounds(), viewport.getBounds(),
rect, expectedRectsFitBounds[i],
"Fit bounds correctly." "Fit bounds correctly."
); );
} }
@ -425,19 +544,27 @@
viewer.open(DZI_PATH); viewer.open(DZI_PATH);
}); });
var testRectsFitBounds = [ asyncTest('fitBounds with viewport rotation', function(){
new OpenSeadragon.Rect(0, -0.75, 0.5, 1), var openHandler = function(event) {
new OpenSeadragon.Rect(0.5, 0, 0.5, 0.8), viewer.removeHandler('open', openHandler);
new OpenSeadragon.Rect(0.75, 0.75, 0.5, 0.5), var viewport = viewer.viewport;
new OpenSeadragon.Rect(-0.3, -0.3, 0.5, 0.5) viewport.setRotation(45);
];
var expectedRectsFitBounds = [ for(var i = 0; i < testRectsFitBounds.length; i++){
new OpenSeadragon.Rect(-0.25, -0.5, 1, 1), var rect = testRectsFitBounds[i];
new OpenSeadragon.Rect(0.35, 0, 0.8, 0.8), viewport.fitBounds(rect, true);
new OpenSeadragon.Rect(0.75, 0.75, 0.5, 0.5), Util.assertRectangleEquals(
new OpenSeadragon.Rect(-0.25, -0.25, 0.5, 0.5) viewport.getBounds(),
]; expectedRectsFitBoundsWithRotation[i],
EPSILON,
"Fit bounds correctly."
);
}
start();
};
viewer.addHandler('open', openHandler);
viewer.open(DZI_PATH);
});
asyncTest('fitBoundsWithConstraints', function(){ asyncTest('fitBoundsWithConstraints', function(){
var openHandler = function(event) { var openHandler = function(event) {
@ -450,7 +577,7 @@
viewport.fitBoundsWithConstraints(rect, true); viewport.fitBoundsWithConstraints(rect, true);
propEqual( propEqual(
viewport.getBounds(), viewport.getBounds(),
expectedRectsFitBounds[i], expectedRectsFitBoundsWithConstraints[i],
"Fit bounds correctly." "Fit bounds correctly."
); );
} }
@ -491,6 +618,7 @@
viewer.addHandler('open', openHandler); viewer.addHandler('open', openHandler);
viewer.open(WIDE_PATH); viewer.open(WIDE_PATH);
}); });
// End fitBounds tests.
asyncTest('panBy', function(){ asyncTest('panBy', function(){
var openHandler = function(event) { var openHandler = function(event) {