mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-25 06:36:11 +03:00
Merge pull request #185 from robhobbes/master
Adding partial support for rotation.
This commit is contained in:
commit
aefe7f3610
@ -407,6 +407,10 @@ $.Drawer.prototype = {
|
||||
}
|
||||
|
||||
return loading;
|
||||
},
|
||||
|
||||
canRotate: function() {
|
||||
return USE_CANVAS;
|
||||
}
|
||||
};
|
||||
|
||||
@ -509,6 +513,7 @@ function updateViewport( drawer ) {
|
||||
Math.log( 2 )
|
||||
))
|
||||
),
|
||||
degrees = drawer.viewport.degrees,
|
||||
renderPixelRatioC,
|
||||
renderPixelRatioT,
|
||||
zeroRatioT,
|
||||
@ -533,7 +538,14 @@ function updateViewport( drawer ) {
|
||||
drawer.context.clearRect( 0, 0, viewportSize.x, viewportSize.y );
|
||||
}
|
||||
|
||||
//TODO
|
||||
//Change bounds for rotation
|
||||
if (degrees === 90 || degrees === 270) {
|
||||
var rotatedBounds = viewportBounds.rotate( degrees );
|
||||
viewportTL = rotatedBounds.getTopLeft();
|
||||
viewportBR = rotatedBounds.getBottomRight();
|
||||
}
|
||||
|
||||
//Don't draw if completely outside of the viewport
|
||||
if ( !drawer.wrapHorizontal &&
|
||||
( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
|
||||
return;
|
||||
@ -575,6 +587,7 @@ function updateViewport( drawer ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//Perform calculations for draw if we haven't drawn this
|
||||
renderPixelRatioT = drawer.viewport.deltaPixelsFromPoints(
|
||||
drawer.source.getPixelRatio( level ),
|
||||
false
|
||||
@ -1117,7 +1130,7 @@ function drawOverlay( viewport, overlay, container ){
|
||||
overlay.bounds.getSize(),
|
||||
true
|
||||
);
|
||||
overlay.drawHTML( container );
|
||||
overlay.drawHTML( container, viewport );
|
||||
}
|
||||
|
||||
function drawTiles( drawer, lastDrawn ){
|
||||
@ -1196,7 +1209,15 @@ function drawTiles( drawer, lastDrawn ){
|
||||
} else {
|
||||
|
||||
if ( USE_CANVAS ) {
|
||||
// TODO do this in a more performant way
|
||||
// specifically, don't save,rotate,restore every time we draw a tile
|
||||
if( drawer.viewport.degrees !== 0 ) {
|
||||
offsetForRotation( tile, drawer.canvas, drawer.context, drawer.viewport.degrees );
|
||||
tile.drawCanvas( drawer.context );
|
||||
restoreRotationChanges( tile, drawer.canvas, drawer.context );
|
||||
} else {
|
||||
tile.drawCanvas( drawer.context );
|
||||
}
|
||||
} else {
|
||||
tile.drawHTML( drawer.canvas );
|
||||
}
|
||||
@ -1222,6 +1243,32 @@ function drawTiles( drawer, lastDrawn ){
|
||||
}
|
||||
}
|
||||
|
||||
function offsetForRotation( tile, canvas, context, degrees ){
|
||||
var cx = canvas.width / 2,
|
||||
cy = canvas.height / 2,
|
||||
px = tile.position.x - cx,
|
||||
py = tile.position.y - cy;
|
||||
|
||||
context.save();
|
||||
|
||||
context.translate(cx, cy);
|
||||
context.rotate( Math.PI / 180 * degrees);
|
||||
tile.position.x = px;
|
||||
tile.position.y = py;
|
||||
}
|
||||
|
||||
function restoreRotationChanges( tile, canvas, context ){
|
||||
var cx = canvas.width / 2,
|
||||
cy = canvas.height / 2,
|
||||
px = tile.position.x + cx,
|
||||
py = tile.position.y + cy;
|
||||
|
||||
tile.position.x = px;
|
||||
tile.position.y = py;
|
||||
|
||||
context.restore();
|
||||
}
|
||||
|
||||
|
||||
function drawDebugInfo( drawer, tile, count, i ){
|
||||
|
||||
|
@ -533,6 +533,9 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
||||
navigatorPosition: null,
|
||||
navigatorSizeRatio: 0.2,
|
||||
|
||||
// INITIAL ROTATION
|
||||
degrees: 0,
|
||||
|
||||
//REFERENCE STRIP SETTINGS
|
||||
showReferenceStrip: false,
|
||||
referenceStripScroll: 'horizontal',
|
||||
|
@ -174,12 +174,18 @@
|
||||
* @function
|
||||
* @param {Element} container
|
||||
*/
|
||||
drawHTML: function( container ) {
|
||||
drawHTML: function( container, viewport ) {
|
||||
var element = this.element,
|
||||
style = this.style,
|
||||
scales = this.scales,
|
||||
drawerCenter = new $.Point(
|
||||
viewport.viewer.drawer.canvas.width / 2,
|
||||
viewport.viewer.drawer.canvas.height / 2
|
||||
),
|
||||
degrees = viewport.degrees,
|
||||
position,
|
||||
size;
|
||||
size,
|
||||
overlayCenter;
|
||||
|
||||
if ( element.parentNode != container ) {
|
||||
//save the source parent for later if we need it
|
||||
@ -200,6 +206,23 @@
|
||||
position = position.apply( Math.floor );
|
||||
size = size.apply( Math.ceil );
|
||||
|
||||
// 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 );
|
||||
|
||||
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 there is one to allow, this allows someone to overwrite
|
||||
// the drawing/positioning/sizing of the overlay
|
||||
if (this.onDraw) {
|
||||
|
15
src/point.js
15
src/point.js
@ -160,6 +160,21 @@ $.Point.prototype = {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Rotates the point around the specified pivot
|
||||
* From http://stackoverflow.com/questions/4465931/rotate-rectangle-around-a-point
|
||||
* @function
|
||||
* @param {Number} degress to rotate around the pivot.
|
||||
* @param {OpenSeadragon.Point} pivot Point about which to rotate.
|
||||
* @returns {OpenSeadragon.Point}. A new point representing the point rotated around the specified pivot
|
||||
*/
|
||||
rotate: function ( degrees, pivot ) {
|
||||
var angle = degrees * Math.PI / 180.0,
|
||||
x = Math.cos( angle ) * ( this.x - pivot.x ) - Math.sin( angle ) * ( this.y - pivot.y ) + pivot.x,
|
||||
y = Math.sin( angle ) * ( this.x - pivot.x ) + Math.cos( angle ) * ( this.y - pivot.y ) + pivot.y;
|
||||
return new $.Point( x, y );
|
||||
},
|
||||
|
||||
/**
|
||||
* Add another Point to this point and return a new Point.
|
||||
* @function
|
||||
|
@ -76,7 +76,10 @@ $.Rect.prototype = {
|
||||
* the rectangle.
|
||||
*/
|
||||
getTopLeft: function() {
|
||||
return new $.Point( this.x, this.y );
|
||||
return new $.Point(
|
||||
this.x,
|
||||
this.y
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -93,10 +96,38 @@ $.Rect.prototype = {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Provides the coordinates of the top-right corner of the rectangle as a
|
||||
* point.
|
||||
* @function
|
||||
* @returns {OpenSeadragon.Point} The coordinate of the top-right corner of
|
||||
* the rectangle.
|
||||
*/
|
||||
getTopRight: function() {
|
||||
return new $.Point(
|
||||
this.x + this.width,
|
||||
this.y
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Provides the coordinates of the bottom-left corner of the rectangle as a
|
||||
* point.
|
||||
* @function
|
||||
* @returns {OpenSeadragon.Point} The coordinate of the bottom-left corner of
|
||||
* the rectangle.
|
||||
*/
|
||||
getBottomLeft: function() {
|
||||
return new $.Point(
|
||||
this.x,
|
||||
this.y + this.height
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Computes the center of the rectangle.
|
||||
* @function
|
||||
* @returns {OpenSeadragon.Point} The center of the rectangle as represnted
|
||||
* @returns {OpenSeadragon.Point} The center of the rectangle as represented
|
||||
* as represented by a 2-dimensional vector (x,y)
|
||||
*/
|
||||
getCenter: function() {
|
||||
@ -109,7 +140,7 @@ $.Rect.prototype = {
|
||||
/**
|
||||
* Returns the width and height component as a vector OpenSeadragon.Point
|
||||
* @function
|
||||
* @returns {OpenSeadragon.Point} The 2 dimensional vector represnting the
|
||||
* @returns {OpenSeadragon.Point} The 2 dimensional vector representing the
|
||||
* the width and height of the rectangle.
|
||||
*/
|
||||
getSize: function() {
|
||||
@ -117,7 +148,7 @@ $.Rect.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if two Rectanlges have equivalent components.
|
||||
* Determines if two Rectangles have equivalent components.
|
||||
* @function
|
||||
* @param {OpenSeadragon.Rect} rectangle The Rectangle to compare to.
|
||||
* @return {Boolean} 'true' if all components are equal, otherwise 'false'.
|
||||
@ -131,7 +162,62 @@ $.Rect.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Provides a string representation of the retangle which is useful for
|
||||
* Rotates a rectangle around a point. Currently only 90, 180, and 270
|
||||
* degrees are supported.
|
||||
* @function
|
||||
* @param {Number} degrees The angle in degrees to rotate.
|
||||
* @param {OpenSeadragon.Point} pivot The point about which to rotate.
|
||||
* Defaults to the center of the rectangle.
|
||||
* @return {OpenSeadragon.Rect}
|
||||
*/
|
||||
rotate: function( degrees, pivot ) {
|
||||
// TODO support arbitrary rotation
|
||||
var width = this.width,
|
||||
height = this.height,
|
||||
newTopLeft;
|
||||
|
||||
degrees = ( degrees + 360 ) % 360;
|
||||
if( degrees % 90 !== 0 ) {
|
||||
throw new Error('Currently only 0, 90, 180, and 270 degrees are supported.');
|
||||
}
|
||||
|
||||
if( degrees === 0 ){
|
||||
return new $.Rect(
|
||||
this.x,
|
||||
this.y,
|
||||
this.width,
|
||||
this.height
|
||||
);
|
||||
}
|
||||
|
||||
pivot = pivot || this.getCenter();
|
||||
|
||||
switch ( degrees ) {
|
||||
case 90:
|
||||
newTopLeft = this.getBottomLeft();
|
||||
width = this.height;
|
||||
height = this.width;
|
||||
break;
|
||||
case 180:
|
||||
newTopLeft = this.getBottomRight();
|
||||
break;
|
||||
case 270:
|
||||
newTopLeft = this.getTopRight();
|
||||
width = this.height;
|
||||
height = this.width;
|
||||
break;
|
||||
default:
|
||||
newTopLeft = this.getTopLeft();
|
||||
break;
|
||||
}
|
||||
|
||||
newTopLeft = newTopLeft.rotate(degrees, pivot);
|
||||
|
||||
return new $.Rect(newTopLeft.x, newTopLeft.y, width, height);
|
||||
},
|
||||
|
||||
/**
|
||||
* Provides a string representation of the rectangle which is useful for
|
||||
* debugging.
|
||||
* @function
|
||||
* @returns {String} A string representation of the rectangle.
|
||||
|
@ -79,7 +79,8 @@ $.Viewport = function( options ) {
|
||||
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
|
||||
defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel,
|
||||
minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel,
|
||||
maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel
|
||||
maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel,
|
||||
degrees: $.DEFAULT_SETTINGS.degrees
|
||||
|
||||
}, options );
|
||||
|
||||
@ -500,6 +501,7 @@ $.Viewport.prototype = {
|
||||
this.centerSpringX.target.value,
|
||||
this.centerSpringY.target.value
|
||||
);
|
||||
delta = delta.rotate( -this.degrees, new $.Point( 0, 0 ) );
|
||||
return this.panTo( center.plus( delta ), immediately );
|
||||
},
|
||||
|
||||
@ -534,6 +536,12 @@ $.Viewport.prototype = {
|
||||
* @return {OpenSeadragon.Viewport} Chainable.
|
||||
*/
|
||||
zoomBy: function( factor, refPoint, immediately ) {
|
||||
if( refPoint ) {
|
||||
refPoint = refPoint.rotate(
|
||||
-this.degrees,
|
||||
new $.Point( this.centerSpringX.target.value, this.centerSpringY.target.value )
|
||||
);
|
||||
}
|
||||
return this.zoomTo( this.zoomSpring.target.value * factor, refPoint, immediately );
|
||||
},
|
||||
|
||||
@ -565,6 +573,40 @@ $.Viewport.prototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Currently only 90 degree rotation is supported and it only works
|
||||
* with the canvas. Additionally, the navigator does not rotate yet,
|
||||
* debug mode doesn't rotate yet, and overlay rotation is only
|
||||
* partially supported.
|
||||
* @function
|
||||
* @name OpenSeadragon.Viewport.prototype.setRotation
|
||||
* @return {OpenSeadragon.Viewport} Chainable.
|
||||
*/
|
||||
setRotation: function( degrees ) {
|
||||
if( !( this.viewer && this.viewer.drawer.canRotate() ) ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
degrees = ( degrees + 360 ) % 360;
|
||||
if( degrees % 90 !== 0 ) {
|
||||
throw new Error('Currently only 0, 90, 180, and 270 degrees are supported.');
|
||||
}
|
||||
this.degrees = degrees;
|
||||
this.viewer.drawer.update();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the current rotation in degrees.
|
||||
* @function
|
||||
* @name OpenSeadragon.Viewport.prototype.setRotation
|
||||
* @return {Number} The current rotation in degrees.
|
||||
*/
|
||||
getRotation: function() {
|
||||
return this.degrees;
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @return {OpenSeadragon.Viewport} Chainable.
|
||||
|
Loading…
Reference in New Issue
Block a user