added viewport rotation animation

This commit is contained in:
jonasengelmann 2022-03-29 16:50:18 +02:00
parent 8506b8a486
commit 8519e30a3a
5 changed files with 86 additions and 52 deletions

View File

@ -547,8 +547,8 @@ $.Drawer.prototype = {
context.strokeStyle = this.debugGridColor[colorIndex]; context.strokeStyle = this.debugGridColor[colorIndex];
context.fillStyle = this.debugGridColor[colorIndex]; context.fillStyle = this.debugGridColor[colorIndex];
if ( this.viewport.degrees !== 0 ) { if (this.viewport.getRotation(true) % 360 !== 0 ) {
this._offsetForRotation({degrees: this.viewport.degrees}); this._offsetForRotation({degrees: this.viewport.getRotation(true)});
} }
if (tiledImage.getRotation(true) % 360 !== 0) { if (tiledImage.getRotation(true) % 360 !== 0) {
this._offsetForRotation({ this._offsetForRotation({
@ -557,10 +557,11 @@ $.Drawer.prototype = {
tiledImage._getRotationPoint(true), true) tiledImage._getRotationPoint(true), true)
}); });
} }
if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){ if (tiledImage.viewport.getRotation(true) % 360 === 0 &&
if(tiledImage._drawer.viewer.viewport.getFlip()) { tiledImage.getRotation(true) % 360 === 0) {
tiledImage._drawer._flip(); if(tiledImage._drawer.viewer.viewport.getFlip()) {
} tiledImage._drawer._flip();
}
} }
context.strokeRect( context.strokeRect(
@ -575,7 +576,7 @@ $.Drawer.prototype = {
// Rotate the text the right way around. // Rotate the text the right way around.
context.translate( tileCenterX, tileCenterY ); context.translate( tileCenterX, tileCenterY );
context.rotate( Math.PI / 180 * -this.viewport.degrees ); context.rotate( Math.PI / 180 * -this.viewport.getRotation(true) );
context.translate( -tileCenterX, -tileCenterY ); context.translate( -tileCenterX, -tileCenterY );
if( tile.x === 0 && tile.y === 0 ){ if( tile.x === 0 && tile.y === 0 ){
@ -621,17 +622,18 @@ $.Drawer.prototype = {
(tile.position.y + 70) * $.pixelDensityRatio (tile.position.y + 70) * $.pixelDensityRatio
); );
if ( this.viewport.degrees !== 0 ) { if (this.viewport.getRotation(true) % 360 !== 0 ) {
this._restoreRotationChanges(); this._restoreRotationChanges();
} }
if (tiledImage.getRotation(true) % 360 !== 0) { if (tiledImage.getRotation(true) % 360 !== 0) {
this._restoreRotationChanges(); this._restoreRotationChanges();
} }
if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){ if (tiledImage.viewport.getRotation(true) % 360 === 0 &&
if(tiledImage._drawer.viewer.viewport.getFlip()) { tiledImage.getRotation(true) % 360 === 0) {
tiledImage._drawer._flip(); if(tiledImage._drawer.viewer.viewport.getFlip()) {
} tiledImage._drawer._flip();
}
} }
context.restore(); context.restore();

View File

@ -299,18 +299,18 @@
this.adjust(position, size); this.adjust(position, size);
var rotate = 0; var rotate = 0;
if (viewport.degrees && if (viewport.getRotation(true) &&
this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) { this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) {
// BOUNDING_BOX is only valid if both directions get scaled. // BOUNDING_BOX is only valid if both directions get scaled.
// Get replaced by EXACT otherwise. // Get replaced by EXACT otherwise.
if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX && if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX &&
this.width !== null && this.height !== null) { this.width !== null && this.height !== null) {
var rect = new $.Rect(position.x, position.y, size.x, size.y); var rect = new $.Rect(position.x, position.y, size.x, size.y);
var boundingBox = this._getBoundingBox(rect, viewport.degrees); var boundingBox = this._getBoundingBox(rect, viewport.getRotation(true));
position = boundingBox.getTopLeft(); position = boundingBox.getTopLeft();
size = boundingBox.getSize(); size = boundingBox.getSize();
} else { } else {
rotate = viewport.degrees; rotate = viewport.getRotation(true);
} }
} }
@ -447,7 +447,7 @@
// private // private
_adjustBoundsForRotation: function(viewport, bounds) { _adjustBoundsForRotation: function(viewport, bounds) {
if (!viewport || if (!viewport ||
viewport.degrees === 0 || viewport.getRotation(true) === 0 ||
this.rotationMode === $.OverlayRotationMode.EXACT) { this.rotationMode === $.OverlayRotationMode.EXACT) {
return bounds; return bounds;
} }
@ -467,7 +467,7 @@
} }
// NO_ROTATION case // NO_ROTATION case
return bounds.rotate(-viewport.degrees, return bounds.rotate(-viewport.getRotation(true),
this._getPlacementPoint(bounds)); this._getPlacementPoint(bounds));
} }
}; };

