diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 00000000..bc1e4a8b --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,39 @@ +cff-version: 1.2.0 +title: OpenSeadragon +message: "If you use this software, please cite it using the metadata from this file." +type: software +authors: + - given-names: Ian + family-names: Gilman + email: ian@iangilman.com + - given-names: Aseem + family-names: Kishore + - given-names: Chris + family-names: Thatcher + - given-names: Mark + family-names: Salsbery + - given-names: Antoine + family-names: Vandecreme + - given-names: Thomas + family-names: Pearce +identifiers: + - type: url + value: https://openseadragon.github.io/ + description: Homepage + - type: url + value: https://github.com/openseadragon/openseadragon + description: Repository +repository-code: https://github.com/openseadragon/openseadragon +url: https://openseadragon.github.io/ +abstract: "An open-source, web-based viewer for high-resolution zoomable images, implemented in pure JavaScript, for desktop and mobile." +keywords: + - javascript + - image + - zooming + - viewer + - image-viewer + - high-resolution + - iiif +license: BSD-3-Clause +version: 4.1.1 +date-released: 2024-04-01 diff --git a/changelog.txt b/changelog.txt index 13ee1015..d49699cb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,18 +5,27 @@ OPENSEADRAGON CHANGELOG * BREAKING CHANGE: Dropped support for IE11 (#2300, #2361 @AndrewADev) * DEPRECATION: The OpenSeadragon.createCallback function is no longer recommended (#2367 @akansjain) -* The viewer now uses WebGL when available (#2310, #2462, #2466, #2468, #2469, #2472, #2478 @pearcetm, @Aiosa, @thec0keman) +* The viewer now uses WebGL when available (#2310, #2462, #2466, #2468, #2469, #2472, #2478, #2488, #2492 @pearcetm, @Aiosa, @thec0keman) * Added webp to supported image formats (#2455 @BeebBenjamin) * Introduced maxTilesPerFrame option to allow loading more tiles simultaneously (#2387 @jetic83) * Now when creating a viewer or navigator, we leave its position style alone if possible (#2393 @VIRAT9358) +* Added getter & setter for Viewport.maxZoomPixelRatio (#2506 @eug-L) * Test improvements (#2382 @AndrewADev) * MouseTracker options documentation fixes (#2389 @msalsbery) +* Improved documentation and error message for Viewport.imageToViewportZoom (#2505 @eug-L) +* Fixed documentation typos (#2507 @frameflare) * Fixed: Sometimes if the viewport was flipped and the user zoomed in far enough, it would flip back (#2364 @SebDelile) -* Fixed: Strange behavior if IIIF sizes were not in ascending order (#2416 @lutzhelm) * Fixed: Two-finger tap on a Mac trackpad would zoom you out (#2431 @cavenel) * Fixed: dragToPan gesture could not be disabled when flickEnabled was activated (#2464 @jonasengelmann) * Fixed: placeholderFillStyle didn't work properly when the image was rotated (#2469 @pearcetm) * Fixed: Sometimes exponential springs wouldn't ever settle (#2469 @pearcetm) +* Fixed: The navigator wouldn't update its tracking rectangle when the navigator was resized (#2491 @pearcetm) +* Fixed: The drawer would improperly crop when the viewport was flipped and a tiled image was rotated (#2511 @pearcetm, @eug-L) +* Fixed: Flipped viewport caused image to be flipped again when going fullscreen or resizing (#2518 @pearcetm) + +4.1.1: + +* Fixed: Strange behavior if IIIF sizes were not in ascending order (#2416 @lutzhelm) 4.1.0: diff --git a/package.json b/package.json index b1228eba..7654a199 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openseadragon", - "version": "4.1.0", + "version": "4.1.1", "description": "Provides a smooth, zoomable user interface for HTML/Javascript.", "keywords": [ "image", @@ -48,4 +48,4 @@ "test": "grunt test", "prepare": "grunt build" } -} +} \ No newline at end of file diff --git a/src/canvasdrawer.js b/src/canvasdrawer.js index 03de6f1e..70d859dc 100644 --- a/src/canvasdrawer.js +++ b/src/canvasdrawer.js @@ -80,7 +80,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ // Canvas default is "true", so this will only be changed if user specifies "false" in the options or via setImageSmoothinEnabled. this._imageSmoothingEnabled = true; - // Since the tile-drawn and tile-drawing events are fired by this drawer, make sure handlers can be added for them this.viewer.allowEventHandler("tile-drawn"); this.viewer.allowEventHandler("tile-drawing"); @@ -119,7 +118,9 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ */ draw(tiledImages) { this._prepareNewFrame(); // prepare to draw a new frame - + if(this.viewer.viewport.getFlip() !== this._viewportFlipped){ + this._flip(); + } for(const tiledImage of tiledImages){ if (tiledImage.opacity !== 0) { this._drawTiles(tiledImage); @@ -147,10 +148,12 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ } /** + * @param {TiledImage} tiledImage the tiled image that is calling the function * @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams. + * @private */ - minimumOverlapRequired() { - return true; + minimumOverlapRequired(tiledImage) { + return true; } @@ -189,6 +192,14 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ context.restore(); } + /** + * Test whether the current context is flipped or not + * @private + */ + get _viewportFlipped(){ + return this.context.getTransform().a < 0; + } + /** * Fires the tile-drawing event. * @private @@ -310,13 +321,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ tiledImage.getClippedBounds(true)) .getIntegerBoundingBox(); - if(this.viewer.viewport.getFlip()) { - if (this.viewport.getRotation(true) % 360 !== 0 || - tiledImage.getRotation(true) % 360 !== 0) { - bounds.x = this.viewer.container.clientWidth - (bounds.x + bounds.width); - } - } - bounds = bounds.times($.pixelDensityRatio); } this._clear(true, bounds); @@ -325,27 +329,7 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ // When scaling, we must rotate only when blending the sketch canvas to // avoid interpolation if (!sketchScale) { - if (this.viewport.getRotation(true) % 360 !== 0) { - this._offsetForRotation({ - degrees: this.viewport.getRotation(true), - useSketch: useSketch - }); - } - if (tiledImage.getRotation(true) % 360 !== 0) { - this._offsetForRotation({ - degrees: tiledImage.getRotation(true), - point: this.viewport.pixelFromPointNoRotate( - tiledImage._getRotationPoint(true), true), - useSketch: useSketch - }); - } - - if (this.viewport.getRotation(true) % 360 === 0 && - tiledImage.getRotation(true) % 360 === 0) { - if(this.viewer.viewport.getFlip()) { - this._flip(); - } - } + this._setRotations(tiledImage, useSketch); } let usedClip = false; @@ -465,20 +449,7 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ if (useSketch) { if (sketchScale) { - if (this.viewport.getRotation(true) % 360 !== 0) { - this._offsetForRotation({ - degrees: this.viewport.getRotation(true), - useSketch: false - }); - } - if (tiledImage.getRotation(true) % 360 !== 0) { - this._offsetForRotation({ - degrees: tiledImage.getRotation(true), - point: this.viewport.pixelFromPointNoRotate( - tiledImage._getRotationPoint(true), true), - useSketch: false - }); - } + this._setRotations(tiledImage); } this.blendSketch({ opacity: tiledImage.opacity, @@ -497,15 +468,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ } } - if (!sketchScale) { - if (this.viewport.getRotation(true) % 360 === 0 && - tiledImage.getRotation(true) % 360 === 0) { - if(this.viewer.viewport.getFlip()) { - this._flip(); - } - } - } - this._drawDebugInfo( tiledImage, lastDrawn ); // Fire tiled-image-drawn event. @@ -587,7 +549,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ size = tile.size.times($.pixelDensityRatio); context.save(); - // context.globalAlpha = this.options.opacity; // this was deprecated previously and should not be applied as it is set per TiledImage if (typeof scale === 'number' && scale !== 1) { // draw tile at a different scale @@ -835,21 +796,10 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ context.strokeStyle = this.debugGridColor[colorIndex]; context.fillStyle = this.debugGridColor[colorIndex]; - if (this.viewport.getRotation(true) % 360 !== 0 ) { - this._offsetForRotation({degrees: this.viewport.getRotation(true)}); - } - if (tiledImage.getRotation(true) % 360 !== 0) { - this._offsetForRotation({ - degrees: tiledImage.getRotation(true), - point: tiledImage.viewport.pixelFromPointNoRotate( - tiledImage._getRotationPoint(true), true) - }); - } - if (tiledImage.viewport.getRotation(true) % 360 === 0 && - tiledImage.getRotation(true) % 360 === 0) { - if(tiledImage._drawer.viewer.viewport.getFlip()) { - tiledImage._drawer._flip(); - } + this._setRotations(tiledImage); + + if(this._viewportFlipped){ + this._flip({point: tile.position.plus(tile.size.divide(2))}); } context.strokeRect( @@ -864,7 +814,8 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ // Rotate the text the right way around. context.translate( tileCenterX, tileCenterY ); - context.rotate( Math.PI / 180 * -this.viewport.getRotation(true) ); + const angleInDegrees = this.viewport.getRotation(true); + context.rotate( Math.PI / 180 * -angleInDegrees ); context.translate( -tileCenterX, -tileCenterY ); if( tile.x === 0 && tile.y === 0 ){ @@ -917,13 +868,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ this._restoreRotationChanges(); } - if (tiledImage.viewport.getRotation(true) % 360 === 0 && - tiledImage.getRotation(true) % 360 === 0) { - if(tiledImage._drawer.viewer.viewport.getFlip()) { - tiledImage._drawer._flip(); - } - } - context.restore(); } @@ -954,6 +898,33 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ return new $.Point(this.canvas.width / 2, this.canvas.height / 2); } + /** + * Set rotations for viewport & tiledImage + * @private + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {Boolean} [useSketch=false] + */ + _setRotations(tiledImage, useSketch = false) { + var saveContext = false; + if (this.viewport.getRotation(true) % 360 !== 0) { + this._offsetForRotation({ + degrees: this.viewport.getRotation(true), + useSketch: useSketch, + saveContext: saveContext + }); + saveContext = false; + } + if (tiledImage.getRotation(true) % 360 !== 0) { + this._offsetForRotation({ + degrees: tiledImage.getRotation(true), + point: this.viewport.pixelFromPointNoRotate( + tiledImage._getRotationPoint(true), true), + useSketch: useSketch, + saveContext: saveContext + }); + } + } + // private _offsetForRotation(options) { var point = options.point ? @@ -964,26 +935,21 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{ context.save(); context.translate(point.x, point.y); - if(this.viewer.viewport.flipped){ - context.rotate(Math.PI / 180 * -options.degrees); - context.scale(-1, 1); - } else{ - context.rotate(Math.PI / 180 * options.degrees); - } + context.rotate(Math.PI / 180 * options.degrees); context.translate(-point.x, -point.y); } // private _flip(options) { - options = options || {}; - var point = options.point ? + options = options || {}; + var point = options.point ? options.point.times($.pixelDensityRatio) : this._getCanvasCenter(); - var context = this._getContext(options.useSketch); + var context = this._getContext(options.useSketch); - context.translate(point.x, 0); - context.scale(-1, 1); - context.translate(-point.x, 0); + context.translate(point.x, 0); + context.scale(-1, 1); + context.translate(-point.x, 0); } // private diff --git a/src/drawerbase.js b/src/drawerbase.js index adb754ba..d809fe3a 100644 --- a/src/drawerbase.js +++ b/src/drawerbase.js @@ -188,10 +188,11 @@ OpenSeadragon.DrawerBase = class DrawerBase{ } /** + * @param {TiledImage} tiledImage the tiled image that is calling the function * @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams. * @private */ - minimumOverlapRequired() { + minimumOverlapRequired(tiledImage) { return false; } diff --git a/src/htmldrawer.js b/src/htmldrawer.js index 30941c88..fa613dbf 100644 --- a/src/htmldrawer.js +++ b/src/htmldrawer.js @@ -90,11 +90,13 @@ class HTMLDrawer extends OpenSeadragon.DrawerBase{ } /** + * @param {TiledImage} tiledImage the tiled image that is calling the function * @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams. + * @private */ - minimumOverlapRequired() { + minimumOverlapRequired(tiledImage) { return true; - } + } /** * create the HTML element (e.g. canvas, div) that the image will be drawn into diff --git a/src/navigator.js b/src/navigator.js index 6a213624..fb95e4b1 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -309,6 +309,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /* this.oldContainerSize = containerSize; this.world.update(); this.world.draw(); + this.update(this.viewer.viewport); } } }, @@ -355,7 +356,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /* /** * Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs. * @function - * @param {OpenSeadragon.Viewport} The viewport this navigator is tracking. + * @param {OpenSeadragon.Viewport} [viewport] The viewport to display. Default: the viewport this navigator is tracking. */ update: function( viewport ) { @@ -366,6 +367,10 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /* topleft, bottomright; + if(!viewport){ + viewport = this.viewer.viewport; + } + viewerSize = $.getElementSize( this.viewer.element ); if ( this._resizeWithViewer && viewerSize.x && viewerSize.y && !viewerSize.equals( this.oldViewerSize ) ) { this.oldViewerSize = viewerSize; diff --git a/src/tiledimage.js b/src/tiledimage.js index 4d0aa7de..e528be02 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -1741,7 +1741,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag tileCenter = positionT.plus( sizeT.divide( 2 ) ), tileSquaredDistance = viewportCenter.squaredDistanceTo( tileCenter ); - if(this.viewer.drawer.minimumOverlapRequired()){ + if(this.viewer.drawer.minimumOverlapRequired(this)){ if ( !overlap ) { sizeC = sizeC.plus( new $.Point(1, 1)); } diff --git a/src/tilesource.js b/src/tilesource.js index 7ac6dccf..79b12994 100644 --- a/src/tilesource.js +++ b/src/tilesource.js @@ -585,13 +585,13 @@ $.TileSource.prototype = { }, /** - * Responsible determining if a the particular TileSource supports the + * Responsible for determining if the particular TileSource supports the * data format ( and allowed to apply logic against the url the data was * loaded from, if any ). Overriding implementations are expected to do * something smart with data and / or url to determine support. Also - * understand that iteration order of TileSources is not guarunteed so + * understand that iteration order of TileSources is not guaranteed so * please make sure your data or url is expressive enough to ensure a simple - * and sufficient mechanisim for clear determination. + * and sufficient mechanism for clear determination. * @function * @param {String|Object|Array|Document} data * @param {String} url - the url the data was loaded @@ -828,7 +828,7 @@ $.TileSource.prototype = { }; // Load the tile with an AJAX request if the loadWithAjax option is - // set. Otherwise load the image by setting the source proprety of the image object. + // set. Otherwise load the image by setting the source property of the image object. if (context.loadWithAjax) { dataStore.request = $.makeAjaxRequest({ url: context.src, diff --git a/src/viewer.js b/src/viewer.js index ce552786..2af05c96 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -2206,7 +2206,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, * viewport which the location coordinates will be treated as relative * to. * @param {function} [onDraw] - If supplied the callback is called when the overlay - * needs to be drawn. It it the responsibility of the callback to do any drawing/positioning. + * needs to be drawn. It is the responsibility of the callback to do any drawing/positioning. * It is passed position, size and element. * @returns {OpenSeadragon.Viewer} Chainable. * @fires OpenSeadragon.Viewer.event:add-overlay diff --git a/src/viewport.js b/src/viewport.js index cfa114cb..4d209dc5 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -1711,7 +1711,7 @@ $.Viewport.prototype = { * 1 means original image size, 0.5 half size... * Viewport zoom: ratio of the displayed image's width to viewport's width. * 1 means identical width, 2 means image's width is twice the viewport's width... - * Note: not accurate with multi-image. + * Note: not accurate with multi-image; use [TiledImage.imageToViewportZoom] for the specific image of interest. * @function * @param {Number} imageZoom The image zoom * target zoom. @@ -1723,7 +1723,7 @@ $.Viewport.prototype = { if (count > 1) { if (!this.silenceMultiImageWarnings) { $.console.error('[Viewport.imageToViewportZoom] is not accurate ' + - 'with multi-image.'); + 'with multi-image. Instead, use [TiledImage.imageToViewportZoom] for the specific image of interest'); } } else if (count === 1) { // It is better to use TiledImage.imageToViewportZoom @@ -1789,7 +1789,41 @@ $.Viewport.prototype = { */ this.viewer.raiseEvent('flip', {flipped: state}); return this; - } + }, + + /** + * Gets current max zoom pixel ratio + * @function + * @returns {Number} Max zoom pixel ratio + */ + getMaxZoomPixelRatio: function() { + return this.maxZoomPixelRatio; + }, + + /** + * Sets max zoom pixel ratio + * @function + * @param {Number} ratio - Max zoom pixel ratio + * @param {Boolean} [applyConstraints=true] - Apply constraints after setting ratio; + * Takes effect only if current zoom is greater than set max zoom pixel ratio + * @param {Boolean} [immediately=false] - Whether to animate to new zoom + */ + setMaxZoomPixelRatio: function(ratio, applyConstraints = true, immediately = false) { + + $.console.assert(!isNaN(ratio), "[Viewport.setMaxZoomPixelRatio] ratio must be a number"); + + if (isNaN(ratio)) { + return; + } + + this.maxZoomPixelRatio = ratio; + + if (applyConstraints) { + if (this.getZoom() > this.getMaxZoom()) { + this.applyConstraints(immediately); + } + } + }, }; diff --git a/src/webgldrawer.js b/src/webgldrawer.js index 28f5774e..c34de65b 100644 --- a/src/webgldrawer.js +++ b/src/webgldrawer.js @@ -206,6 +206,16 @@ return 'webgl'; } + /** + * @param {TiledImage} tiledImage the tiled image that is calling the function + * @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams. + * @private + */ + minimumOverlapRequired(tiledImage) { + // return true if the tiled image is tainted, since the backup canvas drawer will be used. + return tiledImage.isTainted(); + } + /** * create the HTML element (canvas in this case) that the image will be drawn into * @private @@ -347,7 +357,7 @@ // This can apparently happen on some systems if too many WebGL contexts have been created // in which case maxTextures can be null, leading to out of bounds errors with the array. // For example, when viewers were created and not destroyed in the test suite, this error - // occured in the TravisCI tests, though it did not happen when testing locally either in + // occurred in the TravisCI tests, though it did not happen when testing locally either in // a browser or on the command line via grunt test. throw(new Error(`WegGL error: bad value for gl parameter MAX_TEXTURE_IMAGE_UNITS (${maxTextures}). This could happen @@ -513,10 +523,14 @@ } this._outputContext.restore(); if(tiledImage.debugMode){ - let colorIndex = this.viewer.world.getIndexOfItem(tiledImage) % this.debugGridColor.length; - let strokeStyle = this.debugGridColor[colorIndex]; - let fillStyle = this.debugGridColor[colorIndex]; - this._drawDebugInfo(tilesToDraw, tiledImage, strokeStyle, fillStyle); + const flipped = this.viewer.viewport.getFlip(); + if(flipped){ + this._flip(); + } + this._drawDebugInfo(tilesToDraw, tiledImage, flipped); + if(flipped){ + this._flip(); + } } @@ -998,32 +1012,64 @@ this._clippingContext.restore(); } + /** + * Set rotations for viewport & tiledImage + * @private + * @param {OpenSeadragon.TiledImage} tiledImage + */ + _setRotations(tiledImage) { + var saveContext = false; + if (this.viewport.getRotation(true) % 360 !== 0) { + this._offsetForRotation({ + degrees: this.viewport.getRotation(true), + saveContext: saveContext + }); + saveContext = false; + } + if (tiledImage.getRotation(true) % 360 !== 0) { + this._offsetForRotation({ + degrees: tiledImage.getRotation(true), + point: this.viewport.pixelFromPointNoRotate( + tiledImage._getRotationPoint(true), true), + saveContext: saveContext + }); + } + } + // private _offsetForRotation(options) { var point = options.point ? options.point.times($.pixelDensityRatio) : - new $.Point(this._outputCanvas.width / 2, this._outputCanvas.height / 2); + this._getCanvasCenter(); var context = this._outputContext; context.save(); context.translate(point.x, point.y); - if(this.viewport.flipped){ - context.rotate(Math.PI / 180 * -options.degrees); - context.scale(-1, 1); - } else{ - context.rotate(Math.PI / 180 * options.degrees); - } + context.rotate(Math.PI / 180 * options.degrees); context.translate(-point.x, -point.y); } // private - _drawDebugInfo( tilesToDraw, tiledImage, stroke, fill ) { + _flip(options) { + options = options || {}; + var point = options.point ? + options.point.times($.pixelDensityRatio) : + this._getCanvasCenter(); + var context = this._outputContext; + + context.translate(point.x, 0); + context.scale(-1, 1); + context.translate(-point.x, 0); + } + + // private + _drawDebugInfo( tilesToDraw, tiledImage, flipped ) { for ( var i = tilesToDraw.length - 1; i >= 0; i-- ) { var tile = tilesToDraw[ i ].tile; try { - this._drawDebugInfoOnTile(tile, tilesToDraw.length, i, tiledImage, stroke, fill); + this._drawDebugInfoOnTile(tile, tilesToDraw.length, i, tiledImage, flipped); } catch(e) { $.console.error(e); } @@ -1031,30 +1077,20 @@ } // private - _drawDebugInfoOnTile(tile, count, i, tiledImage, stroke, fill) { + _drawDebugInfoOnTile(tile, count, i, tiledImage, flipped) { - var context = this._outputContext; + var colorIndex = this.viewer.world.getIndexOfItem(tiledImage) % this.debugGridColor.length; + var context = this.context; context.save(); context.lineWidth = 2 * $.pixelDensityRatio; context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial'; - context.strokeStyle = stroke; - context.fillStyle = fill; + context.strokeStyle = this.debugGridColor[colorIndex]; + context.fillStyle = this.debugGridColor[colorIndex]; - if (this.viewport.getRotation(true) % 360 !== 0 ) { - this._offsetForRotation({degrees: this.viewport.getRotation(true)}); - } - if (tiledImage.getRotation(true) % 360 !== 0) { - this._offsetForRotation({ - degrees: tiledImage.getRotation(true), - point: tiledImage.viewport.pixelFromPointNoRotate( - tiledImage._getRotationPoint(true), true) - }); - } - if (tiledImage.viewport.getRotation(true) % 360 === 0 && - tiledImage.getRotation(true) % 360 === 0) { - if(tiledImage._drawer.viewer.viewport.getFlip()) { - tiledImage._drawer._flip(); - } + this._setRotations(tiledImage); + + if(flipped){ + this._flip({point: tile.position.plus(tile.size.divide(2))}); } context.strokeRect( @@ -1069,7 +1105,8 @@ // Rotate the text the right way around. context.translate( tileCenterX, tileCenterY ); - context.rotate( Math.PI / 180 * -this.viewport.getRotation(true) ); + const angleInDegrees = this.viewport.getRotation(true); + context.rotate( Math.PI / 180 * -angleInDegrees ); context.translate( -tileCenterX, -tileCenterY ); if( tile.x === 0 && tile.y === 0 ){ @@ -1122,13 +1159,6 @@ this._restoreRotationChanges(); } - if (tiledImage.viewport.getRotation(true) % 360 === 0 && - tiledImage.getRotation(true) % 360 === 0) { - if(tiledImage._drawer.viewer.viewport.getFlip()) { - tiledImage._drawer._flip(); - } - } - context.restore(); } @@ -1156,6 +1186,15 @@ } + /** + * Get the canvas center + * @private + * @returns {OpenSeadragon.Point} The center point of the canvas + */ + _getCanvasCenter() { + return new $.Point(this.canvas.width / 2, this.canvas.height / 2); + } + // private _restoreRotationChanges() { var context = this._outputContext; diff --git a/src/world.js b/src/world.js index 598b2326..839f0acf 100644 --- a/src/world.js +++ b/src/world.js @@ -277,11 +277,14 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W * Draws all items. */ draw: function() { - this.viewer.drawer.draw(this._items); - this._needsDraw = false; - for (let item of this._items) { - this._needsDraw = item.setDrawn() || this._needsDraw; - } + return new $.Promise((resolve) => { + this.viewer.drawer.draw(this._items); + this._needsDraw = false; + for (let item of this._items) { + this._needsDraw = item.setDrawn() || this._needsDraw; + } + resolve(); + }); }, /** diff --git a/test/demo/basic2.html b/test/demo/basic2.html new file mode 100644 index 00000000..bcfdb78b --- /dev/null +++ b/test/demo/basic2.html @@ -0,0 +1,35 @@ + + +
+