mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-29 00:26:10 +03:00
Viewport getBounds and fitBounds methods now take rotation into account. Fix #924
This commit is contained in:
parent
3106d8f85b
commit
521e020b9a
@ -306,8 +306,8 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
||||
this.updateSize();
|
||||
}
|
||||
|
||||
if( viewport && this.viewport ) {
|
||||
bounds = viewport.getBounds( true );
|
||||
if (viewport && this.viewport) {
|
||||
bounds = viewport.getBoundsNoRotate(true);
|
||||
topleft = this.viewport.pixelFromPointNoRotate(bounds.getTopLeft(), false);
|
||||
bottomright = this.viewport.pixelFromPointNoRotate(bounds.getBottomRight(), false)
|
||||
.minus( this.totalBorderWidths );
|
||||
|
@ -795,6 +795,7 @@ function updateViewport( tiledImage ) {
|
||||
levelOpacity,
|
||||
levelVisibility;
|
||||
|
||||
viewportBounds = viewportBounds.getBoundingBox();
|
||||
viewportBounds.x -= tiledImage._xSpring.current.value;
|
||||
viewportBounds.y -= tiledImage._ySpring.current.value;
|
||||
|
||||
@ -804,18 +805,6 @@ function updateViewport( tiledImage ) {
|
||||
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 viewportBR = viewportBounds.getBottomRight();
|
||||
|
||||
|
@ -2981,11 +2981,13 @@ function updateOnce( viewer ) {
|
||||
if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) {
|
||||
if ( viewer.preserveImageSizeOnResize ) {
|
||||
var prevContainerSize = THIS[ viewer.hash ].prevContainerSize;
|
||||
var bounds = viewer.viewport.getBounds(true);
|
||||
var bounds = viewer.viewport.getBoundsNoRotate(true);
|
||||
var deltaX = (containerSize.x - prevContainerSize.x);
|
||||
var deltaY = (containerSize.y - prevContainerSize.y);
|
||||
var viewportDiff = viewer.viewport.deltaPointsFromPixels(new OpenSeadragon.Point(deltaX, deltaY), true);
|
||||
viewer.viewport.resize(new OpenSeadragon.Point(containerSize.x, containerSize.y), false);
|
||||
var viewportDiff = viewer.viewport.deltaPointsFromPixels(
|
||||
new $.Point(deltaX, deltaY), true);
|
||||
viewer.viewport.resize(
|
||||
new $.Point(containerSize.x, containerSize.y), false);
|
||||
|
||||
// Keep the center of the image in the center and just adjust the amount of image shown
|
||||
bounds.width += viewportDiff.x;
|
||||
@ -2996,7 +2998,7 @@ function updateOnce( viewer ) {
|
||||
}
|
||||
else {
|
||||
// maintain image position
|
||||
var oldBounds = viewer.viewport.getBounds();
|
||||
var oldBounds = viewer.viewport.getBoundsNoRotate();
|
||||
var oldCenter = viewer.viewport.getCenter();
|
||||
resizeViewportAndRecenter(viewer, containerSize, oldBounds, oldCenter);
|
||||
}
|
||||
|
129
src/viewport.js
129
src/viewport.js
@ -237,6 +237,17 @@ $.Viewport.prototype = {
|
||||
* @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates.
|
||||
*/
|
||||
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 width = 1.0 / this.getHomeZoom();
|
||||
var height = width / this.getAspectRatio();
|
||||
@ -254,8 +265,8 @@ $.Viewport.prototype = {
|
||||
* @param {Boolean} immediately
|
||||
* @fires OpenSeadragon.Viewer.event:home
|
||||
*/
|
||||
goHome: function( immediately ) {
|
||||
if( this.viewer ){
|
||||
goHome: function(immediately) {
|
||||
if (this.viewer) {
|
||||
/**
|
||||
* Raised when the "home" operation occurs (see {@link OpenSeadragon.Viewport#goHome}).
|
||||
*
|
||||
@ -266,11 +277,11 @@ $.Viewport.prototype = {
|
||||
* @property {Boolean} immediately
|
||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||
*/
|
||||
this.viewer.raiseEvent( 'home', {
|
||||
this.viewer.raiseEvent('home', {
|
||||
immediately: immediately
|
||||
});
|
||||
}
|
||||
return this.fitBounds( this.getHomeBounds(), immediately );
|
||||
return this.fitBounds(this.getHomeBounds(), immediately);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -352,14 +363,26 @@ $.Viewport.prototype = {
|
||||
* @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.
|
||||
*/
|
||||
getBounds: function( current ) {
|
||||
var center = this.getCenter( current ),
|
||||
width = 1.0 / this.getZoom( current ),
|
||||
height = width / this.getAspectRatio();
|
||||
getBounds: function(current) {
|
||||
return this.getBoundsNoRotate(current).rotate(-this.getRotation());
|
||||
},
|
||||
|
||||
/**
|
||||
* 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(
|
||||
center.x - ( width / 2.0 ),
|
||||
center.y - ( height / 2.0 ),
|
||||
center.x - (width / 2.0),
|
||||
center.y - (height / 2.0),
|
||||
width,
|
||||
height
|
||||
);
|
||||
@ -371,8 +394,19 @@ $.Viewport.prototype = {
|
||||
* @returns {OpenSeadragon.Rect} The location you are zoomed/panned to,
|
||||
* including the space taken by margins, in viewport coordinates.
|
||||
*/
|
||||
getBoundsWithMargins: function( current ) {
|
||||
var bounds = this.getBounds(current);
|
||||
getBoundsWithMargins: function(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);
|
||||
bounds.x -= this._margins.left / factor;
|
||||
bounds.y -= this._margins.top / factor;
|
||||
@ -538,7 +572,7 @@ $.Viewport.prototype = {
|
||||
this.zoomTo( constrainedZoom, this.zoomPoint, immediately );
|
||||
}
|
||||
|
||||
bounds = this.getBounds();
|
||||
bounds = this.getBoundsNoRotate();
|
||||
|
||||
constrainedBounds = this._applyBoundaryConstraints( bounds, immediately );
|
||||
|
||||
@ -564,39 +598,38 @@ $.Viewport.prototype = {
|
||||
* @param {Object} options (immediately=false, constraints=false)
|
||||
* @return {OpenSeadragon.Viewport} Chainable.
|
||||
*/
|
||||
_fitBounds: function( bounds, options ) {
|
||||
_fitBounds: function(bounds, options) {
|
||||
options = options || {};
|
||||
var immediately = options.immediately || false;
|
||||
var constraints = options.constraints || false;
|
||||
|
||||
var aspect = this.getAspectRatio();
|
||||
var center = bounds.getCenter();
|
||||
|
||||
// Compute width and height of bounding box.
|
||||
var newBounds = new $.Rect(
|
||||
bounds.x,
|
||||
bounds.y,
|
||||
bounds.width,
|
||||
bounds.height
|
||||
);
|
||||
bounds.height,
|
||||
bounds.degrees + this.getRotation())
|
||||
.getBoundingBox();
|
||||
|
||||
if ( newBounds.getAspectRatio() >= aspect ) {
|
||||
newBounds.height = bounds.width / aspect;
|
||||
newBounds.y = center.y - newBounds.height / 2;
|
||||
if (newBounds.getAspectRatio() >= aspect) {
|
||||
newBounds.height = newBounds.width / aspect;
|
||||
} else {
|
||||
newBounds.width = bounds.height * aspect;
|
||||
newBounds.x = center.x - newBounds.width / 2;
|
||||
newBounds.width = newBounds.height * aspect;
|
||||
}
|
||||
|
||||
this.panTo( this.getCenter( true ), true );
|
||||
this.zoomTo( this.getZoom( true ), null, true );
|
||||
|
||||
var oldBounds = this.getBounds();
|
||||
var oldZoom = this.getZoom();
|
||||
// Compute x and y from width, height and center position
|
||||
newBounds.x = center.x - newBounds.width / 2;
|
||||
newBounds.y = center.y - newBounds.height / 2;
|
||||
var newZoom = 1.0 / newBounds.width;
|
||||
|
||||
if (constraints) {
|
||||
var newBoundsAspectRatio = newBounds.getAspectRatio();
|
||||
var newConstrainedZoom = Math.max(
|
||||
Math.min(newZoom, this.getMaxZoom() ),
|
||||
Math.min(newZoom, this.getMaxZoom()),
|
||||
this.getMinZoom()
|
||||
);
|
||||
|
||||
@ -608,32 +641,32 @@ $.Viewport.prototype = {
|
||||
newBounds.y = center.y - newBounds.height / 2;
|
||||
}
|
||||
|
||||
newBounds = this._applyBoundaryConstraints( newBounds, immediately );
|
||||
newBounds = this._applyBoundaryConstraints(newBounds, immediately);
|
||||
center = newBounds.getCenter();
|
||||
}
|
||||
|
||||
if (immediately) {
|
||||
this.panTo( center, true );
|
||||
this.panTo(center, 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 ||
|
||||
Math.abs(newBounds.width - oldBounds.width) < 0.00000001) {
|
||||
return this.panTo( center, immediately );
|
||||
return this.panTo(center, immediately);
|
||||
}
|
||||
|
||||
var referencePoint = oldBounds.getTopLeft().times(
|
||||
this._containerInnerSize.x / oldBounds.width
|
||||
).minus(
|
||||
newBounds.getTopLeft().times(
|
||||
this._containerInnerSize.x / newBounds.width
|
||||
)
|
||||
).divide(
|
||||
this._containerInnerSize.x / oldBounds.width -
|
||||
this._containerInnerSize.x / newBounds.width
|
||||
);
|
||||
newBounds = newBounds.rotate(-this.getRotation());
|
||||
var referencePoint = newBounds.getTopLeft().divide(newBounds.width)
|
||||
.minus(oldBounds.getTopLeft().divide(oldBounds.width))
|
||||
.divide(1 / newBounds.width - 1 / oldBounds.width);
|
||||
|
||||
return this.zoomTo( newZoom, referencePoint, immediately );
|
||||
return this.zoomTo(newZoom, referencePoint, immediately);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -754,7 +787,12 @@ $.Viewport.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Zooms to the specified zoom level
|
||||
* @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.
|
||||
* @fires OpenSeadragon.Viewer.event:zoom
|
||||
*/
|
||||
@ -844,7 +882,7 @@ $.Viewport.prototype = {
|
||||
* @fires OpenSeadragon.Viewer.event:resize
|
||||
*/
|
||||
resize: function( newContainerSize, maintain ) {
|
||||
var oldBounds = this.getBounds(),
|
||||
var oldBounds = this.getBoundsNoRotate(),
|
||||
newBounds = oldBounds,
|
||||
widthDeltaFactor;
|
||||
|
||||
@ -996,7 +1034,8 @@ $.Viewport.prototype = {
|
||||
* @returns {OpenSeadragon.Point}
|
||||
*/
|
||||
pixelFromPointNoRotate: function(point, current) {
|
||||
return this._pixelFromPointNoRotate(point, this.getBounds(current));
|
||||
return this._pixelFromPointNoRotate(
|
||||
point, this.getBoundsNoRotate(current));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1007,7 +1046,7 @@ $.Viewport.prototype = {
|
||||
* @returns {OpenSeadragon.Point}
|
||||
*/
|
||||
pixelFromPoint: function(point, current) {
|
||||
return this._pixelFromPoint(point, this.getBounds(current));
|
||||
return this._pixelFromPoint(point, this.getBoundsNoRotate(current));
|
||||
},
|
||||
|
||||
// private
|
||||
@ -1038,7 +1077,7 @@ $.Viewport.prototype = {
|
||||
* @returns {OpenSeadragon.Point}
|
||||
*/
|
||||
pointFromPixelNoRotate: function(pixel, current) {
|
||||
var bounds = this.getBounds( current );
|
||||
var bounds = this.getBoundsNoRotate(current);
|
||||
return pixel.minus(
|
||||
new $.Point(this._margins.left, this._margins.top)
|
||||
).divide(
|
||||
|
@ -5,6 +5,7 @@
|
||||
var VIEWER_ID = "example";
|
||||
var PREFIX_URL = "/build/openseadragon/images/";
|
||||
var SPRING_STIFFNESS = 100; // Faster animation = faster tests
|
||||
var EPSILON = 0.0000000001;
|
||||
|
||||
module("viewport", {
|
||||
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() {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
@ -226,10 +247,11 @@
|
||||
Util.assertRectangleEquals(
|
||||
viewport.getHomeBounds(),
|
||||
new OpenSeadragon.Rect(
|
||||
(1 - Math.sqrt(2)) / 2,
|
||||
(1 - Math.sqrt(2)) / 2,
|
||||
0.5,
|
||||
-0.5,
|
||||
Math.sqrt(2),
|
||||
Math.sqrt(2)),
|
||||
Math.sqrt(2),
|
||||
45),
|
||||
0.00000001,
|
||||
"Test getHomeBounds with degrees = -675");
|
||||
start();
|
||||
@ -420,6 +442,33 @@
|
||||
new OpenSeadragon.Rect(-0.3, -0.3, 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)
|
||||
];
|
||||
|
||||
var expectedRectsFitBoundsWithConstraints = [
|
||||
new OpenSeadragon.Rect(-0.25, -0.5, 1, 1),
|
||||
new OpenSeadragon.Rect(0.35, 0, 0.8, 0.8),
|
||||
@ -447,6 +496,28 @@
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
asyncTest('fitBounds with viewport rotation', function(){
|
||||
var openHandler = function(event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
var viewport = viewer.viewport;
|
||||
viewport.setRotation(45);
|
||||
|
||||
for(var i = 0; i < testRectsFitBounds.length; i++){
|
||||
var rect = testRectsFitBounds[i];
|
||||
viewport.fitBounds(rect, true);
|
||||
Util.assertRectangleEquals(
|
||||
viewport.getBounds(),
|
||||
expectedRectsFitBoundsWithRotation[i],
|
||||
EPSILON,
|
||||
"Fit bounds correctly."
|
||||
);
|
||||
}
|
||||
start();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
viewer.open(DZI_PATH);
|
||||
});
|
||||
|
||||
asyncTest('fitBoundsWithConstraints', function(){
|
||||
var openHandler = function(event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
|
Loading…
Reference in New Issue
Block a user