View File

@ -2076,9 +2076,10 @@ function drawTiles( tiledImage, lastDrawn ) {
.getIntegerBoundingBox(); .getIntegerBoundingBox();
if(tiledImage._drawer.viewer.viewport.getFlip()) { if(tiledImage._drawer.viewer.viewport.getFlip()) {
if (tiledImage.viewport.degrees !== 0 || tiledImage.getRotation(true) % 360 !== 0){ if (tiledImage.viewport.getRotation(true) % 360 !== 0 ||
bounds.x = tiledImage._drawer.viewer.container.clientWidth - (bounds.x + bounds.width); tiledImage.getRotation(true) % 360 !== 0) {
} bounds.x = tiledImage._drawer.viewer.container.clientWidth - (bounds.x + bounds.width);
}
} }
bounds = bounds.times($.pixelDensityRatio); bounds = bounds.times($.pixelDensityRatio);
@ -2089,9 +2090,9 @@ function drawTiles( tiledImage, lastDrawn ) {
// When scaling, we must rotate only when blending the sketch canvas to // When scaling, we must rotate only when blending the sketch canvas to
// avoid interpolation // avoid interpolation
if (!sketchScale) { if (!sketchScale) {
if (tiledImage.viewport.degrees !== 0) { if (tiledImage.viewport.getRotation(true) % 360 !== 0) {
tiledImage._drawer._offsetForRotation({ tiledImage._drawer._offsetForRotation({
degrees: tiledImage.viewport.degrees, degrees: tiledImage.viewport.getRotation(true),
useSketch: useSketch useSketch: useSketch
}); });
} }
@ -2104,10 +2105,11 @@ function drawTiles( tiledImage, lastDrawn ) {
}); });
} }
if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){ if (tiledImage.viewport.getRotation(true) === 0 &&
if(tiledImage._drawer.viewer.viewport.getFlip()) { tiledImage.getRotation(true) % 360 === 0) {
tiledImage._drawer._flip(); if(tiledImage._drawer.viewer.viewport.getFlip()) {
} tiledImage._drawer._flip();
}
} }
} }
@ -2214,16 +2216,16 @@ function drawTiles( tiledImage, lastDrawn ) {
if (tiledImage.getRotation(true) % 360 !== 0) { if (tiledImage.getRotation(true) % 360 !== 0) {
tiledImage._drawer._restoreRotationChanges(useSketch); tiledImage._drawer._restoreRotationChanges(useSketch);
} }
if (tiledImage.viewport.degrees !== 0) { if (tiledImage.viewport.getRotation(true) % 360 !== 0) {
tiledImage._drawer._restoreRotationChanges(useSketch); tiledImage._drawer._restoreRotationChanges(useSketch);
} }
} }
if (useSketch) { if (useSketch) {
if (sketchScale) { if (sketchScale) {
if (tiledImage.viewport.degrees !== 0) { if (tiledImage.viewport.getRotation(true) % 360 !== 0) {
tiledImage._drawer._offsetForRotation({ tiledImage._drawer._offsetForRotation({
degrees: tiledImage.viewport.degrees, degrees: tiledImage.viewport.getRotation(true),
useSketch: false useSketch: false
}); });
} }
@ -2247,18 +2249,19 @@ function drawTiles( tiledImage, lastDrawn ) {
if (tiledImage.getRotation(true) % 360 !== 0) { if (tiledImage.getRotation(true) % 360 !== 0) {
tiledImage._drawer._restoreRotationChanges(false); tiledImage._drawer._restoreRotationChanges(false);
} }
if (tiledImage.viewport.degrees !== 0) { if (tiledImage.viewport.getRotation(true) % 360 !== 0) {
tiledImage._drawer._restoreRotationChanges(false); tiledImage._drawer._restoreRotationChanges(false);
} }
} }
} }
if (!sketchScale) { if (!sketchScale) {
if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){ if (tiledImage.viewport.getRotation(true) % 360 === 0 &&
if(tiledImage._drawer.viewer.viewport.getFlip()) { tiledImage.getRotation(true) % 360 === 0) {
tiledImage._drawer._flip(); if(tiledImage._drawer.viewer.viewport.getFlip()) {
tiledImage._drawer._flip();
}
} }
}
} }
drawDebugInfo( tiledImage, lastDrawn ); drawDebugInfo( tiledImage, lastDrawn );

