mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-22 13:16:10 +03:00
Merge pull request #896 from avandecreme/overlays
Overlays improvements
This commit is contained in:
commit
eec0d4c9ff
@ -5,6 +5,12 @@ OPENSEADRAGON CHANGELOG
|
|||||||
|
|
||||||
* BREAKING CHANGE: Viewport.homeBounds, Viewport.contentSize, Viewport.contentAspectX and
|
* BREAKING CHANGE: Viewport.homeBounds, Viewport.contentSize, Viewport.contentAspectX and
|
||||||
Viewport.contentAspectY have been removed. (#846)
|
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: Viewport.setHomeBounds has been deprecated (#846)
|
||||||
* DEPRECATION: the Viewport constructor is now ignoring the contentSize option (#846)
|
* DEPRECATION: the Viewport constructor is now ignoring the contentSize option (#846)
|
||||||
* Tile edge smoothing at high zoom (#764)
|
* 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)
|
* Fixed issue causing HTML pages to jump unwantedly to the reference strip upon loading (#872)
|
||||||
* Added addOnceHandler method to EventSource (#887)
|
* Added addOnceHandler method to EventSource (#887)
|
||||||
* Added TiledImage.fitBounds method (#888)
|
* 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:
|
2.1.0:
|
||||||
|
|
||||||
|
@ -1337,6 +1337,49 @@ if (typeof define === 'function' && define.amd) {
|
|||||||
return window.getComputedStyle( element, "" );
|
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).
|
* Determines if a point is within the bounding rectangle of the given element (hit-test).
|
||||||
|
416
src/overlay.js
416
src/overlay.js
@ -32,7 +32,7 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function( $ ){
|
(function($) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enumeration of positions that an overlay may be assigned relative to
|
* An enumeration of positions that an overlay may be assigned relative to
|
||||||
@ -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.
|
||||||
@ -64,19 +81,27 @@
|
|||||||
* @param {Element} options.element
|
* @param {Element} options.element
|
||||||
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location - The
|
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location - The
|
||||||
* location of the overlay on the image. If a {@link OpenSeadragon.Point}
|
* location of the overlay on the image. If a {@link OpenSeadragon.Point}
|
||||||
* is specified, the overlay will keep a constant size independently of the
|
* is specified, the overlay will be located at this location with respect
|
||||||
* zoom. If a {@link OpenSeadragon.Rect} is specified, the overlay size will
|
* to the placement option. If a {@link OpenSeadragon.Rect} is specified,
|
||||||
* be adjusted when the zoom changes.
|
* 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]
|
* @param {OpenSeadragon.Placement} [options.placement=OpenSeadragon.Placement.TOP_LEFT]
|
||||||
* Relative position to the viewport.
|
* Defines what part of the overlay should be at the specified options.location
|
||||||
* Only used if location is a {@link OpenSeadragon.Point}.
|
|
||||||
* @param {OpenSeadragon.Overlay.OnDrawCallback} [options.onDraw]
|
* @param {OpenSeadragon.Overlay.OnDrawCallback} [options.onDraw]
|
||||||
* @param {Boolean} [options.checkResize=true] Set to false to avoid to
|
* @param {Boolean} [options.checkResize=true] Set to false to avoid to
|
||||||
* check the size of the overlay everytime it is drawn when using a
|
* check the size of the overlay everytime it is drawn in the directions
|
||||||
* {@link OpenSeadragon.Point} as options.location. It will improve
|
* which are not scaled. It will improve performances but will cause a
|
||||||
* performances but will cause a misalignment if the overlay size changes.
|
* 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}.
|
* onDraw callback signature used by {@link OpenSeadragon.Overlay}.
|
||||||
@ -89,7 +114,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var options;
|
var options;
|
||||||
if ( $.isPlainObject( element ) ) {
|
if ($.isPlainObject(element)) {
|
||||||
options = element;
|
options = element;
|
||||||
} else {
|
} else {
|
||||||
options = {
|
options = {
|
||||||
@ -100,34 +125,48 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.element = options.element;
|
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;
|
this.style = options.element.style;
|
||||||
// rects are always top-left
|
this._init(options);
|
||||||
this.placement = options.location instanceof $.Point ?
|
|
||||||
options.placement : $.Placement.TOP_LEFT;
|
|
||||||
this.onDraw = options.onDraw;
|
|
||||||
this.checkResize = options.checkResize === undefined ?
|
|
||||||
true : options.checkResize;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @lends OpenSeadragon.Overlay.prototype */
|
/** @lends OpenSeadragon.Overlay.prototype */
|
||||||
$.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
|
* @function
|
||||||
* @param {OpenSeadragon.Point} position
|
* @param {OpenSeadragon.Point} position
|
||||||
* @param {OpenSeadragon.Point} size
|
* @param {OpenSeadragon.Point} size
|
||||||
@ -153,20 +192,20 @@
|
|||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
var element = this.element,
|
var element = this.element;
|
||||||
style = this.style;
|
var style = this.style;
|
||||||
|
|
||||||
if ( element.parentNode ) {
|
if (element.parentNode) {
|
||||||
element.parentNode.removeChild( element );
|
element.parentNode.removeChild(element);
|
||||||
//this should allow us to preserve overlays when required between
|
//this should allow us to preserve overlays when required between
|
||||||
//pages
|
//pages
|
||||||
if ( element.prevElementParent ) {
|
if (element.prevElementParent) {
|
||||||
style.display = 'none';
|
style.display = 'none';
|
||||||
//element.prevElementParent.insertBefore(
|
//element.prevElementParent.insertBefore(
|
||||||
// element,
|
// element,
|
||||||
// element.prevNextSibling
|
// element.prevNextSibling
|
||||||
//);
|
//);
|
||||||
document.body.appendChild( element );
|
document.body.appendChild(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,121 +216,258 @@
|
|||||||
style.left = "";
|
style.left = "";
|
||||||
style.position = "";
|
style.position = "";
|
||||||
|
|
||||||
if ( this.scales ) {
|
if (this.width !== null) {
|
||||||
style.width = "";
|
style.width = "";
|
||||||
|
}
|
||||||
|
if (this.height !== null) {
|
||||||
style.height = "";
|
style.height = "";
|
||||||
}
|
}
|
||||||
|
var transformOriginProp = $.getCssPropertyWithVendorPrefix(
|
||||||
|
'transformOrigin');
|
||||||
|
var transformProp = $.getCssPropertyWithVendorPrefix(
|
||||||
|
'transform');
|
||||||
|
if (transformOriginProp && transformProp) {
|
||||||
|
style[transformOriginProp] = "";
|
||||||
|
style[transformProp] = "";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
* @param {Element} container
|
* @param {Element} container
|
||||||
*/
|
*/
|
||||||
drawHTML: function( container, viewport ) {
|
drawHTML: function(container, viewport) {
|
||||||
var element = this.element,
|
var element = this.element;
|
||||||
style = this.style,
|
if (element.parentNode !== container) {
|
||||||
scales = this.scales,
|
|
||||||
degrees = viewport.degrees,
|
|
||||||
position = viewport.pixelFromPoint(
|
|
||||||
this.bounds.getTopLeft(),
|
|
||||||
true
|
|
||||||
),
|
|
||||||
size,
|
|
||||||
overlayCenter;
|
|
||||||
|
|
||||||
if ( element.parentNode != container ) {
|
|
||||||
//save the source parent for later if we need it
|
//save the source parent for later if we need it
|
||||||
element.prevElementParent = element.parentNode;
|
element.prevElementParent = element.parentNode;
|
||||||
element.prevNextSibling = element.nextSibling;
|
element.prevNextSibling = element.nextSibling;
|
||||||
container.appendChild( element );
|
container.appendChild(element);
|
||||||
this.size = $.getElementSize( 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 ) {
|
var positionAndSize = this._getOverlayPositionAndSize(viewport);
|
||||||
size = viewport.deltaPixelsFromPoints(
|
|
||||||
this.bounds.getSize(),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
} else if ( this.checkResize ) {
|
|
||||||
size = $.getElementSize( element );
|
|
||||||
} else {
|
|
||||||
size = this.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.position = position;
|
var position = positionAndSize.position;
|
||||||
this.size = size;
|
var size = this.size = positionAndSize.size;
|
||||||
|
var rotate = positionAndSize.rotate;
|
||||||
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 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// call the onDraw callback if it exists to allow one to overwrite
|
// call the onDraw callback if it exists to allow one to overwrite
|
||||||
// the drawing/positioning/sizing of the overlay
|
// the drawing/positioning/sizing of the overlay
|
||||||
if ( this.onDraw ) {
|
if (this.onDraw) {
|
||||||
this.onDraw( position, size, element );
|
this.onDraw(position, size, this.element);
|
||||||
} else {
|
} else {
|
||||||
|
var style = this.style;
|
||||||
style.left = position.x + "px";
|
style.left = position.x + "px";
|
||||||
style.top = position.y + "px";
|
style.top = position.y + "px";
|
||||||
style.position = "absolute";
|
if (this.width !== null) {
|
||||||
|
|
||||||
if (style.display != 'none') {
|
|
||||||
style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( scales ) {
|
|
||||||
style.width = size.x + "px";
|
style.width = size.x + "px";
|
||||||
|
}
|
||||||
|
if (this.height !== null) {
|
||||||
style.height = size.y + "px";
|
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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// private
|
||||||
* @function
|
_getOverlayPositionAndSize: function(viewport) {
|
||||||
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} location
|
var position = viewport.pixelFromPoint(this.location, true);
|
||||||
* @param {OpenSeadragon.Placement} position
|
var size = this._getSizeInPixels(viewport);
|
||||||
*/
|
this.adjust(position, size);
|
||||||
update: function( location, placement ) {
|
|
||||||
this.scales = location instanceof $.Rect;
|
var rotate = 0;
|
||||||
this.bounds = new $.Rect(
|
if (viewport.degrees &&
|
||||||
location.x,
|
this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) {
|
||||||
location.y,
|
// BOUNDING_BOX is only valid if both directions get scaled.
|
||||||
location.width,
|
// Get replaced by EXACT otherwise.
|
||||||
location.height
|
if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX &&
|
||||||
);
|
this.width !== null && this.height !== null) {
|
||||||
// rects are always top-left
|
var rect = new $.Rect(position.x, position.y, size.x, size.y);
|
||||||
this.placement = location instanceof $.Point ?
|
var boundingBox = this._getBoundingBox(rect, viewport.degrees);
|
||||||
placement : $.Placement.TOP_LEFT;
|
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
|
* @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
|
* @returns {OpenSeadragon.Rect} overlay bounds
|
||||||
*/
|
*/
|
||||||
getBounds: function() {
|
getBounds: function(viewport) {
|
||||||
return this.bounds.clone();
|
$.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));
|
||||||
|
@ -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 */
|
/** @lends OpenSeadragon.Rect.prototype */
|
||||||
$.Rect.prototype = {
|
$.Rect.prototype = {
|
||||||
/**
|
/**
|
||||||
@ -284,7 +311,7 @@ $.Rect.prototype = {
|
|||||||
* Rotates a rectangle around a point.
|
* Rotates a rectangle around a point.
|
||||||
* @function
|
* @function
|
||||||
* @param {Number} degrees The angle in degrees to rotate.
|
* @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.
|
* Defaults to the center of the rectangle.
|
||||||
* @return {OpenSeadragon.Rect}
|
* @return {OpenSeadragon.Rect}
|
||||||
*/
|
*/
|
||||||
|
@ -1788,7 +1788,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
|||||||
* is closed which include when changing page.
|
* is closed which include when changing page.
|
||||||
* @method
|
* @method
|
||||||
* @param {Element|String|Object} element - A reference to an element or an id for
|
* @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
|
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or
|
||||||
* rectangle which will be overlayed. This is a viewport relative location.
|
* rectangle which will be overlayed. This is a viewport relative location.
|
||||||
* @param {OpenSeadragon.Placement} placement - The position of the
|
* @param {OpenSeadragon.Placement} placement - The position of the
|
||||||
@ -2199,32 +2201,23 @@ function getOverlayObject( viewer, overlay ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var location = overlay.location;
|
var location = overlay.location;
|
||||||
if ( !location ) {
|
var width = overlay.width;
|
||||||
if ( overlay.width && overlay.height ) {
|
var height = overlay.height;
|
||||||
location = overlay.px !== undefined ?
|
if (!location) {
|
||||||
viewer.viewport.imageToViewportRectangle( new $.Rect(
|
var x = overlay.x;
|
||||||
|
var y = overlay.y;
|
||||||
|
if (overlay.px !== undefined) {
|
||||||
|
var rect = viewer.viewport.imageToViewportRectangle(new $.Rect(
|
||||||
overlay.px,
|
overlay.px,
|
||||||
overlay.py,
|
overlay.py,
|
||||||
overlay.width,
|
width || 0,
|
||||||
overlay.height
|
height || 0));
|
||||||
) ) :
|
x = rect.x;
|
||||||
new $.Rect(
|
y = rect.y;
|
||||||
overlay.x,
|
width = width !== undefined ? rect.width : undefined;
|
||||||
overlay.y,
|
height = height !== undefined ? rect.height : undefined;
|
||||||
overlay.width,
|
|
||||||
overlay.height
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
location = overlay.px !== undefined ?
|
|
||||||
viewer.viewport.imageToViewportCoordinates( new $.Point(
|
|
||||||
overlay.px,
|
|
||||||
overlay.py
|
|
||||||
) ) :
|
|
||||||
new $.Point(
|
|
||||||
overlay.x,
|
|
||||||
overlay.y
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
location = new $.Point(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
var placement = overlay.placement;
|
var placement = overlay.placement;
|
||||||
@ -2237,7 +2230,10 @@ function getOverlayObject( viewer, overlay ) {
|
|||||||
location: location,
|
location: location,
|
||||||
placement: placement,
|
placement: placement,
|
||||||
onDraw: overlay.onDraw,
|
onDraw: overlay.onDraw,
|
||||||
checkResize: overlay.checkResize
|
checkResize: overlay.checkResize,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
rotationMode: overlay.rotationMode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1262,6 +1262,34 @@ $.Viewport.prototype = {
|
|||||||
return this.pixelFromPoint( point, true );
|
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.
|
* Convert pixel coordinates relative to the window to viewport coordinates.
|
||||||
* @param {OpenSeadragon.Point} pixel
|
* @param {OpenSeadragon.Point} pixel
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="contentDiv" class="openseadragon1"></div>
|
<div id="contentDiv" class="openseadragon1"></div>
|
||||||
<div id="annotation-div">
|
<div id="annotation-div">
|
||||||
<input type="button" value="Hide Overlay" id="hideOverlay">
|
<input type="button" value="Hide Overlays" id="hideOverlays">
|
||||||
|
<input type="button" value="Rotate" id="rotate">
|
||||||
|
<span id="degrees">0deg</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -22,19 +24,74 @@
|
|||||||
var viewer = OpenSeadragon({
|
var viewer = OpenSeadragon({
|
||||||
id: "contentDiv",
|
id: "contentDiv",
|
||||||
prefixUrl: "../../build/openseadragon/images/",
|
prefixUrl: "../../build/openseadragon/images/",
|
||||||
tileSources: "../data/testpattern.dzi"
|
tileSources: "../data/testpattern.dzi",
|
||||||
|
minZoomImageRatio: 0,
|
||||||
|
maxZoomPixelRatio: 10
|
||||||
});
|
});
|
||||||
|
|
||||||
viewer.addHandler("open", function(event) {
|
viewer.addHandler("open", function(event) {
|
||||||
var elt = document.createElement("div");
|
var elt = document.createElement("div");
|
||||||
|
elt.className = "runtime-overlay";
|
||||||
elt.style.background = "green";
|
elt.style.background = "green";
|
||||||
elt.id = "runtime-overlay";
|
elt.style.outline = "3px solid red";
|
||||||
elt.style.border = "1px solid red";
|
elt.style.opacity = "0.7";
|
||||||
viewer.addOverlay( elt, new OpenSeadragon.Rect(0.2, 0.2, 0.75, 0.75) );
|
elt.textContent = "Scaled overlay";
|
||||||
|
viewer.addOverlay({
|
||||||
|
element: elt,
|
||||||
|
location: new OpenSeadragon.Rect(0.21, 0.21, 0.099, 0.099),
|
||||||
|
rotationMode: OpenSeadragon.OverlayRotationMode.BOUNDING_BOX
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#hideOverlay").click(function(){
|
elt = document.createElement("div");
|
||||||
$("#runtime-overlay").toggle();
|
elt.className = "runtime-overlay";
|
||||||
|
elt.style.background = "white";
|
||||||
|
elt.style.outline = "3px solid red";
|
||||||
|
elt.style.width = "100px";
|
||||||
|
elt.textContent = "Scaled vertically";
|
||||||
|
viewer.addOverlay({
|
||||||
|
element: elt,
|
||||||
|
location: new OpenSeadragon.Point(0.6, 0.6),
|
||||||
|
height: 0.1,
|
||||||
|
placement: OpenSeadragon.Placement.TOP_LEFT,
|
||||||
|
rotationMode: OpenSeadragon.OverlayRotationMode.NO_ROTATION
|
||||||
|
});
|
||||||
|
|
||||||
|
elt = document.createElement("div");
|
||||||
|
elt.className = "runtime-overlay";
|
||||||
|
elt.style.background = "white";
|
||||||
|
elt.style.opacity = "0.5";
|
||||||
|
elt.style.outline = "1px solid blue";
|
||||||
|
elt.style.height = "100px";
|
||||||
|
elt.textContent = "Scaled horizontally";
|
||||||
|
viewer.addOverlay({
|
||||||
|
element: elt,
|
||||||
|
location: new OpenSeadragon.Point(0.1, 0.5),
|
||||||
|
width: 0.1
|
||||||
|
});
|
||||||
|
|
||||||
|
elt = document.createElement("div");
|
||||||
|
elt.className = "runtime-overlay";
|
||||||
|
elt.style.background = "white";
|
||||||
|
elt.style.opacity = "0.5";
|
||||||
|
elt.style.outline = "5px solid pink";
|
||||||
|
elt.style.width = "100px";
|
||||||
|
elt.style.height = "100px";
|
||||||
|
elt.textContent = "Not scaled, centered in the middle";
|
||||||
|
viewer.addOverlay({
|
||||||
|
element: elt,
|
||||||
|
location: new OpenSeadragon.Point(0.5, 0.5),
|
||||||
|
placement: OpenSeadragon.Placement.CENTER,
|
||||||
|
checkResize: false,
|
||||||
|
rotationMode: OpenSeadragon.OverlayRotationMode.EXACT
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
$("#hideOverlays").click(function(){
|
||||||
|
$(".runtime-overlay").toggle();
|
||||||
|
});
|
||||||
|
$("#rotate").click(function() {
|
||||||
|
viewer.viewport.setRotation(viewer.viewport.getRotation() + 22.5);
|
||||||
|
$("#degrees").text(viewer.viewport.getRotation() + "deg");
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user