From 8519e30a3ac186f840ae22bb7173b3c400d64770 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Tue, 29 Mar 2022 16:50:18 +0200 Subject: [PATCH 01/17] added viewport rotation animation --- src/drawer.js | 26 +++++++++++---------- src/overlay.js | 10 ++++----- src/tiledimage.js | 37 ++++++++++++++++-------------- src/viewer.js | 8 +++---- src/viewport.js | 57 +++++++++++++++++++++++++++++++++++------------ 5 files changed, 86 insertions(+), 52 deletions(-) diff --git a/src/drawer.js b/src/drawer.js index 30d7fcf2..e316704a 100644 --- a/src/drawer.js +++ b/src/drawer.js @@ -547,8 +547,8 @@ $.Drawer.prototype = { context.strokeStyle = this.debugGridColor[colorIndex]; context.fillStyle = this.debugGridColor[colorIndex]; - if ( this.viewport.degrees !== 0 ) { - this._offsetForRotation({degrees: this.viewport.degrees}); + if (this.viewport.getRotation(true) % 360 !== 0 ) { + this._offsetForRotation({degrees: this.viewport.getRotation(true)}); } if (tiledImage.getRotation(true) % 360 !== 0) { this._offsetForRotation({ @@ -557,10 +557,11 @@ $.Drawer.prototype = { tiledImage._getRotationPoint(true), true) }); } - if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){ - if(tiledImage._drawer.viewer.viewport.getFlip()) { - tiledImage._drawer._flip(); - } + if (tiledImage.viewport.getRotation(true) % 360 === 0 && + tiledImage.getRotation(true) % 360 === 0) { + if(tiledImage._drawer.viewer.viewport.getFlip()) { + tiledImage._drawer._flip(); + } } context.strokeRect( @@ -575,7 +576,7 @@ $.Drawer.prototype = { // Rotate the text the right way around. 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 ); if( tile.x === 0 && tile.y === 0 ){ @@ -621,17 +622,18 @@ $.Drawer.prototype = { (tile.position.y + 70) * $.pixelDensityRatio ); - if ( this.viewport.degrees !== 0 ) { + if (this.viewport.getRotation(true) % 360 !== 0 ) { this._restoreRotationChanges(); } if (tiledImage.getRotation(true) % 360 !== 0) { this._restoreRotationChanges(); } - if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){ - if(tiledImage._drawer.viewer.viewport.getFlip()) { - tiledImage._drawer._flip(); - } + if (tiledImage.viewport.getRotation(true) % 360 === 0 && + tiledImage.getRotation(true) % 360 === 0) { + if(tiledImage._drawer.viewer.viewport.getFlip()) { + tiledImage._drawer._flip(); + } } context.restore(); diff --git a/src/overlay.js b/src/overlay.js index 9fd1532c..18ceca02 100644 --- a/src/overlay.js +++ b/src/overlay.js @@ -299,18 +299,18 @@ this.adjust(position, size); var rotate = 0; - if (viewport.degrees && + if (viewport.getRotation(true) && this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) { // BOUNDING_BOX is only valid if both directions get scaled. // Get replaced by EXACT otherwise. if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX && this.width !== null && this.height !== null) { 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(); size = boundingBox.getSize(); } else { - rotate = viewport.degrees; + rotate = viewport.getRotation(true); } } @@ -447,7 +447,7 @@ // private _adjustBoundsForRotation: function(viewport, bounds) { if (!viewport || - viewport.degrees === 0 || + viewport.getRotation(true) === 0 || this.rotationMode === $.OverlayRotationMode.EXACT) { return bounds; } @@ -467,7 +467,7 @@ } // NO_ROTATION case - return bounds.rotate(-viewport.degrees, + return bounds.rotate(-viewport.getRotation(true), this._getPlacementPoint(bounds)); } }; diff --git a/src/tiledimage.js b/src/tiledimage.js index 80204328..a8692d77 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -2076,9 +2076,10 @@ function drawTiles( tiledImage, lastDrawn ) { .getIntegerBoundingBox(); if(tiledImage._drawer.viewer.viewport.getFlip()) { - if (tiledImage.viewport.degrees !== 0 || tiledImage.getRotation(true) % 360 !== 0){ - bounds.x = tiledImage._drawer.viewer.container.clientWidth - (bounds.x + bounds.width); - } + if (tiledImage.viewport.getRotation(true) % 360 !== 0 || + tiledImage.getRotation(true) % 360 !== 0) { + bounds.x = tiledImage._drawer.viewer.container.clientWidth - (bounds.x + bounds.width); + } } bounds = bounds.times($.pixelDensityRatio); @@ -2089,9 +2090,9 @@ function drawTiles( tiledImage, lastDrawn ) { // When scaling, we must rotate only when blending the sketch canvas to // avoid interpolation if (!sketchScale) { - if (tiledImage.viewport.degrees !== 0) { + if (tiledImage.viewport.getRotation(true) % 360 !== 0) { tiledImage._drawer._offsetForRotation({ - degrees: tiledImage.viewport.degrees, + degrees: tiledImage.viewport.getRotation(true), useSketch: useSketch }); } @@ -2104,10 +2105,11 @@ function drawTiles( tiledImage, lastDrawn ) { }); } - if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){ - if(tiledImage._drawer.viewer.viewport.getFlip()) { - tiledImage._drawer._flip(); - } + if (tiledImage.viewport.getRotation(true) === 0 && + tiledImage.getRotation(true) % 360 === 0) { + if(tiledImage._drawer.viewer.viewport.getFlip()) { + tiledImage._drawer._flip(); + } } } @@ -2214,16 +2216,16 @@ function drawTiles( tiledImage, lastDrawn ) { if (tiledImage.getRotation(true) % 360 !== 0) { tiledImage._drawer._restoreRotationChanges(useSketch); } - if (tiledImage.viewport.degrees !== 0) { + if (tiledImage.viewport.getRotation(true) % 360 !== 0) { tiledImage._drawer._restoreRotationChanges(useSketch); } } if (useSketch) { if (sketchScale) { - if (tiledImage.viewport.degrees !== 0) { + if (tiledImage.viewport.getRotation(true) % 360 !== 0) { tiledImage._drawer._offsetForRotation({ - degrees: tiledImage.viewport.degrees, + degrees: tiledImage.viewport.getRotation(true), useSketch: false }); } @@ -2247,18 +2249,19 @@ function drawTiles( tiledImage, lastDrawn ) { if (tiledImage.getRotation(true) % 360 !== 0) { tiledImage._drawer._restoreRotationChanges(false); } - if (tiledImage.viewport.degrees !== 0) { + if (tiledImage.viewport.getRotation(true) % 360 !== 0) { tiledImage._drawer._restoreRotationChanges(false); } } } if (!sketchScale) { - if (tiledImage.viewport.degrees === 0 && tiledImage.getRotation(true) % 360 === 0){ - if(tiledImage._drawer.viewer.viewport.getFlip()) { - tiledImage._drawer._flip(); + if (tiledImage.viewport.getRotation(true) % 360 === 0 && + tiledImage.getRotation(true) % 360 === 0) { + if(tiledImage._drawer.viewer.viewport.getFlip()) { + tiledImage._drawer._flip(); + } } - } } drawDebugInfo( tiledImage, lastDrawn ); diff --git a/src/viewer.js b/src/viewer.js index 8d7be6ae..a138e2de 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -2810,18 +2810,18 @@ function onCanvasKeyPress( event ) { break; case 114: //r - clockwise rotation 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{ - this.viewport.setRotation($.positiveModulo(this.viewport.degrees + this.rotationIncrement, 360)); + this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() + this.rotationIncrement, 360)); } this.viewport.applyConstraints(); event.preventDefault = true; break; case 82: //R - counterclockwise rotation 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{ - this.viewport.setRotation($.positiveModulo(this.viewport.degrees - this.rotationIncrement, 360)); + this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() - this.rotationIncrement, 360)); } this.viewport.applyConstraints(); event.preventDefault = true; diff --git a/src/viewport.js b/src/viewport.js index be350af9..028c5916 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -133,9 +133,16 @@ $.Viewport = function( options ) { animationTime: this.animationTime }); + this.degreesSpring = new $.Spring({ + initial: 0, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + this._oldCenterX = this.centerSpringX.current.value; this._oldCenterY = this.centerSpringY.current.value; this._oldZoom = this.zoomSpring.current.value; + this._oldDegree = this.degreesSpring.current.value; this._setContentBounds(new $.Rect(0, 0, 1, 1), 1); @@ -184,7 +191,7 @@ $.Viewport.prototype = { this._contentSizeNoRotate = this._contentBoundsNoRotate.getSize().times( contentFactor); - this._contentBounds = bounds.rotate(this.degrees).getBoundingBox(); + this._contentBounds = bounds.rotate(this.getRotation(true)).getBoundingBox(); this._contentSize = this._contentBounds.getSize().times(contentFactor); 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. */ 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) { 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 || immediately) { this.fitBounds( - constrainedBounds.rotate(-this.getRotation()), + constrainedBounds.rotate(-this.getRotation(true)), immediately); } return this; @@ -878,13 +885,27 @@ $.Viewport.prototype = { * Rotates this viewport to the angle specified. * @function * @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. */ - setRotation: function(degrees) { + setRotation: function(degrees, immediately) { if (!this.viewer || !this.viewer.drawer.canRotate()) { 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.viewer.world.getHomeBounds(), this.viewer.world.getContentFactor()); @@ -907,10 +928,13 @@ $.Viewport.prototype = { /** * Gets the current rotation in degrees. * @function + * @param {Boolean} [current=false] True for current rotation, false for target. * @return {Number} The current rotation in degrees. */ - getRotation: function() { - return this.degrees; + getRotation: function(current) { + return current ? + this.degreesSpring.current.value : + this.degreesSpring.target.value; }, /** @@ -978,13 +1002,18 @@ $.Viewport.prototype = { this.centerSpringX.update(); this.centerSpringY.update(); + this.degreesSpring.update(); + var changed = this.centerSpringX.current.value !== this._oldCenterX || 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._oldCenterY = this.centerSpringY.current.value; this._oldZoom = this.zoomSpring.current.value; + this._oldDegree = this.degreesSpring.current.value; return changed; }, @@ -1035,7 +1064,7 @@ $.Viewport.prototype = { */ deltaPixelsFromPoints: function(deltaPoints, current) { return this.deltaPixelsFromPointsNoRotate( - deltaPoints.rotate(this.getRotation()), + deltaPoints.rotate(this.getRotation(current)), current); }, @@ -1064,7 +1093,7 @@ $.Viewport.prototype = { */ deltaPointsFromPixels: function(deltaPixels, current) { return this.deltaPointsFromPixelsNoRotate(deltaPixels, current) - .rotate(-this.getRotation()); + .rotate(-this.getRotation(current)); }, /** @@ -1106,7 +1135,7 @@ $.Viewport.prototype = { // private _pixelFromPoint: function(point, bounds) { return this._pixelFromPointNoRotate( - point.rotate(this.getRotation(), this.getCenter(true)), + point.rotate(this.getRotation(true), this.getCenter(true)), bounds); }, @@ -1139,8 +1168,8 @@ $.Viewport.prototype = { */ pointFromPixel: function(pixel, current) { return this.pointFromPixelNoRotate(pixel, current).rotate( - -this.getRotation(), - this.getCenter(true) + -this.getRotation(current), + this.getCenter(current) ); }, From 65957efe72747cc6c008c8e98514f15407c960ee Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Tue, 29 Mar 2022 16:55:47 +0200 Subject: [PATCH 02/17] updated docs --- src/openseadragon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openseadragon.js b/src/openseadragon.js index ef002f37..3801f7cb 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -332,7 +332,7 @@ * * @property {Number} [animationTime=1.2] * Specifies the animation duration per each {@link OpenSeadragon.Spring} - * which occur when the image is dragged or zoomed. + * which occur when the image is dragged, zoomed or rotated. * * @property {OpenSeadragon.GestureSettings} [gestureSettingsMouse] * Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings}) From 1cbc2d96c1801a962f808a708ea8822fdc0a3815 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Tue, 29 Mar 2022 19:18:25 +0200 Subject: [PATCH 03/17] fixed initial degree option --- src/viewport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/viewport.js b/src/viewport.js index 028c5916..3a6e339a 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -134,7 +134,7 @@ $.Viewport = function( options ) { }); this.degreesSpring = new $.Spring({ - initial: 0, + initial: options.degrees, springStiffness: this.springStiffness, animationTime: this.animationTime }); From 8746e8b243e703c7ca1bbf8c07fe58ea3bfbecce Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Wed, 30 Mar 2022 22:37:14 +0200 Subject: [PATCH 04/17] fixed wrong getHomeBounds --- src/viewport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/viewport.js b/src/viewport.js index 3a6e339a..118f8184 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -191,7 +191,7 @@ $.Viewport.prototype = { this._contentSizeNoRotate = this._contentBoundsNoRotate.getSize().times( contentFactor); - this._contentBounds = bounds.rotate(this.getRotation(true)).getBoundingBox(); + this._contentBounds = bounds.rotate(this.getRotation()).getBoundingBox(); this._contentSize = this._contentBounds.getSize().times(contentFactor); this._contentAspectRatio = this._contentSize.x / this._contentSize.y; From dc2a1534d3b904eb0150f874041a98856062d829 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Wed, 30 Mar 2022 22:59:29 +0200 Subject: [PATCH 05/17] removed modulo for degrees to avoid spining --- src/viewer.js | 16 ++++++++-------- src/viewport.js | 3 +-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/viewer.js b/src/viewer.js index a138e2de..985ba468 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -2810,18 +2810,18 @@ function onCanvasKeyPress( event ) { break; case 114: //r - clockwise rotation if(this.viewport.flipped){ - this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() - this.rotationIncrement, 360)); + this.viewport.setRotation(this.viewport.getRotation() - this.rotationIncrement); } else{ - this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() + this.rotationIncrement, 360)); + this.viewport.setRotation(this.viewport.getRotation() + this.rotationIncrement); } this.viewport.applyConstraints(); event.preventDefault = true; break; case 82: //R - counterclockwise rotation if(this.viewport.flipped){ - this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() + this.rotationIncrement, 360)); + this.viewport.setRotation(this.viewport.getRotation() + this.rotationIncrement); } else{ - this.viewport.setRotation($.positiveModulo(this.viewport.getRotation() - this.rotationIncrement, 360)); + this.viewport.setRotation(this.viewport.getRotation() - this.rotationIncrement); } this.viewport.applyConstraints(); event.preventDefault = true; @@ -3708,9 +3708,9 @@ function onRotateLeft() { var currRotation = this.viewport.getRotation(); if ( this.viewport.flipped ){ - currRotation = $.positiveModulo(currRotation + this.rotationIncrement, 360); + currRotation += this.rotationIncrement; } else { - currRotation = $.positiveModulo(currRotation - this.rotationIncrement, 360); + currRotation -= this.rotationIncrement; } this.viewport.setRotation(currRotation); } @@ -3721,9 +3721,9 @@ function onRotateRight() { var currRotation = this.viewport.getRotation(); if ( this.viewport.flipped ){ - currRotation = $.positiveModulo(currRotation - this.rotationIncrement, 360); + currRotation -= this.rotationIncrement; } else { - currRotation = $.positiveModulo(currRotation + this.rotationIncrement, 360); + currRotation += this.rotationIncrement; } this.viewport.setRotation(currRotation); } diff --git a/src/viewport.js b/src/viewport.js index 118f8184..d37bfbae 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -138,6 +138,7 @@ $.Viewport = function( options ) { springStiffness: this.springStiffness, animationTime: this.animationTime }); + delete options.degrees; this._oldCenterX = this.centerSpringX.current.value; this._oldCenterY = this.centerSpringY.current.value; @@ -904,8 +905,6 @@ $.Viewport.prototype = { this.degreesSpring.springTo(degrees); } - this.degrees = $.positiveModulo(this.degreesSpring.target.value, 360); - this._setContentBounds( this.viewer.world.getHomeBounds(), this.viewer.world.getContentFactor()); From fb8bafc6a04eabb7096e4cf7db98864847154ad6 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Wed, 30 Mar 2022 23:05:14 +0200 Subject: [PATCH 06/17] updated tests --- test/modules/controls.js | 6 +++--- test/modules/drawer.js | 2 +- test/modules/units.js | 4 ++-- test/modules/viewport.js | 30 +++++++++++++++++++++--------- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/test/modules/controls.js b/test/modules/controls.js index 0e6bdf7c..7e774d9b 100644 --- a/test/modules/controls.js +++ b/test/modules/controls.js @@ -230,11 +230,11 @@ // Now simulate the left/right button clicks. // TODO: re-factor simulateViewerClickWithDrag so it'll accept any element, and use that. - assert.equal(viewer.viewport.degrees, 0, "Image should start at 0 degrees rotation"); + assert.equal(viewer.viewport.getRotation(), 0, "Image should start at 0 degrees rotation"); viewer.rotateLeftButton.onRelease(); - assert.equal(viewer.viewport.degrees, 270, "Image should be 270 degrees rotation (left)"); + assert.equal(viewer.viewport.getRotation(), -90, "Image should be -90 degrees rotation (left)"); viewer.rotateRightButton.onRelease(); - assert.equal(viewer.viewport.degrees, 0, "Image should be 270 degrees rotation (right)"); + assert.equal(viewer.viewport.getRotation(), 0, "Image should be 0 degrees rotation (right)"); viewer.close(); done(); diff --git a/test/modules/drawer.js b/test/modules/drawer.js index ba53ba2d..4fd1a29f 100644 --- a/test/modules/drawer.js +++ b/test/modules/drawer.js @@ -45,7 +45,7 @@ }); viewer.addHandler('open', function handler(event) { - viewer.viewport.setRotation(30); + viewer.viewport.setRotation(30, true); Util.spyOnce(viewer.drawer.context, 'rotate', function() { assert.ok(true, 'drawing with new rotation'); done(); diff --git a/test/modules/units.js b/test/modules/units.js index 6d0bc74d..46e27ec2 100644 --- a/test/modules/units.js +++ b/test/modules/units.js @@ -210,13 +210,13 @@ checkPoint(assert, ' after zoom and pan'); //Restore rotation - viewer.viewport.setRotation(0); + viewer.viewport.setRotation(0, true); done(); }); viewer.viewport.zoomTo(0.8).panTo(new OpenSeadragon.Point(0.1, 0.2)); }); - viewer.viewport.setRotation(45); + viewer.viewport.setRotation(45, true); viewer.open([{ tileSource: "/test/data/testpattern.dzi" }, { diff --git a/test/modules/viewport.js b/test/modules/viewport.js index d820d5d6..59597060 100644 --- a/test/modules/viewport.js +++ b/test/modules/viewport.js @@ -245,7 +245,7 @@ function openHandler() { viewer.removeHandler('open', openHandler); var viewport = viewer.viewport; - viewport.setRotation(-675); + viewport.setRotation(-675, true); Util.assertRectangleEquals( assert, viewport.getHomeBoundsNoRotate(), @@ -267,7 +267,7 @@ function openHandler() { viewer.removeHandler('open', openHandler); var viewport = viewer.viewport; - viewport.setRotation(-675); + viewport.setRotation(-675, true); Util.assertRectangleEquals( assert, viewport.getHomeBounds(), @@ -531,7 +531,7 @@ var openHandler = function() { viewer.removeHandler('open', openHandler); var viewport = viewer.viewport; - viewport.setRotation(45); + viewport.setRotation(45, true); viewport.fitBounds(new OpenSeadragon.Rect(1, 1, 1, 1), true); viewport.applyConstraints(true); var bounds = viewport.getBounds(); @@ -555,7 +555,7 @@ var viewport = viewer.viewport; viewport.setFlip(true); - viewport.setRotation(45); + viewport.setRotation(45, true); viewport.fitBounds(new OpenSeadragon.Rect(1, 1, 1, 1), true); viewport.applyConstraints(true); @@ -657,7 +657,7 @@ var openHandler = function(event) { viewer.removeHandler('open', openHandler); var viewport = viewer.viewport; - viewport.setRotation(45); + viewport.setRotation(45, true); for(var i = 0; i < testRectsFitBounds.length; i++){ var rect = testRectsFitBounds[i]; @@ -1064,11 +1064,23 @@ var viewport = viewer.viewport; assert.propEqual(viewport.getRotation, 0, "Original rotation should be 0 degrees"); - viewport.setRotation(90); + viewport.setRotation(90, true); assert.propEqual(viewport.getRotation, 90, "Rotation should be 90 degrees"); - viewport.setRotation(-75); + viewport.setRotation(-75, true); assert.propEqual(viewport.getRotation, -75, "Rotation should be -75 degrees"); + viewport.setRotation(0, true); + assert.strictEqual(viewport.getRotation(true), 0, 'viewport has default current rotation'); + assert.strictEqual(viewport.getRotation(false), 0, 'viewport has default target rotation'); + + viewport.setRotation(400); + assert.strictEqual(viewport.getRotation(true), 0, 'current rotation is not changed'); + assert.strictEqual(viewport.getRotation(false), 400, 'target rotation is set correctly'); + + viewport.setRotation(200, true); + assert.strictEqual(viewport.getRotation(true), 200, 'current rotation is set correctly'); + assert.strictEqual(viewport.getRotation(false), 200, 'target rotation is set correctly'); + done(); }; @@ -1085,9 +1097,9 @@ viewport.setFlip(true); assert.propEqual(viewport.getRotation, 0, "Original flipped rotation should be 0 degrees"); - viewport.setRotation(90); + viewport.setRotation(90, true); assert.propEqual(viewport.getRotation, 90, "Flipped rotation should be 90 degrees"); - viewport.setRotation(-75); + viewport.setRotation(-75, true); assert.propEqual(viewport.getRotation, -75, "Flipped rotation should be -75 degrees"); done(); From ef8e7ad9c5dde439832ddc7e6e1baf3cb85ae692 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Wed, 30 Mar 2022 23:41:43 +0200 Subject: [PATCH 07/17] fixed typo --- src/viewport.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/viewport.js b/src/viewport.js index d37bfbae..853458df 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -143,7 +143,7 @@ $.Viewport = function( options ) { this._oldCenterX = this.centerSpringX.current.value; this._oldCenterY = this.centerSpringY.current.value; this._oldZoom = this.zoomSpring.current.value; - this._oldDegree = this.degreesSpring.current.value; + this._oldDegrees = this.degreesSpring.current.value; this._setContentBounds(new $.Rect(0, 0, 1, 1), 1); @@ -1006,13 +1006,13 @@ $.Viewport.prototype = { var changed = this.centerSpringX.current.value !== this._oldCenterX || this.centerSpringY.current.value !== this._oldCenterY || this.zoomSpring.current.value !== this._oldZoom || - this.degreesSpring.current.value !== this._oldDegree; + this.degreesSpring.current.value !== this._oldDegrees; this._oldCenterX = this.centerSpringX.current.value; this._oldCenterY = this.centerSpringY.current.value; this._oldZoom = this.zoomSpring.current.value; - this._oldDegree = this.degreesSpring.current.value; + this._oldDegrees = this.degreesSpring.current.value; return changed; }, From c2821b177530d00319d88ad69499f629ee5d0356 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Thu, 31 Mar 2022 23:45:46 +0200 Subject: [PATCH 08/17] set initial navigator animation time to viewport's --- src/navigator.js | 2 +- src/viewer.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/navigator.js b/src/navigator.js index 81993b74..dfd1a7fa 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -107,7 +107,7 @@ $.Navigator = function( options ){ showSequenceControl: false, immediateRender: true, blendTime: 0, - animationTime: 0, + animationTime: options.animationTime, autoResize: options.autoResize, // prevent resizing the navigator from adding unwanted space around the image minZoomImageRatio: 1.0, diff --git a/src/viewer.js b/src/viewer.js index 985ba468..2b6a6b4a 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -448,7 +448,8 @@ $.Viewer = function( options ) { opacity: this.navigatorOpacity, borderColor: this.navigatorBorderColor, displayRegionColor: this.navigatorDisplayRegionColor, - crossOriginPolicy: this.crossOriginPolicy + crossOriginPolicy: this.crossOriginPolicy, + animationTime: this.animationTime, }); } From d62538f42eb9fccc265edb70e463e87279841fcb Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Thu, 31 Mar 2022 23:50:38 +0200 Subject: [PATCH 09/17] fixed white space --- src/viewport.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/viewport.js b/src/viewport.js index 853458df..122708b1 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -143,7 +143,7 @@ $.Viewport = function( options ) { this._oldCenterX = this.centerSpringX.current.value; this._oldCenterY = this.centerSpringY.current.value; this._oldZoom = this.zoomSpring.current.value; - this._oldDegrees = this.degreesSpring.current.value; + this._oldDegrees = this.degreesSpring.current.value; this._setContentBounds(new $.Rect(0, 0, 1, 1), 1); @@ -1012,7 +1012,7 @@ $.Viewport.prototype = { this._oldCenterX = this.centerSpringX.current.value; this._oldCenterY = this.centerSpringY.current.value; this._oldZoom = this.zoomSpring.current.value; - this._oldDegrees = this.degreesSpring.current.value; + this._oldDegrees = this.degreesSpring.current.value; return changed; }, From c16d1e3dff7bf6c299eb67b2a758903ae1926f1b Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Fri, 1 Apr 2022 10:06:18 +0200 Subject: [PATCH 10/17] ensure backward compatibility --- src/viewer.js | 2 +- src/viewport.js | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/viewer.js b/src/viewer.js index 2b6a6b4a..0778e1e0 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -378,7 +378,7 @@ $.Viewer = function( options ) { minZoomLevel: this.minZoomLevel, maxZoomLevel: this.maxZoomLevel, viewer: this, - degrees: this.degrees, + initialDegrees: this.degrees, flipped: this.flipped, navigatorRotate: this.navigatorRotate, homeFillsViewer: this.homeFillsViewer, diff --git a/src/viewport.js b/src/viewport.js index 122708b1..dffad0f1 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -107,7 +107,7 @@ $.Viewport = function( options ) { defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel, minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel, maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel, - degrees: $.DEFAULT_SETTINGS.degrees, + initialDegrees: $.DEFAULT_SETTINGS.degrees, flipped: $.DEFAULT_SETTINGS.flipped, homeFillsViewer: $.DEFAULT_SETTINGS.homeFillsViewer, silenceMultiImageWarnings: $.DEFAULT_SETTINGS.silenceMultiImageWarnings @@ -134,11 +134,10 @@ $.Viewport = function( options ) { }); this.degreesSpring = new $.Spring({ - initial: options.degrees, + initial: options.initialDegrees, springStiffness: this.springStiffness, animationTime: this.animationTime }); - delete options.degrees; this._oldCenterX = this.centerSpringX.current.value; this._oldCenterY = this.centerSpringY.current.value; @@ -153,6 +152,19 @@ $.Viewport = function( options ) { /** @lends OpenSeadragon.Viewport.prototype */ $.Viewport.prototype = { + + // deprecated + get degrees () { + $.console.warn('Accessing [Viewport.degrees] is deprecated. Use viewport.getRotation instead.'); + return this.getRotation(); + }, + + // deprecated + set degrees (degrees) { + $.console.warn('Setting [Viewport.degrees] is deprecated. Use viewport.setRotation instead.'); + this.setRotation(degrees); + }, + /** * Updates the viewport's home bounds and constraints for the given content size. * @function From 62e24ac1ab6df5cf9046f1476869525199144225 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Tue, 19 Apr 2022 16:43:00 +0200 Subject: [PATCH 11/17] ensure constructor backward compatibility --- src/viewer.js | 2 +- src/viewport.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/viewer.js b/src/viewer.js index 0778e1e0..2b6a6b4a 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -378,7 +378,7 @@ $.Viewer = function( options ) { minZoomLevel: this.minZoomLevel, maxZoomLevel: this.maxZoomLevel, viewer: this, - initialDegrees: this.degrees, + degrees: this.degrees, flipped: this.flipped, navigatorRotate: this.navigatorRotate, homeFillsViewer: this.homeFillsViewer, diff --git a/src/viewport.js b/src/viewport.js index dffad0f1..203fe07f 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -86,6 +86,9 @@ $.Viewport = function( options ) { delete options.margins; + options.initialDegrees = options.degrees; + delete options.degrees; + $.extend( true, this, { //required settings From 1b27e59be80a70d2169a8ff896925d2ca3b10535 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Wed, 29 Jun 2022 19:47:03 +0200 Subject: [PATCH 12/17] added Euclidean modulo helper function --- src/openseadragon.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/openseadragon.js b/src/openseadragon.js index cc2373ae..6a3d734f 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -1635,7 +1635,7 @@ function OpenSeadragon( options ){ /** * Compute the modulo of a number but makes sure to always return * a positive value. - * @param {Number} number the number to computes the modulo of + * @param {Number} number the number to compute the modulo of * @param {Number} modulo the modulo * @returns {Number} the result of the modulo of number */ @@ -1647,6 +1647,16 @@ function OpenSeadragon( options ){ return result; }, + /** + * Computes Euclidean modulo of m % n. + * @param {Number} number the number to compute the modulo of + * @param {Number} modulo the modulo + * @returns {Number} the result of the modulo of number + */ + euclideanModulo: function(number, modulo) { + return ( ( number % modulo ) + modulo ) % modulo; + }, + /** * Determines if a point is within the bounding rectangle of the given element (hit-test). * @function From 3cdd94e46548214f9bf335a49d93867526d5fc4c Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Wed, 29 Jun 2022 19:47:26 +0200 Subject: [PATCH 13/17] constrained rotation to shortest path --- src/viewport.js | 11 ++++++++++- test/modules/viewport.js | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/viewport.js b/src/viewport.js index 203fe07f..9a058968 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -917,7 +917,16 @@ $.Viewport.prototype = { if (immediately) { this.degreesSpring.resetTo(degrees); } else { - this.degreesSpring.springTo(degrees); + var from = $.euclideanModulo(this.degreesSpring.current.value, 360); + this.degreesSpring.resetTo(from); + var to = $.euclideanModulo(degrees, 360); + var diff = to - from; + if (diff > 180) { + to -= 360; + } else if (diff < -180) { + to += 360; + } + this.degreesSpring.springTo(to); } this._setContentBounds( diff --git a/test/modules/viewport.js b/test/modules/viewport.js index 59597060..804af1e9 100644 --- a/test/modules/viewport.js +++ b/test/modules/viewport.js @@ -1075,7 +1075,7 @@ viewport.setRotation(400); assert.strictEqual(viewport.getRotation(true), 0, 'current rotation is not changed'); - assert.strictEqual(viewport.getRotation(false), 400, 'target rotation is set correctly'); + assert.strictEqual(viewport.getRotation(false), 40, 'target rotation is set correctly'); viewport.setRotation(200, true); assert.strictEqual(viewport.getRotation(true), 200, 'current rotation is set correctly'); From 32af983910f84d1fbc15dfa6e13d37d3895a57e6 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Wed, 29 Jun 2022 20:32:47 +0200 Subject: [PATCH 14/17] always return Euclidean modulo of current rotation --- src/viewport.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/viewport.js b/src/viewport.js index 9a058968..4d8b9c9a 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -956,8 +956,8 @@ $.Viewport.prototype = { */ getRotation: function(current) { return current ? - this.degreesSpring.current.value : - this.degreesSpring.target.value; + $.euclideanModulo(this.degreesSpring.current.value, 360) : + $.euclideanModulo(this.degreesSpring.target.value, 360); }, /** From ddd4a05e5e27a05cd1dd32bcf51b008416b9078f Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Thu, 7 Jul 2022 16:31:35 +0200 Subject: [PATCH 15/17] Revert "always return Euclidean modulo of current rotation" This reverts commit 32af983910f84d1fbc15dfa6e13d37d3895a57e6. --- src/viewport.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/viewport.js b/src/viewport.js index 4d8b9c9a..9a058968 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -956,8 +956,8 @@ $.Viewport.prototype = { */ getRotation: function(current) { return current ? - $.euclideanModulo(this.degreesSpring.current.value, 360) : - $.euclideanModulo(this.degreesSpring.target.value, 360); + this.degreesSpring.current.value : + this.degreesSpring.target.value; }, /** From 9bce0e696cfa81a5b9091d179fb77554789c35d7 Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Mon, 22 Aug 2022 15:31:35 +0200 Subject: [PATCH 16/17] removed redundant EuclideanModulo function --- src/openseadragon.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/openseadragon.js b/src/openseadragon.js index 6a3d734f..a32c5dd0 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -1634,7 +1634,7 @@ function OpenSeadragon( options ){ /** * Compute the modulo of a number but makes sure to always return - * a positive value. + * a positive value (also known as Euclidean modulo). * @param {Number} number the number to compute the modulo of * @param {Number} modulo the modulo * @returns {Number} the result of the modulo of number @@ -1647,15 +1647,6 @@ function OpenSeadragon( options ){ return result; }, - /** - * Computes Euclidean modulo of m % n. - * @param {Number} number the number to compute the modulo of - * @param {Number} modulo the modulo - * @returns {Number} the result of the modulo of number - */ - euclideanModulo: function(number, modulo) { - return ( ( number % modulo ) + modulo ) % modulo; - }, /** * Determines if a point is within the bounding rectangle of the given element (hit-test). From 5f50d9e59e27a568c34879595c48ac36b0eadece Mon Sep 17 00:00:00 2001 From: jonasengelmann <40031476+jonasengelmann@users.noreply.github.com> Date: Mon, 22 Aug 2022 15:34:29 +0200 Subject: [PATCH 17/17] reworked setRotation to allow all degree values --- src/viewport.js | 16 +++++++++------- test/modules/viewport.js | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/viewport.js b/src/viewport.js index 9a058968..f8d7ea24 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -917,16 +917,18 @@ $.Viewport.prototype = { if (immediately) { this.degreesSpring.resetTo(degrees); } else { - var from = $.euclideanModulo(this.degreesSpring.current.value, 360); - this.degreesSpring.resetTo(from); - var to = $.euclideanModulo(degrees, 360); - var diff = to - from; + var normalizedFrom = $.positiveModulo(this.degreesSpring.current.value, 360); + var normalizedTo = $.positiveModulo(degrees, 360); + var diff = normalizedTo - normalizedFrom; if (diff > 180) { - to -= 360; + normalizedTo -= 360; } else if (diff < -180) { - to += 360; + normalizedTo += 360; } - this.degreesSpring.springTo(to); + + var reverseDiff = normalizedFrom - normalizedTo; + this.degreesSpring.resetTo(degrees + reverseDiff); + this.degreesSpring.springTo(degrees); } this._setContentBounds( diff --git a/test/modules/viewport.js b/test/modules/viewport.js index 804af1e9..59597060 100644 --- a/test/modules/viewport.js +++ b/test/modules/viewport.js @@ -1075,7 +1075,7 @@ viewport.setRotation(400); assert.strictEqual(viewport.getRotation(true), 0, 'current rotation is not changed'); - assert.strictEqual(viewport.getRotation(false), 40, 'target rotation is set correctly'); + assert.strictEqual(viewport.getRotation(false), 400, 'target rotation is set correctly'); viewport.setRotation(200, true); assert.strictEqual(viewport.getRotation(true), 200, 'current rotation is set correctly');