View File

@ -2810,18 +2810,18 @@ function onCanvasKeyPress( event ) {
break; break;
case 114: //r - clockwise rotation case 114: //r - clockwise rotation
if(this.viewport.flipped){ if(this.viewport.flipped){
this.viewport.setRotation($.positiveModulo(this.viewport.degrees - this.rotationIncrement, 360)); this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() - this.rotationIncrement, 360));
} else{ } else{
this.viewport.setRotation($.positiveModulo(this.viewport.degrees + this.rotationIncrement, 360)); this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() + this.rotationIncrement, 360));
} }
this.viewport.applyConstraints(); this.viewport.applyConstraints();
event.preventDefault = true; event.preventDefault = true;
break; break;
case 82: //R - counterclockwise rotation case 82: //R - counterclockwise rotation
if(this.viewport.flipped){ if(this.viewport.flipped){
this.viewport.setRotation($.positiveModulo(this.viewport.degrees + this.rotationIncrement, 360)); this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() + this.rotationIncrement, 360));
} else{ } else{
this.viewport.setRotation($.positiveModulo(this.viewport.degrees - this.rotationIncrement, 360)); this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() - this.rotationIncrement, 360));
} }
this.viewport.applyConstraints(); this.viewport.applyConstraints();
event.preventDefault = true; event.preventDefault = true;

View File

