diff --git a/changelog.txt b/changelog.txt index eaedcd1b..582f2d53 100644 --- a/changelog.txt +++ b/changelog.txt @@ -57,6 +57,8 @@ OPENSEADRAGON CHANGELOG * Fixed a bug where the navigator wouldn't pick up opacity/composite changes made while it is loading (#2018 @crydell) * Explicitly set passive:false for wheel event handlers to suppress console warnings. Fixes #1669 (#2043 @msalsbery) * Viewer's canvas-click events now include an originalTarget property so you can know which element received the click (#2037 @iangilman) +* Added method for getting the size of an image in window coordinates (#2049 @superbland) +* Added a setMaxLevel function to TileSource so you can change its maxLevel if needed (#2059, #2066 @kim-sanghoon) 2.4.2: diff --git a/src/mousetracker.js b/src/mousetracker.js index 83c7eafc..e64e7637 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -271,7 +271,10 @@ lastPinchDist: 0, currentPinchDist: 0, lastPinchCenter: null, - currentPinchCenter: null + currentPinchCenter: null, + + // Tracking for drag + sentDragEvent: false }; this.hasGestureHandlers = !!( this.pressHandler || this.nonPrimaryPressHandler || @@ -1446,6 +1449,8 @@ for ( i = 0; i < pointerListCount; i++ ) { delegate.activePointersLists.pop(); } + + delegate.sentDragEvent = false; } /** @@ -3476,7 +3481,7 @@ } // Drag End - if ( tracker.dragEndHandler ) { + if ( tracker.dragEndHandler && delegate.sentDragEvent ) { tracker.dragEndHandler( { eventSource: tracker, @@ -3492,6 +3497,9 @@ ); } + // We want to clear this flag regardless of whether we fired the dragEndHandler + delegate.sentDragEvent = false; + // Click / Double-Click if ( ( tracker.clickHandler || tracker.dblClickHandler ) && updateGPoint.insideElement ) { quick = releaseTime - updateGPoint.contactTime <= tracker.clickTimeThreshold && @@ -3679,6 +3687,7 @@ } ); eventInfo.preventDefault = true; + delegate.sentDragEvent = true; } } else if ( pointsList.contacts === 2 ) { // Move (2 contacts, use center) diff --git a/src/tiledimage.js b/src/tiledimage.js index 39f195f2..870163af 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -419,6 +419,15 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag return new $.Point(this.source.dimensions.x, this.source.dimensions.y); }, + /** + * @returns {OpenSeadragon.Point} The TiledImage's content size, in window coordinates. + */ + getSizeInWindowCoordinates: function() { + var topLeft = this.imageToWindowCoordinates(new $.Point(0, 0)); + var bottomRight = this.imageToWindowCoordinates(this.getContentSize()); + return new $.Point(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y); + }, + // private _viewportToImageDelta: function( viewerX, viewerY, current ) { var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value); diff --git a/src/tilesource.js b/src/tilesource.js index 8c66258e..a915ac2c 100644 --- a/src/tilesource.js +++ b/src/tilesource.js @@ -275,12 +275,32 @@ $.TileSource.prototype = { return this._tileHeight; }, + /** + * Set the maxLevel to the given level, and perform the memoization of + * getLevelScale with the new maxLevel. This function can be useful if the + * memoization is required before the first call of getLevelScale, or both + * memoized getLevelScale and maxLevel should be changed accordingly. + * @function + * @param {Number} level + */ + setMaxLevel: function( level ) { + this.maxLevel = level; + this._memoizeLevelScale(); + }, + /** * @function * @param {Number} level */ getLevelScale: function( level ) { + // if getLevelScale is not memoized, we generate the memoized version + // at the first call and return the result + this._memoizeLevelScale(); + return this.getLevelScale( level ); + }, + // private + _memoizeLevelScale: function() { // see https://github.com/openseadragon/openseadragon/issues/22 // we use the tilesources implementation of getLevelScale to generate // a memoized re-implementation @@ -292,7 +312,6 @@ $.TileSource.prototype = { this.getLevelScale = function( _level ){ return levelScaleCache[ _level ]; }; - return this.getLevelScale( level ); }, /** diff --git a/test/modules/tiledimage.js b/test/modules/tiledimage.js index 46860648..4a075328 100644 --- a/test/modules/tiledimage.js +++ b/test/modules/tiledimage.js @@ -41,8 +41,11 @@ viewer.addHandler('open', function(event) { var image = viewer.world.getItemAt(0); var contentSize = image.getContentSize(); + var sizeInWindowCoords = image.getSizeInWindowCoordinates(); assert.equal(contentSize.x, 500, 'contentSize.x'); assert.equal(contentSize.y, 2000, 'contentSize.y'); + assert.equal(sizeInWindowCoords.x, 125, 'sizeInWindowCoords.x'); + assert.equal(sizeInWindowCoords.y, 500, 'sizeInWindowCoords.y'); checkBounds(assert, image, new OpenSeadragon.Rect(5, 6, 10, 40), 'initial bounds'); @@ -74,7 +77,18 @@ image.setHeight(4); checkBounds(assert, image, new OpenSeadragon.Rect(7, 8, 1, 4), 'bounds after width'); - assert.equal(handlerCount, 1, 'correct number of handlers called'); + viewer.addHandler('zoom', function zoomHandler(event) { + var sizeInWindowCoords = image.getSizeInWindowCoordinates(); + viewer.removeHandler('zoom', zoomHandler); + handlerCount++; + assert.equal(sizeInWindowCoords.x, 4000, 'sizeInWindowCoords.x after zoom'); + assert.equal(sizeInWindowCoords.y, 16000, 'sizeInWindowCoords.y after zoom'); + }); + + viewer.viewport.zoomTo(8, null, true); + + assert.equal(handlerCount, 2, 'correct number of handlers called'); + done(); }); diff --git a/test/modules/tilesource.js b/test/modules/tilesource.js index 0d33f4e5..2f752c4a 100644 --- a/test/modules/tilesource.js +++ b/test/modules/tilesource.js @@ -120,4 +120,32 @@ assertTileAtPoint(0, new OpenSeadragon.Point(1, 3033 / 2000), new OpenSeadragon.Point(0, 0)); }); + QUnit.test('changing maxLevel', function(assert) { + var tileSource = new OpenSeadragon.TileSource({ + width: 4096, + height: 4096, + }); + + assert.equal(tileSource.maxLevel, 12, 'The initial max level should be 12.'); + + function assertLevelScale(level, expected) { + var actual = tileSource.getLevelScale(level); + assert.ok(Math.abs(actual - expected) < Number.EPSILON, "The scale at level " + level + + " should be " + expected.toString() + + " got " + actual.toString()); + } + + assertLevelScale(12, 1); + assertLevelScale(10, 1 / 4); + assertLevelScale(8, 1 / 16); + assertLevelScale(6, 1 / 64); + + tileSource.setMaxLevel(9); + + assertLevelScale(9, 1); + assertLevelScale(7, 1 / 4); + assertLevelScale(5, 1 / 16); + assertLevelScale(3, 1 / 64); + }); + }());