Fix Overlays.getBounds with rotation.

This commit is contained in:
Antoine Vandecreme 2016-04-01 13:29:09 -04:00
parent 0685d8a3a4
commit bd62d56a37
2 changed files with 268 additions and 20 deletions

View File

@ -131,7 +131,6 @@
/** @lends OpenSeadragon.Overlay.prototype */
$.Overlay.prototype = {
// private
_init: function(options) {
this.location = options.location;
@ -157,7 +156,6 @@
this.placement = $.Placement.TOP_LEFT;
}
},
/**
* Internal function to adjust the position of an overlay
* depending on it size and placement.
@ -181,7 +179,6 @@
position.y -= size.y;
}
},
/**
* @function
*/
@ -225,7 +222,6 @@
style[transformProp] = "";
}
},
/**
* @function
* @param {Element} container
@ -283,7 +279,6 @@
}
}
},
// private
_getOverlayPositionAndSize: function(viewport) {
var position = viewport.pixelFromPoint(this.location, true);
@ -312,7 +307,6 @@
rotate: rotate
};
},
// private
_getSizeInPixels: function(viewport) {
var width = this.size.x;
@ -339,26 +333,29 @@
}
return new $.Point(width, height);
},
// private
_getBoundingBox: function(rect, degrees) {
var refPoint = new $.Point(rect.x, rect.y);
var refPoint = this._getPlacementPoint(rect);
return rect.rotate(degrees, refPoint).getBoundingBox();
},
// private
_getPlacementPoint: function(rect) {
var result = new $.Point(rect.x, rect.y);
var properties = $.Placement.properties[this.placement];
if (properties) {
if (properties.isHorizontallyCentered) {
refPoint.x += rect.width / 2;
result.x += rect.width / 2;
} else if (properties.isRight) {
refPoint.x += rect.width;
result.x += rect.width;
}
if (properties.isVerticallyCentered) {
refPoint.y += rect.height / 2;
result.y += rect.height / 2;
} else if (properties.isBottom) {
refPoint.y += rect.height;
result.y += rect.height;
}
}
return rect.rotate(degrees, refPoint).getBoundingBox();
return result;
},
// private
_getTransformOrigin: function() {
var result = "";
@ -378,7 +375,6 @@
}
return result;
},
/**
* Changes the overlay settings.
* @function
@ -403,7 +399,6 @@
rotationMode: options.rotationMode || this.rotationMode
});
},
/**
* Returns the current bounds of the overlay in viewport coordinates
* @function
@ -411,11 +406,11 @@
* @returns {OpenSeadragon.Rect} overlay bounds
*/
getBounds: function(viewport) {
$.console.assert(!viewport, 'Calling Overlay.getBounds withouth ' +
'specifying a viewport is deprecated.');
var width = this.width;
var height = this.height;
if (width === null || height === null) {
$.console.assert(!viewport, 'The viewport must be specified to' +
' get the bounds of a not entirely scaling overlay');
var size = viewport.deltaPointsFromPixelsNoRotate(this.size, true);
if (width === null) {
width = size.x;
@ -426,7 +421,23 @@
}
var location = this.location.clone();
this.adjust(location, new $.Point(width, height));
return new $.Rect(location.x, location.y, width, height);
return this._adjustBoundsForRotation(
viewport, new $.Rect(location.x, location.y, width, height));
},
_adjustBoundsForRotation: function(viewport, bounds) {
if (!viewport ||
viewport.degrees === 0 ||
this.rotationMode === $.OverlayRotationMode.EXACT) {
return bounds;
}
// If overlay not fully scalable, BOUNDING_BOX falls back to EXACT
if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX &&
(this.width === null || this.height === null)) {
return bounds;
}
return bounds.rotate(-viewport.degrees,
this._getPlacementPoint(bounds));
}
};

View File

