diff --git a/changelog.txt b/changelog.txt
index b201bbf5..ea669fa1 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -6,7 +6,7 @@ OPENSEADRAGON CHANGELOG
* NEW BEHAVIOR: Setting the viewport rotation now animates by default (pass false for the new immediately parameter to disable) (#2136 @jonasengelmann)
* DEPRECATION: Don't access the viewport's degrees property directly anymore; instead use setRotation and getRotation (#2136 @jonasengelmann)
* New gesture: Double-click and drag to zoom (on by default for touch) (#2225 @HamzaTatheer)
-* You can now provide a pivot point when rotating the viewport (#2233 @ pearcetm)
+* You can now provide a pivot point when rotating the viewport (#2233 #2253 @pearcetm)
* Improved the constraints that keep the image in the viewer, specifically when zoomed out a lot (#2160 @joedf, #2246 @pearcetm)
* You can now provide an element for the navigator (as an alternative to an ID) (#1303 @cameronbaney, #2166 #2175 @joedf)
* Now supporting IIIF "id" and "identifier" in addition to "@id" (#2173 @ahankinson)
@@ -15,6 +15,7 @@ OPENSEADRAGON CHANGELOG
* The viewer now emits before-destroy and destroy events (#2239 @pearcetm)
* Improved documentation (#2211 @shyamkumaryadav)
* Fixed: Cropping tiled images with polygons was broken (#2183 @altert)
+* Fixed: IIIF tile sizes would be calculated wrong on rare occasions (#2206 @filak)
* Fixed: Disabling buttons only changed their appearance, but they were still clickable (#2187 @pearcetm)
* Fixed: ImageTileSource produced an error having to do with getTileHashKey (#2190 @Aiosa)
* Fixed: On startup you would get an unnecessary "Viewer.buttons is deprecated" warning (#2201 @joedf, #2219 @jssullivan, #2212 @joedf)
diff --git a/package-lock.json b/package-lock.json
index b810a4e1..ca799e74 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -695,6 +695,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/callsites": {
"version": "3.1.0",
"dev": true,
@@ -2050,6 +2063,20 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/get-intrinsic": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
+ "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/get-stream": {
"version": "5.2.0",
"dev": true,
@@ -3023,6 +3050,18 @@
"node": ">=4"
}
},
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/has-value": {
"version": "1.0.0",
"dev": true,
@@ -4292,6 +4331,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/object-inspect": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+ "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/object-visit": {
"version": "1.0.1",
"dev": true,
@@ -4856,9 +4904,13 @@
}
},
"node_modules/qs": {
- "version": "6.9.4",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dev": true,
- "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
"engines": {
"node": ">=0.6"
},
@@ -5657,6 +5709,20 @@
"node": ">=8"
}
},
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/snapdragon": {
"version": "0.8.2",
"dev": true,
@@ -6901,6 +6967,16 @@
}
}
},
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
"callsites": {
"version": "3.1.0",
"dev": true
@@ -7800,6 +7876,17 @@
"globule": "^1.0.0"
}
},
+ "get-intrinsic": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
+ "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ }
+ },
"get-stream": {
"version": "5.2.0",
"dev": true,
@@ -8443,6 +8530,12 @@
"version": "3.0.0",
"dev": true
},
+ "has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "dev": true
+ },
"has-value": {
"version": "1.0.0",
"dev": true,
@@ -9288,6 +9381,12 @@
}
}
},
+ "object-inspect": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+ "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
+ "dev": true
+ },
"object-visit": {
"version": "1.0.1",
"dev": true,
@@ -9635,8 +9734,13 @@
}
},
"qs": {
- "version": "6.9.4",
- "dev": true
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dev": true,
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
},
"querystring": {
"version": "0.2.0",
@@ -10194,6 +10298,17 @@
"version": "3.0.0",
"dev": true
},
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
"snapdragon": {
"version": "0.8.2",
"dev": true,
diff --git a/src/iiiftilesource.js b/src/iiiftilesource.js
index 632974a6..08932b56 100644
--- a/src/iiiftilesource.js
+++ b/src/iiiftilesource.js
@@ -134,7 +134,7 @@ $.IIIFTileSource = function( options ){
if (!options.maxLevel && !this.emulateLegacyImagePyramid) {
if (!this.scale_factors) {
- options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2)));
+ options.maxLevel = Number(Math.round(Math.log(Math.max(this.width, this.height), 2)));
} else {
var maxScaleFactor = Math.max.apply(null, this.scale_factors);
options.maxLevel = Math.round(Math.log(maxScaleFactor) * Math.LOG2E);
@@ -377,8 +377,8 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
scale = Math.pow( 0.5, this.maxLevel - level ),
//# image dimensions at this level
- levelWidth = Math.ceil( this.width * scale ),
- levelHeight = Math.ceil( this.height * scale ),
+ levelWidth = Math.round( this.width * scale ),
+ levelHeight = Math.round( this.height * scale ),
//## iiif region
tileWidth,
@@ -398,8 +398,8 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
tileWidth = this.getTileWidth(level);
tileHeight = this.getTileHeight(level);
- iiifTileSizeWidth = Math.ceil( tileWidth / scale );
- iiifTileSizeHeight = Math.ceil( tileHeight / scale );
+ iiifTileSizeWidth = Math.round( tileWidth / scale );
+ iiifTileSizeHeight = Math.round( tileHeight / scale );
if (this.version === 1) {
iiifQuality = "native." + this.tileFormat;
} else {
@@ -426,8 +426,8 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
} else {
iiifRegion = [ iiifTileX, iiifTileY, iiifTileW, iiifTileH ].join( ',' );
}
- iiifSizeW = Math.ceil( iiifTileW * scale );
- iiifSizeH = Math.ceil( iiifTileH * scale );
+ iiifSizeW = Math.round( iiifTileW * scale );
+ iiifSizeH = Math.round( iiifTileH * scale );
if ( this.version === 2 && iiifSizeW === this.width ) {
iiifSize = "full";
} else if ( this.version === 3 && iiifSizeW === this.width && iiifSizeH === this.height ) {
diff --git a/src/viewport.js b/src/viewport.js
index 4a68849c..77d02f2c 100644
--- a/src/viewport.js
+++ b/src/viewport.js
@@ -913,17 +913,15 @@ $.Viewport.prototype = {
},
/**
- * Rotates this viewport to the angle specified. Alias for rotateTo.
+ * Rotates this viewport to the angle specified.
* @function
* @param {Number} degrees The degrees to set the rotation to.
- * @param {OpenSeadragon.Point} [pivot] (Optional) point in viewport coordinates
- * around which the rotation should be performed. Defaults to the center of the viewport.
* @param {Boolean} [immediately=false] Whether to animate to the new angle
* or rotate immediately.
* * @returns {OpenSeadragon.Viewport} Chainable.
*/
- setRotation: function(degrees, pivot, immediately) {
- return this.rotateTo(degrees, pivot, immediately);
+ setRotation: function(degrees, immediately) {
+ return this.rotateTo(degrees, null, immediately);
},
/**
@@ -938,6 +936,20 @@ $.Viewport.prototype = {
this.degreesSpring.target.value;
},
+ /**
+ * Rotates this viewport to the angle specified around a pivot point. Alias for rotateTo.
+ * @function
+ * @param {Number} degrees The degrees to set the rotation to.
+ * @param {OpenSeadragon.Point} [pivot] (Optional) point in viewport coordinates
+ * around which the rotation should be performed. Defaults to the center of the viewport.
+ * @param {Boolean} [immediately=false] Whether to animate to the new angle
+ * or rotate immediately.
+ * * @returns {OpenSeadragon.Viewport} Chainable.
+ */
+ setRotationWithPivot: function(degrees, pivot, immediately) {
+ return this.rotateTo(degrees, pivot, immediately);
+ },
+
/**
* Rotates this viewport to the angle specified.
* @function
diff --git a/test/modules/drawer.js b/test/modules/drawer.js
index e39b48b5..d40c47c1 100644
--- a/test/modules/drawer.js
+++ b/test/modules/drawer.js
@@ -46,7 +46,7 @@
});
viewer.addHandler('open', function handler(event) {
- viewer.viewport.setRotation(30, null, true);
+ 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/navigator.js b/test/modules/navigator.js
index e4636108..0859abb9 100644
--- a/test/modules/navigator.js
+++ b/test/modules/navigator.js
@@ -248,14 +248,8 @@
};
var dragNavigatorBackToCenter = function () {
- var start = viewer.viewport.getBounds().getTopLeft(),
- target = new OpenSeadragon.Point(0.5 - viewer.viewport.getBounds().width / 2,
- 1 / viewer.source.aspectRatio / 2 - viewer.viewport.getBounds().height / 2),
- delta = target.minus(start);
- if (viewer.source.aspectRatio < 1) {
- delta.y *= viewer.source.aspectRatio;
- }
- simulateNavigatorDrag(viewer.navigator, delta.x * displayRegionWidth, delta.y * displayRegionHeight);
+ var delta = viewer.viewport.getHomeBounds().getCenter().minus(viewer.viewport.getCenter()).times(displayRegionWidth);
+ simulateNavigatorDrag(viewer.navigator, delta.x, delta.y);
};
var resizeElement = function ($element, width, height) {
diff --git a/test/modules/tiledimage.js b/test/modules/tiledimage.js
index 4a075328..a6b962f7 100644
--- a/test/modules/tiledimage.js
+++ b/test/modules/tiledimage.js
@@ -9,6 +9,7 @@
testLog.reset();
+ // eslint-disable-next-line new-cap
viewer = OpenSeadragon({
id: 'example',
prefixUrl: '/build/openseadragon/images/',
@@ -517,12 +518,17 @@
var image = viewer.world.getItemAt(0);
assert.equal(image.getFullyLoaded(), false, 'not fully loaded at first');
+ // Zoom out enough that we don't start out with all the tiles loaded.
+ viewer.viewport.zoomBy(0.5, null, true);
+
var count = 0;
var fullyLoadedChangeHandler = function(event) {
if (count === 0) {
assert.equal(event.fullyLoaded, true, 'event includes true fullyLoaded property');
assert.equal(image.getFullyLoaded(), true, 'image is fully loaded after event');
+
+ // Zoom in enough that it needs to load some new tiles.
viewer.viewport.zoomBy(5, null, true);
} else if (count === 1) {
assert.equal(event.fullyLoaded, false, 'event includes false fullyLoaded property');
diff --git a/test/modules/units.js b/test/modules/units.js
index 9f350130..ee47ebe1 100644
--- a/test/modules/units.js
+++ b/test/modules/units.js
@@ -212,13 +212,13 @@
checkPoint(assert, ' after zoom and pan');
//Restore rotation
- viewer.viewport.setRotation(0, null, true);
+ viewer.viewport.setRotation(0, true);
done();
});
viewer.viewport.zoomTo(0.8).panTo(new OpenSeadragon.Point(0.1, 0.2));
});
- viewer.viewport.setRotation(45, null, true);
+ 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 1e4c91f8..e8267efc 100644
--- a/test/modules/viewport.js
+++ b/test/modules/viewport.js
@@ -247,7 +247,7 @@
function openHandler() {
viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport;
- viewport.setRotation(-675, null, true);
+ viewport.setRotation(-675, true);
Util.assertRectangleEquals(
assert,
viewport.getHomeBoundsNoRotate(),
@@ -269,7 +269,7 @@
function openHandler() {
viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport;
- viewport.setRotation(-675, null, true);
+ viewport.setRotation(-675, true);
Util.assertRectangleEquals(
assert,
viewport.getHomeBounds(),
@@ -533,7 +533,7 @@
var openHandler = function() {
viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport;
- viewport.setRotation(45, null, true);
+ viewport.setRotation(45, true);
viewport.fitBounds(new OpenSeadragon.Rect(1, 1, 1, 1), true);
viewport.applyConstraints(true);
var bounds = viewport.getBounds();
@@ -557,7 +557,7 @@
var viewport = viewer.viewport;
viewport.setFlip(true);
- viewport.setRotation(45, null, true);
+ viewport.setRotation(45, true);
viewport.fitBounds(new OpenSeadragon.Rect(1, 1, 1, 1), true);
viewport.applyConstraints(true);
@@ -659,7 +659,7 @@
var openHandler = function(event) {
viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport;
- viewport.setRotation(45, null, true);
+ viewport.setRotation(45, true);
for(var i = 0; i < testRectsFitBounds.length; i++){
var rect = testRectsFitBounds[i];
@@ -1066,12 +1066,12 @@
var viewport = viewer.viewport;
assert.propEqual(viewport.getRotation, 0, "Original rotation should be 0 degrees");
- viewport.setRotation(90, null, true);
+ viewport.setRotation(90, true);
assert.propEqual(viewport.getRotation, 90, "Rotation should be 90 degrees");
- viewport.setRotation(-75, null, true);
+ viewport.setRotation(-75, true);
assert.propEqual(viewport.getRotation, -75, "Rotation should be -75 degrees");
- viewport.setRotation(0, null, true);
+ 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');
@@ -1079,7 +1079,7 @@
assert.strictEqual(viewport.getRotation(true), 0, 'current rotation is not changed');
assert.strictEqual(viewport.getRotation(false), 33, 'target rotation is set correctly');
- viewport.setRotation(200, null, true);
+ 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');
@@ -1099,9 +1099,9 @@
viewport.setFlip(true);
assert.propEqual(viewport.getRotation, 0, "Original flipped rotation should be 0 degrees");
- viewport.setRotation(90, null, true);
+ viewport.setRotation(90, true);
assert.propEqual(viewport.getRotation, 90, "Flipped rotation should be 90 degrees");
- viewport.setRotation(-75, null, true);
+ viewport.setRotation(-75, true);
assert.propEqual(viewport.getRotation, -75, "Flipped rotation should be -75 degrees");
done();
diff --git a/test/test.html b/test/test.html
index 7a1a6b1a..8b85a123 100644
--- a/test/test.html
+++ b/test/test.html
@@ -50,6 +50,6 @@
-
+