mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-12-01 09:36:08 +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;
|
return loading;
|
||||||
|
},
|
||||||
|
|
||||||
|
canRotate: function() {
|
||||||
|
return USE_CANVAS;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -509,6 +513,7 @@ function updateViewport( drawer ) {
|
|||||||
Math.log( 2 )
|
Math.log( 2 )
|
||||||
))
|
))
|
||||||
),
|
),
|
||||||
|
degrees = drawer.viewport.degrees,
|
||||||
renderPixelRatioC,
|
renderPixelRatioC,
|
||||||
renderPixelRatioT,
|
renderPixelRatioT,
|
||||||
zeroRatioT,
|
zeroRatioT,
|
||||||
@ -533,7 +538,14 @@ function updateViewport( drawer ) {
|
|||||||
drawer.context.clearRect( 0, 0, viewportSize.x, viewportSize.y );
|
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 &&
|
if ( !drawer.wrapHorizontal &&
|
||||||
( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
|
( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
|
||||||
return;
|
return;
|
||||||
@ -575,6 +587,7 @@ function updateViewport( drawer ) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Perform calculations for draw if we haven't drawn this
|
||||||
renderPixelRatioT = drawer.viewport.deltaPixelsFromPoints(
|
renderPixelRatioT = drawer.viewport.deltaPixelsFromPoints(
|
||||||
drawer.source.getPixelRatio( level ),
|
drawer.source.getPixelRatio( level ),
|
||||||
false
|
false
|
||||||
@ -1117,7 +1130,7 @@ function drawOverlay( viewport, overlay, container ){
|
|||||||
overlay.bounds.getSize(),
|
overlay.bounds.getSize(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
overlay.drawHTML( container );
|
overlay.drawHTML( container, viewport );
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawTiles( drawer, lastDrawn ){
|
function drawTiles( drawer, lastDrawn ){
|
||||||
@ -1196,7 +1209,15 @@ function drawTiles( drawer, lastDrawn ){
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
if ( USE_CANVAS ) {
|
if ( USE_CANVAS ) {
|
||||||
tile.drawCanvas( drawer.context );
|
// 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 {
|
} else {
|
||||||
tile.drawHTML( drawer.canvas );
|
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 ){
|
function drawDebugInfo( drawer, tile, count, i ){
|
||||||
|
|
||||||
|
@ -533,6 +533,9 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
|||||||
navigatorPosition: null,
|
navigatorPosition: null,
|
||||||
navigatorSizeRatio: 0.2,
|
navigatorSizeRatio: 0.2,
|
||||||
|
|
||||||
|
// INITIAL ROTATION
|
||||||
|
degrees: 0,
|
||||||
|
|
||||||
//REFERENCE STRIP SETTINGS
|
//REFERENCE STRIP SETTINGS
|
||||||
showReferenceStrip: false,
|
showReferenceStrip: false,
|
||||||
referenceStripScroll: 'horizontal',
|
referenceStripScroll: 'horizontal',
|
||||||
|
@ -174,12 +174,18 @@
|
|||||||
* @function
|
* @function
|
||||||
* @param {Element} container
|
* @param {Element} container
|
||||||
*/
|
*/
|
||||||
drawHTML: function( container ) {
|
drawHTML: function( container, viewport ) {
|
||||||
var element = this.element,
|
var element = this.element,
|
||||||
style = this.style,
|
style = this.style,
|
||||||
scales = this.scales,
|
scales = this.scales,
|
||||||
|
drawerCenter = new $.Point(
|
||||||
|
viewport.viewer.drawer.canvas.width / 2,
|
||||||
|
viewport.viewer.drawer.canvas.height / 2
|
||||||
|
),
|
||||||
|
degrees = viewport.degrees,
|
||||||
position,
|
position,
|
||||||
size;
|
size,
|
||||||
|
overlayCenter;
|
||||||
|
|
||||||
if ( element.parentNode != container ) {
|
if ( element.parentNode != container ) {
|
||||||
//save the source parent for later if we need it
|
//save the source parent for later if we need it
|
||||||
@ -200,6 +206,23 @@
|
|||||||
position = position.apply( Math.floor );
|
position = position.apply( Math.floor );
|
||||||
size = size.apply( Math.ceil );
|
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
|
// call the onDraw callback if there is one to allow, this allows someone to overwrite
|
||||||
// the drawing/positioning/sizing of the overlay
|
// the drawing/positioning/sizing of the overlay
|
||||||
if (this.onDraw) {
|
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.
|
* Add another Point to this point and return a new Point.
|
||||||
* @function
|
* @function
|
||||||
|
@ -69,14 +69,17 @@ $.Rect.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the coordinates of the upper-left corner of the rectanglea s a
|
* Provides the coordinates of the upper-left corner of the rectangle as a
|
||||||
* point.
|
* point.
|
||||||
* @function
|
* @function
|
||||||
* @returns {OpenSeadragon.Point} The coordinate of the upper-left corner of
|
* @returns {OpenSeadragon.Point} The coordinate of the upper-left corner of
|
||||||
* the rectangle.
|
* the rectangle.
|
||||||
*/
|
*/
|
||||||
getTopLeft: function() {
|
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.
|
* Computes the center of the rectangle.
|
||||||
* @function
|
* @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)
|
* as represented by a 2-dimensional vector (x,y)
|
||||||
*/
|
*/
|
||||||
getCenter: function() {
|
getCenter: function() {
|
||||||
@ -109,7 +140,7 @@ $.Rect.prototype = {
|
|||||||
/**
|
/**
|
||||||
* Returns the width and height component as a vector OpenSeadragon.Point
|
* Returns the width and height component as a vector OpenSeadragon.Point
|
||||||
* @function
|
* @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.
|
* the width and height of the rectangle.
|
||||||
*/
|
*/
|
||||||
getSize: function() {
|
getSize: function() {
|
||||||
@ -117,7 +148,7 @@ $.Rect.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if two Rectanlges have equivalent components.
|
* Determines if two Rectangles have equivalent components.
|
||||||
* @function
|
* @function
|
||||||
* @param {OpenSeadragon.Rect} rectangle The Rectangle to compare to.
|
* @param {OpenSeadragon.Rect} rectangle The Rectangle to compare to.
|
||||||
* @return {Boolean} 'true' if all components are equal, otherwise 'false'.
|
* @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.
|
* debugging.
|
||||||
* @function
|
* @function
|
||||||
* @returns {String} A string representation of the rectangle.
|
* @returns {String} A string representation of the rectangle.
|
||||||
|
@ -79,7 +79,8 @@ $.Viewport = function( options ) {
|
|||||||
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
|
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
|
||||||
defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel,
|
defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel,
|
||||||
minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel,
|
minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel,
|
||||||
maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel
|
maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel,
|
||||||
|
degrees: $.DEFAULT_SETTINGS.degrees
|
||||||
|
|
||||||
}, options );
|
}, options );
|
||||||
|
|
||||||
@ -500,6 +501,7 @@ $.Viewport.prototype = {
|
|||||||
this.centerSpringX.target.value,
|
this.centerSpringX.target.value,
|
||||||
this.centerSpringY.target.value
|
this.centerSpringY.target.value
|
||||||
);
|
);
|
||||||
|
delta = delta.rotate( -this.degrees, new $.Point( 0, 0 ) );
|
||||||
return this.panTo( center.plus( delta ), immediately );
|
return this.panTo( center.plus( delta ), immediately );
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -534,6 +536,12 @@ $.Viewport.prototype = {
|
|||||||
* @return {OpenSeadragon.Viewport} Chainable.
|
* @return {OpenSeadragon.Viewport} Chainable.
|
||||||
*/
|
*/
|
||||||
zoomBy: function( factor, refPoint, immediately ) {
|
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 );
|
return this.zoomTo( this.zoomSpring.target.value * factor, refPoint, immediately );
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -565,6 +573,40 @@ $.Viewport.prototype = {
|
|||||||
return this;
|
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
|
* @function
|
||||||
* @return {OpenSeadragon.Viewport} Chainable.
|
* @return {OpenSeadragon.Viewport} Chainable.
|
||||||
|
Loading…
Reference in New Issue
Block a user