Add overlays rotation support.

This commit is contained in:
Antoine Vandecreme 2016-03-28 17:06:59 -04:00
parent 3e3ce188b1
commit cac5f6dec3
2 changed files with 82 additions and 9 deletions

View File

@ -55,6 +55,23 @@
*/ */
$.OverlayPlacement = $.Placement; $.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 * @class Overlay
* @classdesc Provides a way to float an HTML element on top of the viewer element. * @classdesc Provides a way to float an HTML element on top of the viewer element.
@ -81,6 +98,8 @@
* @param {Boolean} [options.scaleHeight=true] Whether the height of the * @param {Boolean} [options.scaleHeight=true] Whether the height of the
* overlay should be adjusted when the zoom changes when using a * overlay should be adjusted when the zoom changes when using a
* {@link OpenSeadragon.Rect} as options.location * {@link OpenSeadragon.Rect} as options.location
* @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) {
@ -132,13 +151,14 @@
true : options.scaleWidth; true : options.scaleWidth;
this.scaleHeight = options.scaleHeight === undefined ? this.scaleHeight = options.scaleHeight === undefined ?
true : options.scaleHeight; true : options.scaleHeight;
this.rotationMode = options.rotationMode || $.OverlayRotationMode.EXACT;
}; };
/** @lends OpenSeadragon.Overlay.prototype */ /** @lends OpenSeadragon.Overlay.prototype */
$.Overlay.prototype = { $.Overlay.prototype = {
/** /**
* Internal function to adjust the position of a PointOverlay * Internal function to adjust the position of a point-based overlay
* depending on it size and anchor. * depending on it size and anchor.
* @function * @function
* @param {OpenSeadragon.Point} position * @param {OpenSeadragon.Point} position
@ -219,6 +239,7 @@
var position = this.position = positionAndSize.position; var position = this.position = positionAndSize.position;
var size = this.size = positionAndSize.size; var size = this.size = positionAndSize.size;
var rotate = positionAndSize.rotate;
position = position.apply(Math.round); position = position.apply(Math.round);
size = size.apply(Math.round); size = size.apply(Math.round);
@ -239,6 +260,13 @@
style.height = size.y + "px"; style.height = size.y + "px";
} }
} }
if (rotate) {
style.transformOrigin = this._getTransformOrigin();
style.transform = "rotate(" + rotate + "deg)";
} else {
style.transformOrigin = "";
style.transform = "";
}
style.position = "absolute"; style.position = "absolute";
if (style.display !== 'none') { if (style.display !== 'none') {
@ -249,27 +277,71 @@
// private // private
_getRectOverlayPositionAndSize: function(viewport) { _getRectOverlayPositionAndSize: function(viewport) {
var position = viewport.pixelFromPoint(
this.bounds.getTopLeft(), true);
var size = viewport.deltaPixelsFromPointsNoRotate(
this.bounds.getSize(), true);
var rotate = 0;
// BOUNDING_BOX is only valid if both directions get scaled.
// Get replaced by exact otherwise.
if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX &&
this.scaleWidth && this.scaleHeight) {
var boundingBox = new $.Rect(
position.x, position.y, size.x, size.y, viewport.degrees)
.getBoundingBox();
position = boundingBox.getTopLeft();
size = boundingBox.getSize();
} else if (this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) {
rotate = viewport.degrees;
}
return { return {
position: viewport.pixelFromPoint( position: position,
this.bounds.getTopLeft(), true), size: size,
size: viewport.deltaPixelsFromPoints( rotate: rotate
this.bounds.getSize(), true)
}; };
}, },
// private // private
_getPointOverlayPositionAndSize: function(viewport) { _getPointOverlayPositionAndSize: function(viewport) {
var element = this.element;
var position = viewport.pixelFromPoint( var position = viewport.pixelFromPoint(
this.bounds.getTopLeft(), true); this.bounds.getTopLeft(), true);
var size = this.checkResize ? $.getElementSize(element) : this.size; var size = this.checkResize ?
$.getElementSize(this.element) : this.size;
this.adjust(position, size); this.adjust(position, size);
// For point overlays, BOUNDING_BOX is invalid and get replaced by EXACT.
var rotate = this.rotationMode === $.OverlayRotationMode.NO_ROTATION ?
0 : viewport.degrees;
return { return {
position: position, position: position,
size: size size: size,
rotate: rotate
}; };
}, },
// private
_getTransformOrigin: function() {
if (this.scales) {
return "top left";
}
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 location and placement of the overlay. * Changes the location and placement of the overlay.
* @function * @function

View File

@ -2241,7 +2241,8 @@ function getOverlayObject( viewer, overlay ) {
onDraw: overlay.onDraw, onDraw: overlay.onDraw,
checkResize: overlay.checkResize, checkResize: overlay.checkResize,
scaleWidth: overlay.scaleWidth, scaleWidth: overlay.scaleWidth,
scaleHeight: overlay.scaleHeight scaleHeight: overlay.scaleHeight,
rotationMode: overlay.rotationMode
}); });
} }