@ -658,6 +658,7 @@
});
});
// ----------
asyncTest('Overlay.getBounds', function() {
viewer = OpenSeadragon({
id: 'example-overlays',
@ -710,7 +711,7 @@
viewer._drawOverlays();
var actualBounds = viewer.getOverlayById("fully-scaled-overlay")
.getBounds();
.getBounds(viewer.viewport);
var expectedBounds = new OpenSeadragon.Rect(0, 0, 1, 1);
ok(expectedBounds.equals(actualBounds),
"The fully scaled overlay should have bounds " +
@ -745,4 +746,240 @@
});
});
// ----------
asyncTest('Fully scaled overlay rotation mode NO_ROTATION', function() {
viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
degrees: 45,
overlays: [{
id: "fully-scaled-overlay",
x: 1,
y: 1,
width: 1,
height: 1,
placement: OpenSeadragon.Placement.BOTTOM_RIGHT,
rotationMode: OpenSeadragon.OverlayRotationMode.NO_ROTATION
}]
});
viewer.addOnceHandler('open', function() {
var viewport = viewer.viewport;
var $overlay = $("#fully-scaled-overlay");
var expectedSize = viewport.deltaPixelsFromPointsNoRotate(
new OpenSeadragon.Point(1, 1));
var expectedPosition = viewport.viewportToViewerElementCoordinates(
new OpenSeadragon.Point(1, 1))
.minus(expectedSize);
var actualPosition = $overlay.position();
Util.assessNumericValue(actualPosition.left, expectedPosition.x, epsilon,
"Scaled overlay position.x should adjust to rotation.");
Util.assessNumericValue(actualPosition.top, expectedPosition.y, epsilon,
"Scaled overlay position.y should adjust to rotation.");
var actualWidth = $overlay.width();
var actualHeight = $overlay.height();
Util.assessNumericValue(actualWidth, expectedSize.x, epsilon,
"Scaled overlay width should not adjust to rotation.");
Util.assessNumericValue(actualHeight, expectedSize.y, epsilon,
"Scaled overlay height should not adjust to rotation.");
var actualBounds = viewer.getOverlayById("fully-scaled-overlay")
.getBounds(viewport);
var expectedBounds = new OpenSeadragon.Rect(0, 0, 1, 1)
.rotate(-45, new OpenSeadragon.Point(1, 1));
ok(expectedBounds.equals(actualBounds),
"The fully scaled overlay should have bounds " +
expectedBounds.toString() + " but found " + actualBounds);
start();
});
});
// ----------
asyncTest('Horizontally scaled overlay rotation mode NO_ROTATION', function() {
viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
degrees: 45,
overlays: [{
id: "horizontally-scaled-overlay",
x: 0.5,
y: 0.5,
width: 1,
placement: OpenSeadragon.Placement.CENTER,
rotationMode: OpenSeadragon.OverlayRotationMode.NO_ROTATION
}]
});
viewer.addOnceHandler('open', function() {
var $overlay = $("#horizontally-scaled-overlay");
var notScaledWidth = 100;
var notScaledHeight = 100;
$overlay.get(0).style.height = notScaledHeight + "px";
var viewport = viewer.viewport;
var notScaledSize = viewport.deltaPointsFromPixelsNoRotate(
new OpenSeadragon.Point(notScaledWidth, notScaledHeight));
// Force refresh to takes new dimensions into account.
viewer._drawOverlays();
var expectedWidth = viewport.deltaPixelsFromPointsNoRotate(
new OpenSeadragon.Point(1, 1)).x;
var expectedPosition = viewport.viewportToViewerElementCoordinates(
new OpenSeadragon.Point(0.5, 0.5))
.minus(new OpenSeadragon.Point(expectedWidth / 2, notScaledHeight / 2));
var actualPosition = $overlay.position();
Util.assessNumericValue(actualPosition.left, expectedPosition.x, epsilon,
"Horizontally scaled overlay position.x should adjust to rotation.");
Util.assessNumericValue(actualPosition.top, expectedPosition.y, epsilon,
"Horizontally scaled overlay position.y should adjust to rotation.");
var actualWidth = $overlay.width();
var actualHeight = $overlay.height();
Util.assessNumericValue(actualWidth, expectedWidth, epsilon,
"Horizontally scaled overlay width should not adjust to rotation.");
Util.assessNumericValue(actualHeight, notScaledHeight, epsilon,
"Horizontally scaled overlay height should not adjust to rotation.");
var actualBounds = viewer.getOverlayById("horizontally-scaled-overlay")
.getBounds(viewport);
var expectedBounds = new OpenSeadragon.Rect(
0, 0.5 - notScaledSize.y / 2, 1, notScaledSize.y)
.rotate(-45, new OpenSeadragon.Point(0.5, 0.5));
ok(expectedBounds.equals(actualBounds),
"The horizontally scaled overlay should have bounds " +
expectedBounds.toString() + " but found " + actualBounds);
start();
});
});
// ----------
asyncTest('Vertically scaled overlay rotation mode NO_ROTATION', function() {
viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
degrees: 45,
overlays: [{
id: "vertically-scaled-overlay",
x: 0,
y: 0.5,
height: 1,
placement: OpenSeadragon.Placement.LEFT,
rotationMode: OpenSeadragon.OverlayRotationMode.NO_ROTATION
}]
});
viewer.addOnceHandler('open', function() {
var $overlay = $("#vertically-scaled-overlay");
var notScaledWidth = 100;
var notScaledHeight = 100;
$overlay.get(0).style.width = notScaledWidth + "px";
var viewport = viewer.viewport;
var notScaledSize = viewport.deltaPointsFromPixelsNoRotate(
new OpenSeadragon.Point(notScaledWidth, notScaledHeight));
// Force refresh to takes new dimensions into account.
viewer._drawOverlays();
var expectedHeight = viewport.deltaPixelsFromPointsNoRotate(
new OpenSeadragon.Point(1, 1)).y;
var expectedPosition = viewport.viewportToViewerElementCoordinates(
new OpenSeadragon.Point(0, 0.5))
.minus(new OpenSeadragon.Point(0, expectedHeight / 2));
var actualPosition = $overlay.position();
Util.assessNumericValue(actualPosition.left, expectedPosition.x, epsilon,
"Vertically scaled overlay position.x should adjust to rotation.");
Util.assessNumericValue(actualPosition.top, expectedPosition.y, epsilon,
"Vertically scaled overlay position.y should adjust to rotation.");
var actualWidth = $overlay.width();
var actualHeight = $overlay.height();
Util.assessNumericValue(actualWidth, notScaledWidth, epsilon,
"Vertically scaled overlay width should not adjust to rotation.");
Util.assessNumericValue(actualHeight, expectedHeight, epsilon,
"Vertically scaled overlay height should not adjust to rotation.");
var actualBounds = viewer.getOverlayById("vertically-scaled-overlay")
.getBounds(viewport);
var expectedBounds = new OpenSeadragon.Rect(
0, 0, notScaledSize.x, 1)
.rotate(-45, new OpenSeadragon.Point(0, 0.5));
ok(expectedBounds.equals(actualBounds),
"The vertically scaled overlay should have bounds " +
expectedBounds.toString() + " but found " + actualBounds);
start();
});
});
// ----------
asyncTest('Not scaled overlay rotation mode NO_ROTATION', function() {
viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
degrees: 45,
overlays: [{
id: "not-scaled-overlay",
x: 1,
y: 0,
placement: OpenSeadragon.Placement.TOP_RIGHT,
rotationMode: OpenSeadragon.OverlayRotationMode.NO_ROTATION
}]
});
viewer.addOnceHandler('open', function() {
var $overlay = $("#not-scaled-overlay");
var notScaledWidth = 100;
var notScaledHeight = 100;
$overlay.get(0).style.width = notScaledWidth + "px";
$overlay.get(0).style.height = notScaledHeight + "px";
var viewport = viewer.viewport;
var notScaledSize = viewport.deltaPointsFromPixelsNoRotate(
new OpenSeadragon.Point(notScaledWidth, notScaledHeight));
// Force refresh to takes new dimensions into account.
viewer._drawOverlays();
var expectedPosition = viewport.viewportToViewerElementCoordinates(
new OpenSeadragon.Point(1, 0))
.minus(new OpenSeadragon.Point(notScaledWidth, 0));
var actualPosition = $overlay.position();
Util.assessNumericValue(actualPosition.left, expectedPosition.x, epsilon,
"Not scaled overlay position.x should adjust to rotation.");
Util.assessNumericValue(actualPosition.top, expectedPosition.y, epsilon,
"Not scaled overlay position.y should adjust to rotation.");
var actualWidth = $overlay.width();
var actualHeight = $overlay.height();
Util.assessNumericValue(actualWidth, notScaledWidth, epsilon,
"Not scaled overlay width should not adjust to rotation.");
Util.assessNumericValue(actualHeight, notScaledHeight, epsilon,
"Not scaled overlay height should not adjust to rotation.");
var actualBounds = viewer.getOverlayById("not-scaled-overlay")
.getBounds(viewport);
var expectedBounds = new OpenSeadragon.Rect(
1 - notScaledSize.x, 0, notScaledSize.x, notScaledSize.y)
.rotate(-45, new OpenSeadragon.Point(1, 0));
ok(expectedBounds.equals(actualBounds),
"Not scaled overlay should have bounds " +
expectedBounds.toString() + " but found " + actualBounds);
start();
});
});
})();