@ -133,9 +133,16 @@ $.Viewport = function( options ) {
animationTime: this.animationTime animationTime: this.animationTime
}); });
this.degreesSpring = new $.Spring({
initial: 0,
springStiffness: this.springStiffness,
animationTime: this.animationTime
});
this._oldCenterX = this.centerSpringX.current.value; this._oldCenterX = this.centerSpringX.current.value;
this._oldCenterY = this.centerSpringY.current.value; this._oldCenterY = this.centerSpringY.current.value;
this._oldZoom = this.zoomSpring.current.value; this._oldZoom = this.zoomSpring.current.value;
this._oldDegree = this.degreesSpring.current.value;
this._setContentBounds(new $.Rect(0, 0, 1, 1), 1); this._setContentBounds(new $.Rect(0, 0, 1, 1), 1);
@ -184,7 +191,7 @@ $.Viewport.prototype = {
this._contentSizeNoRotate = this._contentBoundsNoRotate.getSize().times( this._contentSizeNoRotate = this._contentBoundsNoRotate.getSize().times(
contentFactor); contentFactor);
this._contentBounds = bounds.rotate(this.degrees).getBoundingBox(); this._contentBounds = bounds.rotate(this.getRotation(true)).getBoundingBox();
this._contentSize = this._contentBounds.getSize().times(contentFactor); this._contentSize = this._contentBounds.getSize().times(contentFactor);
this._contentAspectRatio = this._contentSize.x / this._contentSize.y; this._contentAspectRatio = this._contentSize.x / this._contentSize.y;
@ -367,7 +374,7 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates. * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.
*/ */
getBounds: function(current) { getBounds: function(current) {
return this.getBoundsNoRotate(current).rotate(-this.getRotation()); return this.getBoundsNoRotate(current).rotate(-this.getRotation(current));
}, },
/** /**
@ -399,7 +406,7 @@ $.Viewport.prototype = {
*/ */
getBoundsWithMargins: function(current) { getBoundsWithMargins: function(current) {
return this.getBoundsNoRotateWithMargins(current).rotate( return this.getBoundsNoRotateWithMargins(current).rotate(
-this.getRotation(), this.getCenter(current)); -this.getRotation(current), this.getCenter(current));
}, },
/** /**
@ -585,7 +592,7 @@ $.Viewport.prototype = {
bounds.y !== constrainedBounds.y || bounds.y !== constrainedBounds.y ||
immediately) { immediately) {
this.fitBounds( this.fitBounds(
constrainedBounds.rotate(-this.getRotation()), constrainedBounds.rotate(-this.getRotation(true)),
immediately); immediately);
} }
return this; return this;
@ -878,13 +885,27 @@ $.Viewport.prototype = {
* Rotates this viewport to the angle specified. * Rotates this viewport to the angle specified.
* @function * @function
* @param {Number} degrees The degrees to set the rotation to. * @param {Number} degrees The degrees to set the rotation to.
* @param {Boolean} [immediately=false] Whether to animate to the new angle
* or rotate immediately.
* @return {OpenSeadragon.Viewport} Chainable. * @return {OpenSeadragon.Viewport} Chainable.
*/ */
setRotation: function(degrees) { setRotation: function(degrees, immediately) {
if (!this.viewer || !this.viewer.drawer.canRotate()) { if (!this.viewer || !this.viewer.drawer.canRotate()) {
return this; return this;
} }
this.degrees = $.positiveModulo(degrees, 360);
if (this.degreesSpring.target.value === degrees &&
this.degreesSpring.isAtTargetValue()) {
return this;
}
if (immediately) {
this.degreesSpring.resetTo(degrees);
} else {
this.degreesSpring.springTo(degrees);
}
this.degrees = $.positiveModulo(this.degreesSpring.target.value, 360);
this._setContentBounds( this._setContentBounds(
this.viewer.world.getHomeBounds(), this.viewer.world.getHomeBounds(),
this.viewer.world.getContentFactor()); this.viewer.world.getContentFactor());
@ -907,10 +928,13 @@ $.Viewport.prototype = {
/** /**
* Gets the current rotation in degrees. * Gets the current rotation in degrees.
* @function * @function
* @param {Boolean} [current=false] True for current rotation, false for target.
* @return {Number} The current rotation in degrees. * @return {Number} The current rotation in degrees.
*/ */
getRotation: function() { getRotation: function(current) {
return this.degrees; return current ?
this.degreesSpring.current.value :
this.degreesSpring.target.value;
}, },
/** /**
@ -978,13 +1002,18 @@ $.Viewport.prototype = {
this.centerSpringX.update(); this.centerSpringX.update();
this.centerSpringY.update(); this.centerSpringY.update();
this.degreesSpring.update();
var changed = this.centerSpringX.current.value !== this._oldCenterX || var changed = this.centerSpringX.current.value !== this._oldCenterX ||
this.centerSpringY.current.value !== this._oldCenterY || this.centerSpringY.current.value !== this._oldCenterY ||
this.zoomSpring.current.value !== this._oldZoom; this.zoomSpring.current.value !== this._oldZoom ||
this.degreesSpring.current.value !== this._oldDegree;
this._oldCenterX = this.centerSpringX.current.value; this._oldCenterX = this.centerSpringX.current.value;
this._oldCenterY = this.centerSpringY.current.value; this._oldCenterY = this.centerSpringY.current.value;
this._oldZoom = this.zoomSpring.current.value; this._oldZoom = this.zoomSpring.current.value;
this._oldDegree = this.degreesSpring.current.value;
return changed; return changed;
}, },
@ -1035,7 +1064,7 @@ $.Viewport.prototype = {
*/ */
deltaPixelsFromPoints: function(deltaPoints, current) { deltaPixelsFromPoints: function(deltaPoints, current) {
return this.deltaPixelsFromPointsNoRotate( return this.deltaPixelsFromPointsNoRotate(
deltaPoints.rotate(this.getRotation()), deltaPoints.rotate(this.getRotation(current)),
current); current);
}, },
@ -1064,7 +1093,7 @@ $.Viewport.prototype = {
*/ */
deltaPointsFromPixels: function(deltaPixels, current) { deltaPointsFromPixels: function(deltaPixels, current) {
return this.deltaPointsFromPixelsNoRotate(deltaPixels, current) return this.deltaPointsFromPixelsNoRotate(deltaPixels, current)
.rotate(-this.getRotation()); .rotate(-this.getRotation(current));
}, },
/** /**
@ -1106,7 +1135,7 @@ $.Viewport.prototype = {
// private // private
_pixelFromPoint: function(point, bounds) { _pixelFromPoint: function(point, bounds) {
return this._pixelFromPointNoRotate( return this._pixelFromPointNoRotate(
point.rotate(this.getRotation(), this.getCenter(true)), point.rotate(this.getRotation(true), this.getCenter(true)),
bounds); bounds);
}, },
@ -1139,8 +1168,8 @@ $.Viewport.prototype = {
*/ */
pointFromPixel: function(pixel, current) { pointFromPixel: function(pixel, current) {
return this.pointFromPixelNoRotate(pixel, current).rotate( return this.pointFromPixelNoRotate(pixel, current).rotate(
-this.getRotation(), -this.getRotation(current),
this.getCenter(true) this.getCenter(current)
); );
}, },