diff --git a/changelog.txt b/changelog.txt
index abf513ec..8829d474 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -5,6 +5,12 @@ OPENSEADRAGON CHANGELOG
* BREAKING CHANGE: Viewport.homeBounds, Viewport.contentSize, Viewport.contentAspectX and
Viewport.contentAspectY have been removed. (#846)
+* BREAKING CHANGE: The Overlay.getBounds method now takes the viewport as parameter. (#896)
+* DEPRECATION: Overlay.scales, Overlay.bounds and Overlay.position have been deprecated. (#896)
+ * Overlay.width !== null should be used to test whether the overlay scales horizontally
+ * Overlay.height !== null should be used to test whether the overlay scales vertically
+ * The Overlay.getBounds method should be used to get the bounds of the overlay in viewport coordinates
+ * Overlay.location replaces Overlay.position
* DEPRECATION: Viewport.setHomeBounds has been deprecated (#846)
* DEPRECATION: the Viewport constructor is now ignoring the contentSize option (#846)
* Tile edge smoothing at high zoom (#764)
@@ -30,6 +36,8 @@ OPENSEADRAGON CHANGELOG
* Fixed issue causing HTML pages to jump unwantedly to the reference strip upon loading (#872)
* Added addOnceHandler method to EventSource (#887)
* Added TiledImage.fitBounds method (#888)
+* Overlays can now be scaled in a single dimension by providing a point location and either width or height (#896)
+* Added full rotation support to overlays (#729, #193)
2.1.0:
diff --git a/src/openseadragon.js b/src/openseadragon.js
index 07523516..94c7de6a 100644
--- a/src/openseadragon.js
+++ b/src/openseadragon.js
@@ -1337,6 +1337,49 @@ if (typeof define === 'function' && define.amd) {
return window.getComputedStyle( element, "" );
},
+ /**
+ * Returns the property with the correct vendor prefix appended.
+ * @param {String} property the property name
+ * @returns {String} the property with the correct prefix or null if not
+ * supported.
+ */
+ getCssPropertyWithVendorPrefix: function(property) {
+ var memo = {};
+
+ $.getCssPropertyWithVendorPrefix = function(property) {
+ if (memo[property] !== undefined) {
+ return memo[property];
+ }
+ var style = document.createElement('div').style;
+ var result = null;
+ if (style[property] !== undefined) {
+ result = property;
+ } else {
+ var prefixes = ['Webkit', 'Moz', 'MS', 'O',
+ 'webkit', 'moz', 'ms', 'o'];
+ var suffix = $.capitalizeFirstLetter(property);
+ for (var i = 0; i < prefixes.length; i++) {
+ var prop = prefixes[i] + suffix;
+ if (style[prop] !== undefined) {
+ result = prop;
+ break;
+ }
+ }
+ }
+ memo[property] = result;
+ return result;
+ };
+ return $.getCssPropertyWithVendorPrefix(property);
+ },
+
+ /**
+ * Capitalizes the first letter of a string
+ * @param {String} string
+ * @returns {String} The string with the first letter capitalized
+ */
+ capitalizeFirstLetter: function(string) {
+ return string.charAt(0).toUpperCase() + string.slice(1);
+ },
/**
* Determines if a point is within the bounding rectangle of the given element (hit-test).
diff --git a/src/overlay.js b/src/overlay.js
index 7e121950..76eb347c 100644
--- a/src/overlay.js
+++ b/src/overlay.js
@@ -32,7 +32,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-(function( $ ){
+(function($) {
/**
* An enumeration of positions that an overlay may be assigned relative to
@@ -55,6 +55,23 @@
*/
$.OverlayPlacement = $.Placement;
+ /**
+ * An enumeration of possible ways to handle overlays rotation
+ * @memberOf OpenSeadragon
+ * @static
+ * @property {Number} NO_ROTATION The overlay ignore the viewport rotation.
+ * @property {Number} EXACT The overlay use CSS 3 transforms to rotate with
+ * the viewport. If the overlay contains text, it will get rotated as well.
+ * @property {Number} BOUNDING_BOX The overlay adjusts for rotation by
+ * taking the size of the bounding box of the rotated bounds.
+ * Only valid for overlays with Rect location and scalable in both directions.
+ */
+ $.OverlayRotationMode = {
+ NO_ROTATION: 1,
+ EXACT: 2,
+ BOUNDING_BOX: 3
+ };
+
/**
* @class Overlay
* @classdesc Provides a way to float an HTML element on top of the viewer element.
@@ -64,19 +81,27 @@
* @param {Element} options.element
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location - The
* location of the overlay on the image. If a {@link OpenSeadragon.Point}
- * is specified, the overlay will keep a constant size independently of the
- * zoom. If a {@link OpenSeadragon.Rect} is specified, the overlay size will
- * be adjusted when the zoom changes.
+ * is specified, the overlay will be located at this location with respect
+ * to the placement option. If a {@link OpenSeadragon.Rect} is specified,
+ * the overlay will be placed at this location with the corresponding width
+ * and height and placement TOP_LEFT.
* @param {OpenSeadragon.Placement} [options.placement=OpenSeadragon.Placement.TOP_LEFT]
- * Relative position to the viewport.
- * Only used if location is a {@link OpenSeadragon.Point}.
+ * Defines what part of the overlay should be at the specified options.location
* @param {OpenSeadragon.Overlay.OnDrawCallback} [options.onDraw]
* @param {Boolean} [options.checkResize=true] Set to false to avoid to
- * check the size of the overlay everytime it is drawn when using a
- * {@link OpenSeadragon.Point} as options.location. It will improve
- * performances but will cause a misalignment if the overlay size changes.
+ * check the size of the overlay everytime it is drawn in the directions
+ * which are not scaled. It will improve performances but will cause a
+ * misalignment if the overlay size changes.
+ * @param {Number} [options.width] The width of the overlay in viewport
+ * coordinates. If specified, the width of the overlay will be adjusted when
+ * the zoom changes.
+ * @param {Number} [options.height] The height of the overlay in viewport
+ * coordinates. If specified, the height of the overlay will be adjusted when
+ * the zoom changes.
+ * @param {Boolean} [options.rotationMode=OpenSeadragon.OverlayRotationMode.EXACT]
+ * How to handle the rotation of the viewport.
*/
- $.Overlay = function( element, location, placement ) {
+ $.Overlay = function(element, location, placement) {
/**
* onDraw callback signature used by {@link OpenSeadragon.Overlay}.
@@ -89,7 +114,7 @@
*/
var options;
- if ( $.isPlainObject( element ) ) {
+ if ($.isPlainObject(element)) {
options = element;
} else {
options = {
@@ -99,35 +124,49 @@
};
}
- this.element = options.element;
- this.scales = options.location instanceof $.Rect;
- this.bounds = new $.Rect(
- options.location.x,
- options.location.y,
- options.location.width,
- options.location.height
- );
- this.position = new $.Point(
- options.location.x,
- options.location.y
- );
- this.size = new $.Point(
- options.location.width,
- options.location.height
- );
- this.style = options.element.style;
- // rects are always top-left
- this.placement = options.location instanceof $.Point ?
- options.placement : $.Placement.TOP_LEFT;
- this.onDraw = options.onDraw;
- this.checkResize = options.checkResize === undefined ?
- true : options.checkResize;
+ this.element = options.element;
+ this.style = options.element.style;
+ this._init(options);
};
/** @lends OpenSeadragon.Overlay.prototype */
$.Overlay.prototype = {
+ // private
+ _init: function(options) {
+ this.location = options.location;
+ this.placement = options.placement === undefined ?
+ $.Placement.TOP_LEFT : options.placement;
+ this.onDraw = options.onDraw;
+ this.checkResize = options.checkResize === undefined ?
+ true : options.checkResize;
+
+ // When this.width is not null, the overlay get scaled horizontally
+ this.width = options.width === undefined ? null : options.width;
+
+ // When this.height is not null, the overlay get scaled vertically
+ this.height = options.height === undefined ? null : options.height;
+
+ this.rotationMode = options.rotationMode || $.OverlayRotationMode.EXACT;
+
+ // Having a rect as location is a syntactic sugar
+ if (this.location instanceof $.Rect) {
+ this.width = this.location.width;
+ this.height = this.location.height;
+ this.location = this.location.getTopLeft();
+ this.placement = $.Placement.TOP_LEFT;
+ }
+
+ // Deprecated properties kept for backward compatibility.
+ this.scales = this.width !== null && this.height !== null;
+ this.bounds = new $.Rect(
+ this.location.x, this.location.y, this.width, this.height);
+ this.position = this.location;
+ },
+
/**
+ * Internal function to adjust the position of an overlay
+ * depending on it size and placement.
* @function
* @param {OpenSeadragon.Point} position
* @param {OpenSeadragon.Point} size
@@ -153,20 +192,20 @@
* @function
*/
destroy: function() {
- var element = this.element,
- style = this.style;
+ var element = this.element;
+ var style = this.style;
- if ( element.parentNode ) {
- element.parentNode.removeChild( element );
+ if (element.parentNode) {
+ element.parentNode.removeChild(element);
//this should allow us to preserve overlays when required between
//pages
- if ( element.prevElementParent ) {
+ if (element.prevElementParent) {
style.display = 'none';
//element.prevElementParent.insertBefore(
// element,
// element.prevNextSibling
//);
- document.body.appendChild( element );
+ document.body.appendChild(element);
}
}
@@ -177,121 +216,258 @@
style.left = "";
style.position = "";
- if ( this.scales ) {
+ if (this.width !== null) {
style.width = "";
+ }
+ if (this.height !== null) {
style.height = "";
}
+ var transformOriginProp = $.getCssPropertyWithVendorPrefix(
+ 'transformOrigin');
+ var transformProp = $.getCssPropertyWithVendorPrefix(
+ 'transform');
+ if (transformOriginProp && transformProp) {
+ style[transformOriginProp] = "";
+ style[transformProp] = "";
+ }
},
/**
* @function
* @param {Element} container
*/
- drawHTML: function( container, viewport ) {
- var element = this.element,
- style = this.style,
- scales = this.scales,
- degrees = viewport.degrees,
- position = viewport.pixelFromPoint(
- this.bounds.getTopLeft(),
- true
- ),
- size,
- overlayCenter;
-
- if ( element.parentNode != container ) {
+ drawHTML: function(container, viewport) {
+ var element = this.element;
+ if (element.parentNode !== container) {
//save the source parent for later if we need it
- element.prevElementParent = element.parentNode;
- element.prevNextSibling = element.nextSibling;
- container.appendChild( element );
- this.size = $.getElementSize( element );
+ element.prevElementParent = element.parentNode;
+ element.prevNextSibling = element.nextSibling;
+ container.appendChild(element);
+
+ // this.size is used by overlays which don't get scaled in at
+ // least one direction when this.checkResize is set to false.
+ this.size = $.getElementSize(element);
}
- if ( scales ) {
- size = viewport.deltaPixelsFromPoints(
- this.bounds.getSize(),
- true
- );
- } else if ( this.checkResize ) {
- size = $.getElementSize( element );
- } else {
- size = this.size;
- }
+ var positionAndSize = this._getOverlayPositionAndSize(viewport);
- this.position = position;
- this.size = size;
-
- this.adjust( position, size );
-
- position = position.apply( Math.round );
- size = size.apply( Math.round );
-
- // rotate the position of the overlay
- // TODO only rotate overlays if in canvas mode
- // TODO replace the size rotation with CSS3 transforms
- // TODO add an option to overlays to not rotate with the image
- // Currently only rotates position and size
- if( degrees !== 0 && this.scales ) {
- overlayCenter = new $.Point( size.x / 2, size.y / 2 );
-
- var drawerCenter = new $.Point(
- viewport.viewer.drawer.canvas.width / 2,
- viewport.viewer.drawer.canvas.height / 2
- );
- position = position.plus( overlayCenter ).rotate(
- degrees,
- drawerCenter
- ).minus( overlayCenter );
-
- size = size.rotate( degrees, new $.Point( 0, 0 ) );
- size = new $.Point( Math.abs( size.x ), Math.abs( size.y ) );
- }
+ var position = positionAndSize.position;
+ var size = this.size = positionAndSize.size;
+ var rotate = positionAndSize.rotate;
// call the onDraw callback if it exists to allow one to overwrite
// the drawing/positioning/sizing of the overlay
- if ( this.onDraw ) {
- this.onDraw( position, size, element );
+ if (this.onDraw) {
+ this.onDraw(position, size, this.element);
} else {
- style.left = position.x + "px";
- style.top = position.y + "px";
+ var style = this.style;
+ style.left = position.x + "px";
+ style.top = position.y + "px";
+ if (this.width !== null) {
+ style.width = size.x + "px";
+ }
+ if (this.height !== null) {
+ style.height = size.y + "px";
+ }
+ var transformOriginProp = $.getCssPropertyWithVendorPrefix(
+ 'transformOrigin');
+ var transformProp = $.getCssPropertyWithVendorPrefix(
+ 'transform');
+ if (transformOriginProp && transformProp) {
+ if (rotate) {
+ style[transformOriginProp] = this._getTransformOrigin();
+ style[transformProp] = "rotate(" + rotate + "deg)";
+ } else {
+ style[transformOriginProp] = "";
+ style[transformProp] = "";
+ }
+ }
style.position = "absolute";
- if (style.display != 'none') {
- style.display = 'block';
- }
-
- if ( scales ) {
- style.width = size.x + "px";
- style.height = size.y + "px";
+ if (style.display !== 'none') {
+ style.display = 'block';
}
}
},
- /**
- * @function
- * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location
- * @param {OpenSeadragon.Placement} position
- */
- update: function( location, placement ) {
- this.scales = location instanceof $.Rect;
- this.bounds = new $.Rect(
- location.x,
- location.y,
- location.width,
- location.height
- );
- // rects are always top-left
- this.placement = location instanceof $.Point ?
- placement : $.Placement.TOP_LEFT;
+ // private
+ _getOverlayPositionAndSize: function(viewport) {
+ var position = viewport.pixelFromPoint(this.location, true);
+ var size = this._getSizeInPixels(viewport);
+ this.adjust(position, size);
+
+ var rotate = 0;
+ if (viewport.degrees &&
+ this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) {
+ // BOUNDING_BOX is only valid if both directions get scaled.
+ // Get replaced by EXACT otherwise.
+ if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX &&
+ this.width !== null && this.height !== null) {
+ var rect = new $.Rect(position.x, position.y, size.x, size.y);
+ var boundingBox = this._getBoundingBox(rect, viewport.degrees);
+ position = boundingBox.getTopLeft();
+ size = boundingBox.getSize();
+ } else {
+ rotate = viewport.degrees;
+ }
+ }
+
+ return {
+ position: position,
+ size: size,
+ rotate: rotate
+ };
+ },
+
+ // private
+ _getSizeInPixels: function(viewport) {
+ var width = this.size.x;
+ var height = this.size.y;
+ if (this.width !== null || this.height !== null) {
+ var scaledSize = viewport.deltaPixelsFromPointsNoRotate(
+ new $.Point(this.width || 0, this.height || 0), true);
+ if (this.width !== null) {
+ width = scaledSize.x;
+ }
+ if (this.height !== null) {
+ height = scaledSize.y;
+ }
+ }
+ if (this.checkResize &&
+ (this.width === null || this.height === null)) {
+ var eltSize = this.size = $.getElementSize(this.element);
+ if (this.width === null) {
+ width = eltSize.x;
+ }
+ if (this.height === null) {
+ height = eltSize.y;
+ }
+ }
+ return new $.Point(width, height);
+ },
+
+ // private
+ _getBoundingBox: function(rect, degrees) {
+ 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) {
+ result.x += rect.width / 2;
+ } else if (properties.isRight) {
+ result.x += rect.width;
+ }
+ if (properties.isVerticallyCentered) {
+ result.y += rect.height / 2;
+ } else if (properties.isBottom) {
+ result.y += rect.height;
+ }
+ }
+ return result;
+ },
+
+ // private
+ _getTransformOrigin: function() {
+ var result = "";
+ var properties = $.Placement.properties[this.placement];
+ if (!properties) {
+ return result;
+ }
+ if (properties.isLeft) {
+ result = "left";
+ } else if (properties.isRight) {
+ result = "right";
+ }
+ if (properties.isTop) {
+ result += " top";
+ } else if (properties.isBottom) {
+ result += " bottom";
+ }
+ return result;
},
/**
+ * Changes the overlay settings.
* @function
+ * @param {OpenSeadragon.Point|OpenSeadragon.Rect|Object} location
+ * If an object is specified, the options are the same than the constructor
+ * except for the element which can not be changed.
+ * @param {OpenSeadragon.Placement} position
+ */
+ update: function(location, placement) {
+ var options = $.isPlainObject(location) ? location : {
+ location: location,
+ placement: placement
+ };
+ this._init({
+ location: options.location || this.location,
+ placement: options.placement !== undefined ?
+ options.placement : this.placement,
+ onDraw: options.onDraw || this.onDraw,
+ checkResize: options.checkResize || this.checkResize,
+ width: options.width !== undefined ? options.width : this.width,
+ height: options.height !== undefined ? options.height : this.height,
+ rotationMode: options.rotationMode || this.rotationMode
+ });
+ },
+
+ /**
+ * Returns the current bounds of the overlay in viewport coordinates
+ * @function
+ * @param {OpenSeadragon.Viewport} viewport the viewport
* @returns {OpenSeadragon.Rect} overlay bounds
*/
- getBounds: function() {
- return this.bounds.clone();
+ getBounds: function(viewport) {
+ $.console.assert(viewport,
+ 'A viewport must now be passed to Overlay.getBounds.');
+ var width = this.width;
+ var height = this.height;
+ if (width === null || height === null) {
+ var size = viewport.deltaPointsFromPixelsNoRotate(this.size, true);
+ if (width === null) {
+ width = size.x;
+ }
+ if (height === null) {
+ height = size.y;
+ }
+ }
+ var location = this.location.clone();
+ this.adjust(location, new $.Point(width, height));
+ return this._adjustBoundsForRotation(
+ viewport, new $.Rect(location.x, location.y, width, height));
+ },
+
+ // private
+ _adjustBoundsForRotation: function(viewport, bounds) {
+ if (!viewport ||
+ viewport.degrees === 0 ||
+ this.rotationMode === $.OverlayRotationMode.EXACT) {
+ return bounds;
+ }
+ if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX) {
+ // If overlay not fully scalable, BOUNDING_BOX falls back to EXACT
+ if (this.width === null || this.height === null) {
+ return bounds;
+ }
+ // It is easier to just compute the position and size and
+ // convert to viewport coordinates.
+ var positionAndSize = this._getOverlayPositionAndSize(viewport);
+ return viewport.viewerElementToViewportRectangle(new $.Rect(
+ positionAndSize.position.x,
+ positionAndSize.position.y,
+ positionAndSize.size.x,
+ positionAndSize.size.y));
+ }
+
+ // NO_ROTATION case
+ return bounds.rotate(-viewport.degrees,
+ this._getPlacementPoint(bounds));
}
};
-}( OpenSeadragon ));
+}(OpenSeadragon));
diff --git a/src/rectangle.js b/src/rectangle.js
index cae13e88..afe5da18 100644
--- a/src/rectangle.js
+++ b/src/rectangle.js
@@ -110,6 +110,33 @@ $.Rect = function(x, y, width, height, degrees) {
}
};
+/**
+ * Builds a rectangle having the 3 specified points as summits.
+ * @static
+ * @memberof OpenSeadragon.Rect
+ * @param {OpenSeadragon.Point} topLeft
+ * @param {OpenSeadragon.Point} topRight
+ * @param {OpenSeadragon.Point} bottomLeft
+ * @returns {OpenSeadragon.Rect}
+ */
+$.Rect.fromSummits = function(topLeft, topRight, bottomLeft) {
+ var width = topLeft.distanceTo(topRight);
+ var height = topLeft.distanceTo(bottomLeft);
+ var diff = topRight.minus(topLeft);
+ var radians = Math.atan(diff.y / diff.x);
+ if (diff.x < 0) {
+ radians += Math.PI;
+ } else if (diff.y < 0) {
+ radians += 2 * Math.PI;
+ }
+ return new $.Rect(
+ topLeft.x,
+ topLeft.y,
+ width,
+ height,
+ radians / Math.PI * 180);
+};
+
/** @lends OpenSeadragon.Rect.prototype */
$.Rect.prototype = {
/**
@@ -284,7 +311,7 @@ $.Rect.prototype = {
* Rotates a rectangle around a point.
* @function
* @param {Number} degrees The angle in degrees to rotate.
- * @param {OpenSeadragon.Point} pivot The point about which to rotate.
+ * @param {OpenSeadragon.Point} [pivot] The point about which to rotate.
* Defaults to the center of the rectangle.
* @return {OpenSeadragon.Rect}
*/
diff --git a/src/viewer.js b/src/viewer.js
index d3cce4b8..b2d6e5f2 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -1788,7 +1788,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
* is closed which include when changing page.
* @method
* @param {Element|String|Object} element - A reference to an element or an id for
- * the element which will be overlayed. Or an Object specifying the configuration for the overlay
+ * the element which will be overlayed. Or an Object specifying the configuration for the overlay.
+ * If using an object, see {@link OpenSeadragon.Overlay} for a list of
+ * all available options.
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or
* rectangle which will be overlayed. This is a viewport relative location.
* @param {OpenSeadragon.Placement} placement - The position of the
@@ -2199,32 +2201,23 @@ function getOverlayObject( viewer, overlay ) {
}
var location = overlay.location;
- if ( !location ) {
- if ( overlay.width && overlay.height ) {
- location = overlay.px !== undefined ?
- viewer.viewport.imageToViewportRectangle( new $.Rect(
- overlay.px,
- overlay.py,
- overlay.width,
- overlay.height
- ) ) :
- new $.Rect(
- overlay.x,
- overlay.y,
- overlay.width,
- overlay.height
- );
- } else {
- location = overlay.px !== undefined ?
- viewer.viewport.imageToViewportCoordinates( new $.Point(
- overlay.px,
- overlay.py
- ) ) :
- new $.Point(
- overlay.x,
- overlay.y
- );
+ var width = overlay.width;
+ var height = overlay.height;
+ if (!location) {
+ var x = overlay.x;
+ var y = overlay.y;
+ if (overlay.px !== undefined) {
+ var rect = viewer.viewport.imageToViewportRectangle(new $.Rect(
+ overlay.px,
+ overlay.py,
+ width || 0,
+ height || 0));
+ x = rect.x;
+ y = rect.y;
+ width = width !== undefined ? rect.width : undefined;
+ height = height !== undefined ? rect.height : undefined;
}
+ location = new $.Point(x, y);
}
var placement = overlay.placement;
@@ -2237,7 +2230,10 @@ function getOverlayObject( viewer, overlay ) {
location: location,
placement: placement,
onDraw: overlay.onDraw,
- checkResize: overlay.checkResize
+ checkResize: overlay.checkResize,
+ width: width,
+ height: height,
+ rotationMode: overlay.rotationMode
});
}
diff --git a/src/viewport.js b/src/viewport.js
index 6f418f13..a2a9cc26 100644
--- a/src/viewport.js
+++ b/src/viewport.js
@@ -1312,6 +1312,34 @@ $.Viewport.prototype = {
return this.pixelFromPoint( point, true );
},
+ /**
+ * Convert a rectangle in pixel coordinates relative to the viewer element
+ * to viewport coordinates.
+ * @param {OpenSeadragon.Rect} rectangle the rectangle to convert
+ * @returns {OpenSeadragon.Rect} the converted rectangle
+ */
+ viewerElementToViewportRectangle: function(rectangle) {
+ return $.Rect.fromSummits(
+ this.pointFromPixel(rectangle.getTopLeft(), true),
+ this.pointFromPixel(rectangle.getTopRight(), true),
+ this.pointFromPixel(rectangle.getBottomLeft(), true)
+ );
+ },
+
+ /**
+ * Convert a rectangle in viewport coordinates to pixel coordinates relative
+ * to the viewer element.
+ * @param {OpenSeadragon.Rect} rectangle the rectangle to convert
+ * @returns {OpenSeadragon.Rect} the converted rectangle
+ */
+ viewportToViewerElementRectangle: function(rectangle) {
+ return $.Rect.fromSummits(
+ this.pixelFromPoint(rectangle.getTopLeft(), true),
+ this.pixelFromPoint(rectangle.getTopRight(), true),
+ this.pixelFromPoint(rectangle.getBottomLeft(), true)
+ );
+ },
+
/**
* Convert pixel coordinates relative to the window to viewport coordinates.
* @param {OpenSeadragon.Point} pixel
diff --git a/test/demo/overlay.html b/test/demo/overlay.html
index a3be7724..527ebef3 100644
--- a/test/demo/overlay.html
+++ b/test/demo/overlay.html
@@ -14,7 +14,9 @@
-
+
+
+ 0deg
diff --git a/test/modules/overlays.js b/test/modules/overlays.js
index bb317050..76e91272 100644
--- a/test/modules/overlays.js
+++ b/test/modules/overlays.js
@@ -1,109 +1,111 @@
/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal, testLog */
-( function() {
+(function() {
var viewer;
+ // jQuery.position can give results quite different than what set in style.left
+ var epsilon = 1;
- module( "Overlays", {
+ module("Overlays", {
setup: function() {
- var example = $( '' ).appendTo( "#qunit-fixture" );
- var fixedOverlay = $( '' ).appendTo( example );
- fixedOverlay.width( 70 );
- fixedOverlay.height( 60 );
+ var example = $('').appendTo("#qunit-fixture");
+ var fixedOverlay = $('').appendTo(example);
+ fixedOverlay.width(70);
+ fixedOverlay.height(60);
testLog.reset();
},
teardown: function() {
resetTestVariables();
}
- } );
+ });
var resetTestVariables = function() {
- if ( viewer ) {
+ if (viewer) {
viewer.close();
}
};
- function waitForViewer( handler, count ) {
- if ( typeof count !== "number" ) {
+ function waitForViewer(handler, count) {
+ if (typeof count !== "number") {
count = 0;
}
var ready = viewer.isOpen() &&
viewer.drawer !== null &&
!viewer.world.needsDraw() &&
- Util.equalsWithVariance( viewer.viewport.getBounds( true ).x,
- viewer.viewport.getBounds().x, 0.000 ) &&
- Util.equalsWithVariance( viewer.viewport.getBounds( true ).y,
- viewer.viewport.getBounds().y, 0.000 ) &&
- Util.equalsWithVariance( viewer.viewport.getBounds( true ).width,
- viewer.viewport.getBounds().width, 0.000 );
+ Util.equalsWithVariance(viewer.viewport.getBounds(true).x,
+ viewer.viewport.getBounds().x, 0.000) &&
+ Util.equalsWithVariance(viewer.viewport.getBounds(true).y,
+ viewer.viewport.getBounds().y, 0.000) &&
+ Util.equalsWithVariance(viewer.viewport.getBounds(true).width,
+ viewer.viewport.getBounds().width, 0.000);
- if ( ready ) {
+ if (ready) {
handler();
- } else if ( count < 50 ) {
+ } else if (count < 50) {
count++;
- setTimeout( function() {
- waitForViewer( handler, count );
- }, 100 );
+ setTimeout(function() {
+ waitForViewer(handler, count);
+ }, 100);
} else {
- console.log( "waitForViewer:" + viewer.isOpen( ) + ":" + viewer.drawer +
- ":" + viewer.world.needsDraw() );
+ console.log("waitForViewer:" + viewer.isOpen( ) + ":" + viewer.drawer +
+ ":" + viewer.world.needsDraw());
handler();
}
}
- asyncTest( 'Overlays via viewer options', function() {
+ asyncTest('Overlays via viewer options', function() {
- viewer = OpenSeadragon( {
+ viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
- tileSources: [ '/test/data/testpattern.dzi', '/test/data/testpattern.dzi' ],
+ tileSources: ['/test/data/testpattern.dzi', '/test/data/testpattern.dzi'],
springStiffness: 100, // Faster animation = faster tests
- overlays: [ {
+ overlays: [{
x: 0.1,
y: 0.4,
width: 0.09,
height: 0.09,
id: "overlay"
- } ]
- } );
- viewer.addHandler( 'open', openHandler );
+ }]
+ });
+ viewer.addHandler('open', openHandler);
function openHandler() {
- viewer.removeHandler( 'open', openHandler );
+ viewer.removeHandler('open', openHandler);
- equal( viewer.overlays.length, 1, "Global overlay should be added." );
- equal( viewer.currentOverlays.length, 1, "Global overlay should be open." );
+ equal(viewer.overlays.length, 1, "Global overlay should be added.");
+ equal(viewer.currentOverlays.length, 1, "Global overlay should be open.");
- viewer.addHandler( 'open', openPageHandler );
- viewer.goToPage( 1 );
+ viewer.addHandler('open', openPageHandler);
+ viewer.goToPage(1);
}
function openPageHandler() {
- viewer.removeHandler( 'open', openPageHandler );
+ viewer.removeHandler('open', openPageHandler);
- equal( viewer.overlays.length, 1, "Global overlay should stay after page switch." );
- equal( viewer.currentOverlays.length, 1, "Global overlay should re-open after page switch." );
+ equal(viewer.overlays.length, 1, "Global overlay should stay after page switch.");
+ equal(viewer.currentOverlays.length, 1, "Global overlay should re-open after page switch.");
- viewer.addHandler( 'close', closeHandler );
+ viewer.addHandler('close', closeHandler);
viewer.close();
}
function closeHandler() {
- viewer.removeHandler( 'close', closeHandler );
+ viewer.removeHandler('close', closeHandler);
- equal( viewer.overlays.length, 1, "Global overlay should not be removed on close." );
- equal( viewer.currentOverlays.length, 0, "Global overlay should be closed on close." );
+ equal(viewer.overlays.length, 1, "Global overlay should not be removed on close.");
+ equal(viewer.currentOverlays.length, 0, "Global overlay should be closed on close.");
start();
}
- } );
+ });
- asyncTest( 'Page Overlays via viewer options', function() {
+ asyncTest('Page Overlays via viewer options', function() {
- viewer = OpenSeadragon( {
+ viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
- tileSources: [ {
+ tileSources: [{
Image: {
xmlns: "http://schemas.microsoft.com/deepzoom/2008",
Url: "/test/data/testpattern_files/",
@@ -115,13 +117,13 @@
Height: 1000
}
},
- overlays: [ {
+ overlays: [{
x: 0.1,
y: 0.4,
width: 0.09,
height: 0.09,
id: "overlay"
- } ]
+ }]
}, {
Image: {
xmlns: "http://schemas.microsoft.com/deepzoom/2008",
@@ -134,96 +136,96 @@
Height: 1000
}
}
- } ],
+ }],
springStiffness: 100 // Faster animation = faster tests
- } );
- viewer.addHandler( 'open', openHandler );
+ });
+ viewer.addHandler('open', openHandler);
function openHandler() {
- viewer.removeHandler( 'open', openHandler );
+ viewer.removeHandler('open', openHandler);
- equal( viewer.overlays.length, 0, "No global overlay should be added." );
- equal( viewer.currentOverlays.length, 1, "Page overlay should be open." );
+ equal(viewer.overlays.length, 0, "No global overlay should be added.");
+ equal(viewer.currentOverlays.length, 1, "Page overlay should be open.");
- viewer.addHandler( 'open', openPageHandler );
- viewer.goToPage( 1 );
+ viewer.addHandler('open', openPageHandler);
+ viewer.goToPage(1);
}
function openPageHandler() {
- viewer.removeHandler( 'open', openPageHandler );
+ viewer.removeHandler('open', openPageHandler);
- equal( viewer.overlays.length, 0, "No global overlay should be added after page switch." );
- equal( viewer.currentOverlays.length, 0, "No page overlay should be opened after page switch." );
+ equal(viewer.overlays.length, 0, "No global overlay should be added after page switch.");
+ equal(viewer.currentOverlays.length, 0, "No page overlay should be opened after page switch.");
- viewer.addHandler( 'close', closeHandler );
+ viewer.addHandler('close', closeHandler);
viewer.close();
}
function closeHandler() {
- viewer.removeHandler( 'close', closeHandler );
+ viewer.removeHandler('close', closeHandler);
- equal( viewer.overlays.length, 0, "No global overlay should be added on close." );
- equal( viewer.currentOverlays.length, 0, "Page overlay should be closed on close." );
+ equal(viewer.overlays.length, 0, "No global overlay should be added on close.");
+ equal(viewer.currentOverlays.length, 0, "Page overlay should be closed on close.");
start();
}
- } );
+ });
- asyncTest( 'Overlays via addOverlay method', function() {
+ asyncTest('Overlays via addOverlay method', function() {
- viewer = OpenSeadragon( {
+ viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
- tileSources: [ '/test/data/testpattern.dzi', '/test/data/testpattern.dzi' ],
+ tileSources: ['/test/data/testpattern.dzi', '/test/data/testpattern.dzi'],
springStiffness: 100 // Faster animation = faster tests
- } );
- viewer.addHandler( 'open', openHandler );
+ });
+ viewer.addHandler('open', openHandler);
function openHandler() {
- viewer.removeHandler( 'open', openHandler );
+ viewer.removeHandler('open', openHandler);
- equal( viewer.overlays.length, 0, "No global overlay should be added." );
- equal( viewer.currentOverlays.length, 0, "No overlay should be open." );
+ equal(viewer.overlays.length, 0, "No global overlay should be added.");
+ equal(viewer.currentOverlays.length, 0, "No overlay should be open.");
- var rect = new OpenSeadragon.Rect( 0.1, 0.1, 0.1, 0.1 );
- var overlay = $( "" ).prop( "id", "overlay" ).get( 0 );
- viewer.addOverlay( overlay, rect );
- equal( viewer.overlays.length, 0, "No manual overlay should be added as global overlay." );
- equal( viewer.currentOverlays.length, 1, "A manual overlay should be open." );
+ var rect = new OpenSeadragon.Rect(0.1, 0.1, 0.1, 0.1);
+ var overlay = $("").prop("id", "overlay").get(0);
+ viewer.addOverlay(overlay, rect);
+ equal(viewer.overlays.length, 0, "No manual overlay should be added as global overlay.");
+ equal(viewer.currentOverlays.length, 1, "A manual overlay should be open.");
- viewer.addHandler( 'open', openPageHandler );
- viewer.goToPage( 1 );
+ viewer.addHandler('open', openPageHandler);
+ viewer.goToPage(1);
}
function openPageHandler() {
- viewer.removeHandler( 'open', openPageHandler );
+ viewer.removeHandler('open', openPageHandler);
- equal( viewer.overlays.length, 0, "No global overlay should be added after page switch." );
- equal( viewer.currentOverlays.length, 0, "Manual overlay should be removed after page switch." );
+ equal(viewer.overlays.length, 0, "No global overlay should be added after page switch.");
+ equal(viewer.currentOverlays.length, 0, "Manual overlay should be removed after page switch.");
- viewer.addHandler( 'close', closeHandler );
+ viewer.addHandler('close', closeHandler);
viewer.close();
}
function closeHandler() {
- viewer.removeHandler( 'close', closeHandler );
+ viewer.removeHandler('close', closeHandler);
- equal( viewer.overlays.length, 0, "No global overlay should be added on close." );
- equal( viewer.currentOverlays.length, 0, "Manual overlay should be removed on close." );
+ equal(viewer.overlays.length, 0, "No global overlay should be added on close.");
+ equal(viewer.currentOverlays.length, 0, "Manual overlay should be removed on close.");
start();
}
- } );
+ });
- asyncTest( 'Overlays size in pixels', function() {
+ asyncTest('Overlays size in pixels', function() {
- viewer = OpenSeadragon( {
+ viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
- overlays: [ {
+ overlays: [{
px: 13,
py: 120,
width: 124,
@@ -234,60 +236,68 @@
py: 500,
id: "fixed-overlay",
placement: "TOP_LEFT"
- } ]
- } );
+ }]
+ });
- function checkOverlayPosition( contextMessage ) {
+ function checkOverlayPosition(contextMessage) {
var viewport = viewer.viewport;
var expPosition = viewport.imageToViewerElementCoordinates(
- new OpenSeadragon.Point( 13, 120 ) ).apply( Math.round );
- var actPosition = $( "#overlay" ).position();
- equal( actPosition.left, expPosition.x, "X position mismatch " + contextMessage );
- equal( actPosition.top, expPosition.y, "Y position mismatch " + contextMessage );
+ new OpenSeadragon.Point(13, 120));
+ var actPosition = $("#overlay").position();
+ Util.assessNumericValue(actPosition.left, expPosition.x, epsilon,
+ "X position mismatch " + contextMessage);
+ Util.assessNumericValue(actPosition.top, expPosition.y, epsilon,
+ "Y position mismatch " + contextMessage);
- var zoom = viewport.viewportToImageZoom( viewport.getZoom( true ) );
- var expectedWidth = Math.round( 124 * zoom );
- var expectedHeight = Math.round( 132 * zoom );
- equal( $( "#overlay" ).width(), expectedWidth, "Width mismatch " + contextMessage );
- equal( $( "#overlay" ).height( ), expectedHeight, "Height mismatch " + contextMessage );
+ var zoom = viewport.viewportToImageZoom(viewport.getZoom(true));
+ var expectedWidth = 124 * zoom;
+ var expectedHeight = 132 * zoom;
+ Util.assessNumericValue($("#overlay").width(), expectedWidth, epsilon,
+ "Width mismatch " + contextMessage);
+ Util.assessNumericValue($("#overlay").height(), expectedHeight, epsilon,
+ "Height mismatch " + contextMessage);
expPosition = viewport.imageToViewerElementCoordinates(
- new OpenSeadragon.Point( 400, 500 ) ).apply( Math.round );
- actPosition = $( "#fixed-overlay" ).position();
- equal( actPosition.left, expPosition.x, "Fixed overlay X position mismatch " + contextMessage );
- equal( actPosition.top, expPosition.y, "Fixed overlay Y position mismatch " + contextMessage );
+ new OpenSeadragon.Point(400, 500));
+ actPosition = $("#fixed-overlay").position();
+ Util.assessNumericValue(actPosition.left, expPosition.x, epsilon,
+ "Fixed overlay X position mismatch " + contextMessage);
+ Util.assessNumericValue(actPosition.top, expPosition.y, epsilon,
+ "Fixed overlay Y position mismatch " + contextMessage);
- equal( $( "#fixed-overlay" ).width(), 70, "Fixed overlay width mismatch " + contextMessage );
- equal( $( "#fixed-overlay" ).height( ), 60, "Fixed overlay height mismatch " + contextMessage );
+ Util.assessNumericValue($("#fixed-overlay").width(), 70, epsilon,
+ "Fixed overlay width mismatch " + contextMessage);
+ Util.assessNumericValue($("#fixed-overlay").height(), 60, epsilon,
+ "Fixed overlay height mismatch " + contextMessage);
}
- waitForViewer( function() {
- checkOverlayPosition( "after opening using image coordinates" );
+ waitForViewer(function() {
+ checkOverlayPosition("after opening using image coordinates");
- viewer.viewport.zoomBy( 1.1 ).panBy( new OpenSeadragon.Point( 0.1, 0.2 ) );
- waitForViewer( function() {
- checkOverlayPosition( "after zoom and pan using image coordinates" );
+ viewer.viewport.zoomBy(1.1).panBy(new OpenSeadragon.Point(0.1, 0.2));
+ waitForViewer(function() {
+ checkOverlayPosition("after zoom and pan using image coordinates");
viewer.viewport.goHome();
- waitForViewer( function() {
- checkOverlayPosition( "after goHome using image coordinates" );
+ waitForViewer(function() {
+ checkOverlayPosition("after goHome using image coordinates");
start();
- } );
- } );
+ });
+ });
- } );
- } );
+ });
+ });
- asyncTest( 'Overlays size in points', function() {
+ asyncTest('Overlays size in points', function() {
- viewer = OpenSeadragon( {
+ viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
- overlays: [ {
+ overlays: [{
x: 0.2,
y: 0.1,
width: 0.5,
@@ -298,62 +308,70 @@
y: 0.6,
id: "fixed-overlay",
placement: "TOP_LEFT"
- } ]
- } );
+ }]
+ });
- function checkOverlayPosition( contextMessage ) {
+ function checkOverlayPosition(contextMessage) {
var viewport = viewer.viewport;
var expPosition = viewport.viewportToViewerElementCoordinates(
- new OpenSeadragon.Point( 0.2, 0.1 ) ).apply( Math.round );
- var actPosition = $( "#overlay" ).position();
- equal( actPosition.left, expPosition.x, "X position mismatch " + contextMessage );
- equal( actPosition.top, expPosition.y, "Y position mismatch " + contextMessage );
+ new OpenSeadragon.Point(0.2, 0.1));
+ var actPosition = $("#overlay").position();
+ Util.assessNumericValue(actPosition.left, expPosition.x, epsilon,
+ "X position mismatch " + contextMessage);
+ Util.assessNumericValue(actPosition.top, expPosition.y, epsilon,
+ "Y position mismatch " + contextMessage);
var expectedSize = viewport.deltaPixelsFromPoints(
- new OpenSeadragon.Point( 0.5, 0.1 ) );
- equal( $( "#overlay" ).width(), expectedSize.x, "Width mismatch " + contextMessage );
- equal( $( "#overlay" ).height(), expectedSize.y, "Height mismatch " + contextMessage );
+ new OpenSeadragon.Point(0.5, 0.1));
+ Util.assessNumericValue($("#overlay").width(), expectedSize.x, epsilon,
+ "Width mismatch " + contextMessage);
+ Util.assessNumericValue($("#overlay").height(), expectedSize.y, epsilon,
+ "Height mismatch " + contextMessage);
expPosition = viewport.viewportToViewerElementCoordinates(
- new OpenSeadragon.Point( 0.5, 0.6 ) ).apply( Math.round );
- actPosition = $( "#fixed-overlay" ).position();
- equal( actPosition.left, expPosition.x, "Fixed overlay X position mismatch " + contextMessage );
- equal( actPosition.top, expPosition.y, "Fixed overlay Y position mismatch " + contextMessage );
+ new OpenSeadragon.Point(0.5, 0.6));
+ actPosition = $("#fixed-overlay").position();
+ Util.assessNumericValue(actPosition.left, expPosition.x, epsilon,
+ "Fixed overlay X position mismatch " + contextMessage);
+ Util.assessNumericValue(actPosition.top, expPosition.y, epsilon,
+ "Fixed overlay Y position mismatch " + contextMessage);
- equal( $( "#fixed-overlay" ).width(), 70, "Fixed overlay width mismatch " + contextMessage );
- equal( $( "#fixed-overlay" ).height( ), 60, "Fixed overlay height mismatch " + contextMessage );
+ Util.assessNumericValue($("#fixed-overlay").width(), 70, epsilon,
+ "Fixed overlay width mismatch " + contextMessage);
+ Util.assessNumericValue($("#fixed-overlay").height(), 60, epsilon,
+ "Fixed overlay height mismatch " + contextMessage);
}
- waitForViewer( function() {
- checkOverlayPosition( "after opening using viewport coordinates" );
+ waitForViewer(function() {
+ checkOverlayPosition("after opening using viewport coordinates");
- viewer.viewport.zoomBy( 1.1 ).panBy( new OpenSeadragon.Point( 0.1, 0.2 ) );
- waitForViewer( function() {
- checkOverlayPosition( "after zoom and pan using viewport coordinates" );
+ viewer.viewport.zoomBy(1.1).panBy(new OpenSeadragon.Point(0.1, 0.2));
+ waitForViewer(function() {
+ checkOverlayPosition("after zoom and pan using viewport coordinates");
viewer.viewport.goHome();
- waitForViewer( function() {
- checkOverlayPosition( "after goHome using viewport coordinates" );
+ waitForViewer(function() {
+ checkOverlayPosition("after goHome using viewport coordinates");
start();
- } );
- } );
+ });
+ });
- } );
- } );
+ });
+ });
- asyncTest( 'Overlays placement', function() {
+ asyncTest('Overlays placement', function() {
- var scalableOverlayLocation = new OpenSeadragon.Rect( 0.2, 0.1, 0.5, 0.1 );
- var fixedOverlayLocation = new OpenSeadragon.Point( 0.5, 0.6 );
+ var scalableOverlayLocation = new OpenSeadragon.Rect(0.2, 0.1, 0.5, 0.1);
+ var fixedOverlayLocation = new OpenSeadragon.Point(0.5, 0.6);
- viewer = OpenSeadragon( {
+ viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
- overlays: [ {
+ overlays: [{
x: scalableOverlayLocation.x,
y: scalableOverlayLocation.y,
width: scalableOverlayLocation.width,
@@ -365,204 +383,727 @@
y: fixedOverlayLocation.y,
id: "fixed-overlay",
placement: "TOP_LEFT"
- } ]
- } );
+ }]
+ });
// Scalable overlays are always TOP_LEFT
- function checkScalableOverlayPosition( contextMessage ) {
+ function checkScalableOverlayPosition(contextMessage) {
var viewport = viewer.viewport;
var expPosition = viewport.viewportToViewerElementCoordinates(
- new OpenSeadragon.Point( 0.2, 0.1 ) ).apply( Math.round );
- var actPosition = $( "#overlay" ).position();
- equal( actPosition.left, expPosition.x, "X position mismatch " + contextMessage );
- equal( actPosition.top, expPosition.y, "Y position mismatch " + contextMessage );
+ new OpenSeadragon.Point(0.2, 0.1));
+ var actPosition = $("#overlay").position();
+ Util.assessNumericValue(actPosition.left, expPosition.x, epsilon,
+ "X position mismatch " + contextMessage);
+ Util.assessNumericValue(actPosition.top, expPosition.y, epsilon,
+ "Y position mismatch " + contextMessage);
}
- function checkFixedOverlayPosition( expectedOffset, contextMessage ) {
+ function checkFixedOverlayPosition(expectedOffset, contextMessage) {
var viewport = viewer.viewport;
var expPosition = viewport.viewportToViewerElementCoordinates(
- new OpenSeadragon.Point( 0.5, 0.6 ) )
- .apply( Math.round )
- .plus( expectedOffset );
- var actPosition = $( "#fixed-overlay" ).position();
- equal( actPosition.left, expPosition.x, "Fixed overlay X position mismatch " + contextMessage );
- equal( actPosition.top, expPosition.y, "Fixed overlay Y position mismatch " + contextMessage );
+ new OpenSeadragon.Point(0.5, 0.6))
+ .plus(expectedOffset);
+ var actPosition = $("#fixed-overlay").position();
+ Util.assessNumericValue(actPosition.left, expPosition.x, epsilon,
+ "Fixed overlay X position mismatch " + contextMessage);
+ Util.assessNumericValue(actPosition.top, expPosition.y, epsilon,
+ "Fixed overlay Y position mismatch " + contextMessage);
}
- waitForViewer( function() {
+ waitForViewer(function() {
- checkScalableOverlayPosition( "with TOP_LEFT placement." );
- checkFixedOverlayPosition( new OpenSeadragon.Point( 0, 0 ),
- "with TOP_LEFT placement." );
+ checkScalableOverlayPosition("with TOP_LEFT placement.");
+ checkFixedOverlayPosition(new OpenSeadragon.Point(0, 0),
+ "with TOP_LEFT placement.");
// Check that legacy OpenSeadragon.OverlayPlacement is still working
- viewer.updateOverlay( "overlay", scalableOverlayLocation,
- OpenSeadragon.OverlayPlacement.CENTER );
- viewer.updateOverlay( "fixed-overlay", fixedOverlayLocation,
- OpenSeadragon.OverlayPlacement.CENTER );
+ viewer.updateOverlay("overlay", scalableOverlayLocation,
+ OpenSeadragon.OverlayPlacement.CENTER);
+ viewer.updateOverlay("fixed-overlay", fixedOverlayLocation,
+ OpenSeadragon.OverlayPlacement.CENTER);
- setTimeout( function() {
- checkScalableOverlayPosition( "with CENTER placement." );
- checkFixedOverlayPosition( new OpenSeadragon.Point( -35, -30 ),
- "with CENTER placement." );
+ setTimeout(function() {
+ checkScalableOverlayPosition("with CENTER placement.");
+ checkFixedOverlayPosition(new OpenSeadragon.Point(-35, -30),
+ "with CENTER placement.");
// Check that new OpenSeadragon.Placement is working
- viewer.updateOverlay( "overlay", scalableOverlayLocation,
- OpenSeadragon.Placement.BOTTOM_RIGHT );
- viewer.updateOverlay( "fixed-overlay", fixedOverlayLocation,
- OpenSeadragon.Placement.BOTTOM_RIGHT );
- setTimeout( function() {
- checkScalableOverlayPosition( "with BOTTOM_RIGHT placement." );
- checkFixedOverlayPosition( new OpenSeadragon.Point( -70, -60 ),
- "with BOTTOM_RIGHT placement." );
+ viewer.updateOverlay("overlay", scalableOverlayLocation,
+ OpenSeadragon.Placement.BOTTOM_RIGHT);
+ viewer.updateOverlay("fixed-overlay", fixedOverlayLocation,
+ OpenSeadragon.Placement.BOTTOM_RIGHT);
+ setTimeout(function() {
+ checkScalableOverlayPosition("with BOTTOM_RIGHT placement.");
+ checkFixedOverlayPosition(new OpenSeadragon.Point(-70, -60),
+ "with BOTTOM_RIGHT placement.");
start();
- }, 100 );
+ }, 100);
- }, 100 );
+ }, 100);
- } );
- } );
+ });
+ });
- asyncTest( 'Overlays placement and resizing check', function() {
+ asyncTest('Overlays placement and resizing check', function() {
- var fixedOverlayLocation = new OpenSeadragon.Point( 0.5, 0.6 );
+ var fixedOverlayLocation = new OpenSeadragon.Point(0.5, 0.6);
- viewer = OpenSeadragon( {
+ viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
- overlays: [ {
+ overlays: [{
x: fixedOverlayLocation.x,
y: fixedOverlayLocation.y,
id: "fixed-overlay",
placement: "CENTER",
checkResize: true
- } ]
- } );
+ }]
+ });
- function checkFixedOverlayPosition( expectedOffset, contextMessage ) {
+ function checkFixedOverlayPosition(expectedOffset, contextMessage) {
var viewport = viewer.viewport;
var expPosition = viewport.viewportToViewerElementCoordinates(
- new OpenSeadragon.Point( 0.5, 0.6 ) )
- .apply( Math.round )
- .plus( expectedOffset );
- var actPosition = $( "#fixed-overlay" ).position();
- equal( actPosition.left, expPosition.x, "Fixed overlay X position mismatch " + contextMessage );
- equal( actPosition.top, expPosition.y, "Fixed overlay Y position mismatch " + contextMessage );
+ new OpenSeadragon.Point(0.5, 0.6))
+ .plus(expectedOffset);
+ var actPosition = $("#fixed-overlay").position();
+ Util.assessNumericValue(actPosition.left, expPosition.x, epsilon,
+ "Fixed overlay X position mismatch " + contextMessage);
+ Util.assessNumericValue(actPosition.top, expPosition.y, epsilon,
+ "Fixed overlay Y position mismatch " + contextMessage);
}
- waitForViewer( function() {
- checkFixedOverlayPosition( new OpenSeadragon.Point( -35, -30 ),
- "with overlay of size 70,60." );
+ waitForViewer(function() {
+ checkFixedOverlayPosition(new OpenSeadragon.Point(-35, -30),
+ "with overlay of size 70,60.");
- $( "#fixed-overlay" ).width( 50 );
- $( "#fixed-overlay" ).height( 40 );
+ $("#fixed-overlay").width(50);
+ $("#fixed-overlay").height(40);
// The resizing of the overlays is not detected by the viewer's loop.
viewer.forceRedraw();
- setTimeout( function() {
- checkFixedOverlayPosition( new OpenSeadragon.Point( -25, -20 ),
- "with overlay of size 50,40." );
+ setTimeout(function() {
+ checkFixedOverlayPosition(new OpenSeadragon.Point(-25, -20),
+ "with overlay of size 50,40.");
// Restore original size
- $( "#fixed-overlay" ).width( 70 );
- $( "#fixed-overlay" ).height( 60 );
+ $("#fixed-overlay").width(70);
+ $("#fixed-overlay").height(60);
start();
- }, 100 );
- } );
+ }, 100);
+ });
- } );
+ });
- asyncTest( 'Overlays placement and no resizing check', function() {
+ asyncTest('Overlays placement and no resizing check', function() {
- var fixedOverlayLocation = new OpenSeadragon.Point( 0.5, 0.6 );
+ var fixedOverlayLocation = new OpenSeadragon.Point(0.5, 0.6);
- viewer = OpenSeadragon( {
+ viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
- overlays: [ {
+ overlays: [{
x: fixedOverlayLocation.x,
y: fixedOverlayLocation.y,
id: "fixed-overlay",
placement: "CENTER",
checkResize: false
- } ]
- } );
+ }]
+ });
- function checkFixedOverlayPosition( expectedOffset, contextMessage ) {
+ function checkFixedOverlayPosition(expectedOffset, contextMessage) {
var viewport = viewer.viewport;
var expPosition = viewport.viewportToViewerElementCoordinates(
- new OpenSeadragon.Point( 0.5, 0.6 ) )
- .apply( Math.round )
- .plus( expectedOffset );
- var actPosition = $( "#fixed-overlay" ).position();
- equal( actPosition.left, expPosition.x, "Fixed overlay X position mismatch " + contextMessage );
- equal( actPosition.top, expPosition.y, "Fixed overlay Y position mismatch " + contextMessage );
+ new OpenSeadragon.Point(0.5, 0.6))
+ .plus(expectedOffset);
+ var actPosition = $("#fixed-overlay").position();
+ Util.assessNumericValue(actPosition.left, expPosition.x, epsilon,
+ "Fixed overlay X position mismatch " + contextMessage);
+ Util.assessNumericValue(actPosition.top, expPosition.y, epsilon,
+ "Fixed overlay Y position mismatch " + contextMessage);
}
- waitForViewer( function() {
- checkFixedOverlayPosition( new OpenSeadragon.Point( -35, -30 ),
- "with overlay of size 70,60." );
+ waitForViewer(function() {
+ checkFixedOverlayPosition(new OpenSeadragon.Point(-35, -30),
+ "with overlay of size 70,60.");
- $( "#fixed-overlay" ).width( 50 );
- $( "#fixed-overlay" ).height( 40 );
+ $("#fixed-overlay").width(50);
+ $("#fixed-overlay").height(40);
// The resizing of the overlays is not detected by the viewer's loop.
viewer.forceRedraw();
- setTimeout( function() {
- checkFixedOverlayPosition( new OpenSeadragon.Point( -35, -30 ),
- "with overlay of size 50,40." );
+ setTimeout(function() {
+ checkFixedOverlayPosition(new OpenSeadragon.Point(-35, -30),
+ "with overlay of size 50,40.");
// Restore original size
- $( "#fixed-overlay" ).width( 70 );
- $( "#fixed-overlay" ).height( 60 );
+ $("#fixed-overlay").width(70);
+ $("#fixed-overlay").height(60);
start();
- }, 100 );
- } );
+ }, 100);
+ });
- } );
+ });
// ----------
asyncTest('overlays appear immediately', function() {
equal($('#immediate-overlay0').length, 0, 'overlay 0 does not exist');
equal($('#immediate-overlay1').length, 0, 'overlay 1 does not exist');
- viewer = OpenSeadragon( {
+ viewer = OpenSeadragon({
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
- overlays: [ {
+ overlays: [{
x: 0,
y: 0,
id: "immediate-overlay0"
- } ]
- } );
+ }]
+ });
viewer.addHandler('open', function() {
equal($('#immediate-overlay0').length, 1, 'overlay 0 exists');
- viewer.addOverlay( {
+ viewer.addOverlay({
x: 0,
y: 0,
id: "immediate-overlay1"
- } );
+ });
equal($('#immediate-overlay1').length, 1, 'overlay 1 exists');
start();
});
});
-} )( );
+ // ----------
+ asyncTest('Overlay scaled horizontally only', function() {
+ viewer = OpenSeadragon({
+ id: 'example-overlays',
+ prefixUrl: '/build/openseadragon/images/',
+ tileSources: '/test/data/testpattern.dzi',
+ springStiffness: 100 // Faster animation = faster tests
+ });
+
+ viewer.addHandler('open', function() {
+ viewer.addOverlay({
+ id: "horizontally-scaled-overlay",
+ x: 0,
+ y: 0,
+ width: 1
+ });
+
+ var width = $("#horizontally-scaled-overlay").width();
+ var height = 100;
+ var zoom = 1.1;
+ $("#horizontally-scaled-overlay").get(0).style.height = height + "px";
+
+ viewer.viewport.zoomBy(zoom);
+
+ waitForViewer(function() {
+ var newWidth = $("#horizontally-scaled-overlay").width();
+ var newHeight = $("#horizontally-scaled-overlay").height();
+ equal(newWidth, width * zoom, "Width should be scaled.");
+ equal(newHeight, height, "Height should not be scaled.");
+
+ start();
+ });
+ });
+ });
+
+ // ----------
+ asyncTest('Overlay scaled vertically only', function() {
+ viewer = OpenSeadragon({
+ id: 'example-overlays',
+ prefixUrl: '/build/openseadragon/images/',
+ tileSources: '/test/data/testpattern.dzi',
+ springStiffness: 100 // Faster animation = faster tests
+ });
+
+ viewer.addHandler('open', function() {
+ viewer.addOverlay({
+ id: "vertically-scaled-overlay",
+ x: 0,
+ y: 0,
+ height: 1
+ });
+
+ var width = 100;
+ var height = $("#vertically-scaled-overlay").height();
+ var zoom = 1.1;
+ $("#vertically-scaled-overlay").get(0).style.width = width + "px";
+
+ viewer.viewport.zoomBy(zoom);
+
+ waitForViewer(function() {
+ var newWidth = $("#vertically-scaled-overlay").width();
+ var newHeight = $("#vertically-scaled-overlay").height();
+ equal(newWidth, width, "Width should not be scaled.");
+ equal(newHeight, height * zoom, "Height should be scaled.");
+
+ start();
+ });
+ });
+ });
+
+ // ----------
+ asyncTest('Overlay.getBounds', function() {
+ viewer = OpenSeadragon({
+ id: 'example-overlays',
+ prefixUrl: '/build/openseadragon/images/',
+ tileSources: '/test/data/testpattern.dzi',
+ springStiffness: 100 // Faster animation = faster tests
+ });
+
+ viewer.addHandler('open', function() {
+ viewer.addOverlay({
+ id: "fully-scaled-overlay",
+ x: 1,
+ y: 1,
+ width: 1,
+ height: 1,
+ placement: OpenSeadragon.Placement.BOTTOM_RIGHT
+ });
+ viewer.addOverlay({
+ id: "horizontally-scaled-overlay",
+ x: 0.5,
+ y: 0.5,
+ width: 1,
+ placement: OpenSeadragon.Placement.CENTER
+ });
+ viewer.addOverlay({
+ id: "vertically-scaled-overlay",
+ x: 0,
+ y: 0.5,
+ height: 1,
+ placement: OpenSeadragon.Placement.LEFT
+ });
+ viewer.addOverlay({
+ id: "not-scaled-overlay",
+ x: 1,
+ y: 0,
+ placement: OpenSeadragon.Placement.TOP_RIGHT
+ });
+
+ var notScaledWidth = 100;
+ var notScaledHeight = 100;
+ $("#horizontally-scaled-overlay").get(0).style.height = notScaledHeight + "px";
+ $("#vertically-scaled-overlay").get(0).style.width = notScaledWidth + "px";
+ $("#not-scaled-overlay").get(0).style.width = notScaledWidth + "px";
+ $("#not-scaled-overlay").get(0).style.height = notScaledHeight + "px";
+
+ var notScaledSize = viewer.viewport.deltaPointsFromPixelsNoRotate(
+ new OpenSeadragon.Point(notScaledWidth, notScaledHeight));
+
+ // Force refresh to takes new dimensions into account.
+ viewer._drawOverlays();
+
+ var actualBounds = viewer.getOverlayById("fully-scaled-overlay")
+ .getBounds(viewer.viewport);
+ var expectedBounds = new OpenSeadragon.Rect(0, 0, 1, 1);
+ ok(expectedBounds.equals(actualBounds),
+ "The fully scaled overlay should have bounds " +
+ expectedBounds + " but found " + actualBounds);
+
+
+ actualBounds = viewer.getOverlayById("horizontally-scaled-overlay")
+ .getBounds(viewer.viewport);
+ expectedBounds = new OpenSeadragon.Rect(
+ 0, 0.5 - notScaledSize.y / 2, 1, notScaledSize.y);
+ ok(expectedBounds.equals(actualBounds),
+ "The horizontally scaled overlay should have bounds " +
+ expectedBounds + " but found " + actualBounds);
+
+ actualBounds = viewer.getOverlayById("vertically-scaled-overlay")
+ .getBounds(viewer.viewport);
+ expectedBounds = new OpenSeadragon.Rect(
+ 0, 0, notScaledSize.x, 1);
+ ok(expectedBounds.equals(actualBounds),
+ "The vertically scaled overlay should have bounds " +
+ expectedBounds + " but found " + actualBounds);
+
+ actualBounds = viewer.getOverlayById("not-scaled-overlay")
+ .getBounds(viewer.viewport);
+ expectedBounds = new OpenSeadragon.Rect(
+ 1 - notScaledSize.x, 0, notScaledSize.x, notScaledSize.y);
+ ok(expectedBounds.equals(actualBounds),
+ "The not scaled overlay should have bounds " +
+ expectedBounds + " but found " + actualBounds);
+
+ start();
+ });
+ });
+
+ // ----------
+ 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 + " 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 + " 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 + " 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 + " but found " + actualBounds);
+
+ start();
+ });
+ });
+
+ // ----------
+ asyncTest('Fully scaled overlay rotation mode BOUNDING_BOX', 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.BOUNDING_BOX
+ }]
+ });
+
+ viewer.addOnceHandler('open', function() {
+ var viewport = viewer.viewport;
+
+ var $overlay = $("#fully-scaled-overlay");
+ var expectedRect = viewport.viewportToViewerElementRectangle(
+ new OpenSeadragon.Rect(0, 0, 1, 1)).getBoundingBox();
+ var actualPosition = $overlay.position();
+ Util.assessNumericValue(actualPosition.left, expectedRect.x, epsilon,
+ "Scaled overlay position.x should adjust to rotation.");
+ Util.assessNumericValue(actualPosition.top, expectedRect.y, epsilon,
+ "Scaled overlay position.y should adjust to rotation.");
+
+ var actualWidth = $overlay.width();
+ var actualHeight = $overlay.height();
+ Util.assessNumericValue(actualWidth, expectedRect.width, epsilon,
+ "Scaled overlay width should not adjust to rotation.");
+ Util.assessNumericValue(actualHeight, expectedRect.height, epsilon,
+ "Scaled overlay height should not adjust to rotation.");
+
+ var actualBounds = viewer.getOverlayById("fully-scaled-overlay")
+ .getBounds(viewport);
+ var expectedBounds = new OpenSeadragon.Rect(
+ 0.5, -0.5, Math.sqrt(2), Math.sqrt(2), 45);
+ var boundsEpsilon = 0.000001;
+ Util.assessNumericValue(actualBounds.x, expectedBounds.x, boundsEpsilon,
+ "The fully scaled overlay should have adjusted bounds.x");
+ Util.assessNumericValue(actualBounds.y, expectedBounds.y, boundsEpsilon,
+ "The fully scaled overlay should have adjusted bounds.y");
+ Util.assessNumericValue(actualBounds.width, expectedBounds.width, boundsEpsilon,
+ "The fully scaled overlay should have adjusted bounds.width");
+ Util.assessNumericValue(actualBounds.height, expectedBounds.height, boundsEpsilon,
+ "The fully scaled overlay should have adjusted bounds.height");
+ Util.assessNumericValue(actualBounds.degrees, expectedBounds.degrees, boundsEpsilon,
+ "The fully scaled overlay should have adjusted bounds.degrees");
+
+ start();
+ });
+ });
+
+ // ----------
+ asyncTest('Fully scaled overlay rotation mode EXACT', 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.EXACT
+ }]
+ });
+
+ 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.pixelFromPoint(
+ new OpenSeadragon.Point(1, 1))
+ .minus(expectedSize);
+ // We can't rely on jQuery.position with transforms.
+ var actualStyle = $overlay.get(0).style;
+ var left = Number(actualStyle.left.replace("px", ""));
+ var top = Number(actualStyle.top.replace("px", ""));
+ Util.assessNumericValue(left, expectedPosition.x, epsilon,
+ "Scaled overlay position.x should adjust to rotation.");
+ Util.assessNumericValue(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 transformOriginProp = OpenSeadragon.getCssPropertyWithVendorPrefix(
+ 'transformOrigin');
+ var transformProp = OpenSeadragon.getCssPropertyWithVendorPrefix(
+ 'transform');
+ var transformOrigin = actualStyle[transformOriginProp];
+ // Some browsers replace "right bottom" by "100% 100%"
+ ok(transformOrigin.match(/(100% 100%)|(right bottom)/),
+ "Transform origin should be right bottom. Got: " + transformOrigin);
+ equal(actualStyle[transformProp], "rotate(45deg)",
+ "Transform should be rotate(45deg).");
+
+ var actualBounds = viewer.getOverlayById("fully-scaled-overlay")
+ .getBounds(viewport);
+ var expectedBounds = new OpenSeadragon.Rect(0, 0, 1, 1);
+ ok(expectedBounds.equals(actualBounds),
+ "The fully scaled overlay should have bounds " +
+ expectedBounds + " but found " + actualBounds);
+
+ start();
+ });
+ });
+})();