diff --git a/README.md b/README.md index 1ddabf86..71fafeca 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # OpenSeadragon +[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/openseadragon/openseadragon?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) An open-source, web-based viewer for zoomable images, implemented in pure JavaScript. diff --git a/src/drawer.js b/src/drawer.js index fbb8db0f..fd1cd730 100644 --- a/src/drawer.js +++ b/src/drawer.js @@ -324,6 +324,9 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ } }, + /** + * @private + */ drawDebugInfo: function( tile, count, i ){ if ( this.useCanvas ) { this.context.save(); @@ -396,6 +399,30 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ } }, + /** + * @private + */ + debugRect: function(rect) { + if ( this.useCanvas ) { + this.context.save(); + this.context.lineWidth = 2; + this.context.strokeStyle = this.debugGridColor; + this.context.fillStyle = this.debugGridColor; + + this.context.strokeRect( + rect.x, + rect.y, + rect.width, + rect.height + ); + + this.context.restore(); + } + }, + + /** + * @private + */ _offsetForRotation: function( tile, degrees ){ var cx = this.canvas.width / 2, cy = this.canvas.height / 2, @@ -410,6 +437,9 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ tile.position.y = py; }, + /** + * @private + */ _restoreRotationChanges: function( tile ){ var cx = this.canvas.width / 2, cy = this.canvas.height / 2, diff --git a/src/openseadragon.js b/src/openseadragon.js index 49cd03d9..91a7231d 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -256,6 +256,10 @@ * achieved. Setting this to 0 and wrapHorizontal ( or wrapVertical ) to * true will provide the effect of an infinitely scrolling viewport. * + * @property {Object} [viewportMargins={}] + * Pushes the "home" region in from the sides by the specified amounts. + * Possible subproperties (Numbers, in screen coordinates): left, top, right, bottom. + * * @property {Number} [imageLoaderLimit=0] * The maximum number of image requests to make concurrently. By default * it is set to 0 allowing the browser to make the maximum number of diff --git a/src/rectangle.js b/src/rectangle.js index a546a2e4..217b5126 100644 --- a/src/rectangle.js +++ b/src/rectangle.js @@ -185,6 +185,22 @@ $.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{ ( this.height === other.height ); }, + /** + * Multiply all dimensions in this Rect by a factor and return a new Rect. + * @function + * @param {Number} factor The factor to multiply vector components. + * @returns {OpenSeadragon.Rect} A new rect representing the multiplication + * of the vector components by the factor + */ + times: function( factor ) { + return new OpenSeadragon.Rect( + this.x * factor, + this.y * factor, + this.width * factor, + this.height * factor + ); + }, + /** * Rotates a rectangle around a point. Currently only 90, 180, and 270 * degrees are supported. diff --git a/src/tiledimage.js b/src/tiledimage.js index 0134897a..e2afbed5 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -178,8 +178,7 @@ function updateViewport( tiledImage ) { best = null, haveDrawn = false, currentTime = $.now(), - viewportSize = tiledImage.viewport.getContainerSize(), - viewportBounds = tiledImage.viewport.getBounds( true ), + viewportBounds = tiledImage.viewport.getBoundsWithMargins( true ), viewportTL = viewportBounds.getTopLeft(), viewportBR = viewportBounds.getBottomRight(), zeroRatioC = tiledImage.viewport.deltaPixelsFromPoints( diff --git a/src/viewer.js b/src/viewer.js index d522c077..c0a6d900 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -434,7 +434,8 @@ $.Viewer = function( options ) { viewer: this, degrees: this.degrees, navigatorRotate: this.navigatorRotate, - homeFillsViewer: this.homeFillsViewer + homeFillsViewer: this.homeFillsViewer, + margins: this.viewportMargins }); // Create the image loader diff --git a/src/viewport.js b/src/viewport.js index 0c3744b0..fab50455 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -63,6 +63,15 @@ $.Viewport = function( options ) { delete options.config; } + this._margins = $.extend({ + left: 0, + top: 0, + right: 0, + bottom: 0 + }, options.margins || {}); + + delete options.margins; + $.extend( true, this, { //required settings @@ -89,6 +98,11 @@ $.Viewport = function( options ) { }, options ); + this._containerInnerSize = new $.Point( + Math.max(1, this.containerSize.x - (this._margins.left + this._margins.right)), + Math.max(1, this.containerSize.y - (this._margins.top + this._margins.bottom)) + ); + this.centerSpringX = new $.Spring({ initial: 0, springStiffness: this.springStiffness, @@ -257,7 +271,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ getMaxZoom: function() { var zoom = this.maxZoomLevel; if (!zoom) { - zoom = this.contentSize.x * this.maxZoomPixelRatio / this.containerSize.x; + zoom = this.contentSize.x * this.maxZoomPixelRatio / this._containerInnerSize.x; zoom /= this.homeBounds.width; } @@ -268,11 +282,12 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ * @function */ getAspectRatio: function() { - return this.containerSize.x / this.containerSize.y; + return this._containerInnerSize.x / this._containerInnerSize.y; }, /** * @function + * @returns {OpenSeadragon.Point} The size of the container, in screen coordinates. */ getContainerSize: function() { return new $.Point( @@ -284,6 +299,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ /** * @function * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in world coordinates. */ getBounds: function( current ) { var center = this.getCenter( current ), @@ -298,6 +314,22 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ ); }, + /** + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, + * including the space taken by margins, in world coordinates. + */ + getBoundsWithMargins: function( current ) { + var bounds = this.getBounds(current); + var factor = this._containerInnerSize.x * this.getZoom(current); + bounds.x -= this._margins.left / factor; + bounds.y -= this._margins.top / factor; + bounds.width += (this._margins.left + this._margins.right) / factor; + bounds.height += (this._margins.top + this._margins.bottom) / factor; + return bounds; + }, + /** * @function * @param {Boolean} current - Pass true for the current location; defaults to false (target location). @@ -338,13 +370,9 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ height ); - newZoomPixel = this.zoomPoint.minus( - bounds.getTopLeft() - ).times( - this.containerSize.x / bounds.width - ); + newZoomPixel = this._pixelFromPoint(this.zoomPoint, bounds); deltaZoomPixels = newZoomPixel.minus( oldZoomPixel ); - deltaZoomPoints = deltaZoomPixels.divide( this.containerSize.x * zoom ); + deltaZoomPoints = deltaZoomPixels.divide( this._containerInnerSize.x * zoom ); return centerTarget.plus( deltaZoomPoints ); }, @@ -550,14 +578,14 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ } referencePoint = oldBounds.getTopLeft().times( - this.containerSize.x / oldBounds.width + this._containerInnerSize.x / oldBounds.width ).minus( newBounds.getTopLeft().times( - this.containerSize.x / newBounds.width + this._containerInnerSize.x / newBounds.width ) ).divide( - this.containerSize.x / oldBounds.width - - this.containerSize.x / newBounds.width + this._containerInnerSize.x / oldBounds.width - + this._containerInnerSize.x / newBounds.width ); return this.zoomTo( newZoom, referencePoint, immediately ); @@ -800,12 +828,16 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ newBounds = oldBounds, widthDeltaFactor; - this.containerSize = new $.Point( - newContainerSize.x, - newContainerSize.y + this.containerSize.x = newContainerSize.x; + this.containerSize.y = newContainerSize.y; + + this._containerInnerSize = new $.Point( + Math.max(1, newContainerSize.x - (this._margins.left + this._margins.right)), + Math.max(1, newContainerSize.y - (this._margins.top + this._margins.bottom)) ); if ( maintain ) { + // TODO: widthDeltaFactor will always be 1; probably not what's intended widthDeltaFactor = newContainerSize.x / this.containerSize.x; newBounds.width = oldBounds.width * widthDeltaFactor; newBounds.height = newBounds.width / this.getAspectRatio(); @@ -877,7 +909,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ */ deltaPixelsFromPoints: function( deltaPoints, current ) { return deltaPoints.times( - this.containerSize.x * this.getZoom( current ) + this._containerInnerSize.x * this.getZoom( current ) ); }, @@ -888,7 +920,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ */ deltaPointsFromPixels: function( deltaPixels, current ) { return deltaPixels.divide( - this.containerSize.x * this.getZoom( current ) + this._containerInnerSize.x * this.getZoom( current ) ); }, @@ -898,11 +930,19 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ * @param {Boolean} current - Pass true for the current location; defaults to false (target location). */ pixelFromPoint: function( point, current ) { - var bounds = this.getBounds( current ); + return this._pixelFromPoint(point, this.getBounds( current )); + }, + + /** + * @private + */ + _pixelFromPoint: function( point, bounds ) { return point.minus( bounds.getTopLeft() ).times( - this.containerSize.x / bounds.width + this._containerInnerSize.x / bounds.width + ).plus( + new $.Point(this._margins.left, this._margins.top) ); }, @@ -913,8 +953,10 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ */ pointFromPixel: function( pixel, current ) { var bounds = this.getBounds( current ); - return pixel.divide( - this.containerSize.x / bounds.width + return pixel.minus( + new $.Point(this._margins.left, this._margins.top) + ).divide( + this._containerInnerSize.x / bounds.width ).plus( bounds.getTopLeft() ); @@ -1129,7 +1171,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ */ viewportToImageZoom: function( viewportZoom ) { var imageWidth = this.viewer.source.dimensions.x; - var containerWidth = this.getContainerSize().x; + var containerWidth = this._containerInnerSize.x; var viewportToImageZoomRatio = containerWidth / imageWidth; return viewportZoom * viewportToImageZoomRatio; }, @@ -1147,7 +1189,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ */ imageToViewportZoom: function( imageZoom ) { var imageWidth = this.viewer.source.dimensions.x; - var containerWidth = this.getContainerSize().x; + var containerWidth = this._containerInnerSize.x; var viewportToImageZoomRatio = imageWidth / containerWidth; return imageZoom * viewportToImageZoomRatio; } diff --git a/test/demo/collections/main.js b/test/demo/collections/main.js index 30992342..f558fa66 100644 --- a/test/demo/collections/main.js +++ b/test/demo/collections/main.js @@ -6,49 +6,94 @@ init: function() { var self = this; - var tileSources = [ - { - tileSource: "../../data/tall.dzi", - x: 1.5, - y: 0, - width: 1 - }, { - tileSource: '../../data/wide.dzi', - opacity: 1, - x: 0, - y: 1.5, - height: 1 - } - ]; + var testInitialOpen = false; + var testOverlays = false; + var testMargins = false; + var margins; - this.viewer = OpenSeadragon( { - // debugMode: true, + var config = { + debugMode: true, zoomPerScroll: 1.02, showNavigator: true, id: "contentDiv", - tileSources: tileSources, - prefixUrl: "../../../build/openseadragon/images/", - overlays: [ { - px: 13, - py: 120, - width: 124, - height: 132, - id: "overlay" - }, { - px: 400, - py: 500, - width: 400, - height: 400, - id: "fixed-overlay", - placement: "TOP_LEFT" - } ] - } ); + prefixUrl: "../../../build/openseadragon/images/" + }; - this.viewer.addHandler( "open", function() { - // console.log(self.viewer.viewport.contentSize); - }); + if (testInitialOpen) { + config.tileSources = [ + { + tileSource: "../../data/tall.dzi", + x: 1.5, + y: 0, + width: 1 + }, { + tileSource: '../../data/wide.dzi', + opacity: 1, + x: 0, + y: 1.5, + height: 1 + } + ]; + } + + if (testOverlays) { + config.overlays = [ { + px: 13, + py: 120, + width: 124, + height: 132, + id: "overlay" + }, { + px: 400, + py: 500, + width: 400, + height: 400, + id: "fixed-overlay", + placement: "TOP_LEFT" + } ]; + } + + if (testMargins) { + margins = { + top: 250, + left: 250, + right: 250, + bottom: 250 + }; + + config.viewportMargins = margins; + } + + this.viewer = OpenSeadragon(config); + + if (testInitialOpen) { + this.viewer.addHandler( "open", function() { + // console.log(self.viewer.viewport.contentSize); + }); + } + + if (testMargins) { + this.viewer.addHandler('animation', function() { + var box = new OpenSeadragon.Rect(margins.left, margins.top, + $('#contentDiv').width() - (margins.left + margins.right), + $('#contentDiv').height() - (margins.top + margins.bottom)); + + self.viewer.drawer.debugRect(box); + }); + } // this.crossTest3(); + this.basicTest(); + }, + + // ---------- + basicTest: function() { + var self = this; + + this.viewer.addHandler('open', function() { + }); + + this.viewer.open("../../data/testpattern.dzi"); }, // ---------- @@ -177,6 +222,40 @@ y: -2, width: 6 }); + }, + + // ---------- + cjTest: function() { + var imageKey = "e-pluribus-unum"; + var imageXML = ''; + var $xml = $($.parseXML(imageXML)); + var $image = $xml.find('Image'); + var $size = $xml.find('Size'); + + var dzi = { + Image: { + xmlns: $image.attr('xmlns'), + Url: "http://chrisjordan.com/dzi/" + imageKey + '_files/', + Format: $image.attr('Format'), + Overlap: $image.attr('Overlap'), + TileSize: $image.attr('TileSize'), + Size: { + Height: $size.attr('Height'), + Width: $size.attr('Width') + } + } + }; + + this.viewer.open(dzi, { + width: 100 + }); + }, + + // ---------- + stanfordTest: function() { + var info = {"@context":"http://library.stanford.edu/iiif/image-api/1.1/context.json","@id":"http://ids.lib.harvard.edu/ids/iiif/48530377","width":6251,"height":109517,"scale_factors":[1,2,4,8,16,32],"tile_width":256,"tile_height":256,"formats":["jpg"],"qualities":["native"],"profile":"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1"}; + + this.viewer.open(info); } }; diff --git a/test/test.html b/test/test.html index 76abbd60..88a04135 100644 --- a/test/test.html +++ b/test/test.html @@ -30,6 +30,7 @@ + diff --git a/test/viewport.js b/test/viewport.js new file mode 100644 index 00000000..2daabc68 --- /dev/null +++ b/test/viewport.js @@ -0,0 +1,285 @@ +/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */ + +(function () { + var viewer; + + module("viewport", { + setup: function () { + var example = $('
').appendTo("#qunit-fixture"); + + testLog.reset(); + + viewer = OpenSeadragon({ + id: 'example', + prefixUrl: '/build/openseadragon/images/', + springStiffness: 100 // Faster animation = faster tests + }); + }, + teardown: function () { + if (viewer && viewer.close) { + viewer.close(); + } + + viewer = null; + } + }); + + // helpers and constants + + var ZOOM_FACTOR = 2; // the image will be twice as large as the viewer. + var VIEWER_PADDING = new OpenSeadragon.Point(20, 20); + var DZI_PATH = '/test/data/testpattern.dzi' + + var testZoomLevels = [-1, 0, 0.1, 0.5, 4, 10]; + + var testPoints = [ + new OpenSeadragon.Point(0, 0), + new OpenSeadragon.Point(0.001, 0.001), + new OpenSeadragon.Point(0.25, 0.5), + new OpenSeadragon.Point(0.99, 0.99), + new OpenSeadragon.Point(1, 1) + ]; + + var testRects = [ + new OpenSeadragon.Rect(0, 0, 0, 0), + new OpenSeadragon.Rect(0.001, 0.005, 0.001, 0.003), + new OpenSeadragon.Rect(0.25, 0.25, 0.25, 0.25), + new OpenSeadragon.Rect(0.999, 0.999, 0.999, 0.999), + new OpenSeadragon.Rect(1, 1, 1, 1) + ]; + + // ---------- +/* + asyncTest('template', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + // do stuff here + var orig = ; + var expected = ; + var actual = ; + equal(expected, actual, "what are you testing"); + + start(); + }; + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); +*/ + asyncTest('imageToViewportRectangle', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + var orig, expected, actual; + for (var i = 0; i < testRects.length; i++){ + orig = testRects[i].times(viewer.source.dimensions.x); + expected = new OpenSeadragon.Rect( + orig.x / viewer.source.dimensions.x, + orig.y / viewer.source.dimensions.x, + orig.width / viewer.source.dimensions.x, + orig.height / viewer.source.dimensions.x + ); + actual = viewport.imageToViewportRectangle(orig); + propEqual(actual, expected, "Coordinates converted correctly for " + orig); + } + + start(); + }; + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + + asyncTest('viewportToImageRectangle', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + var orig, expected, actual; + for (var i = 0; i < testRects.length; i++){ + orig = testRects[i].times(viewport.getContainerSize().x); + expected = new OpenSeadragon.Rect( + orig.x * viewer.source.dimensions.x, + orig.y * viewer.source.dimensions.x, + orig.width * viewer.source.dimensions.x, + orig.height * viewer.source.dimensions.x + ); + actual = viewport.viewportToImageRectangle(orig); + propEqual(actual, expected, "Coordinates converted correctly for " + orig); + } + + start(); + }; + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + + asyncTest('viewerElementToImageCoordinates', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + var orig, expected, actual; + for (var i = 0; i < testPoints.length; i++){ + orig = testPoints[i].times(viewport.getContainerSize().x); + expected = orig.times(ZOOM_FACTOR); + actual = viewport.viewerElementToImageCoordinates(orig); + propEqual(actual, expected, "Coordinates converted correctly for " + orig); + } + + start(); + }; + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + + asyncTest('imageToViewerElementCoordinates', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + var orig, expected, actual; + for (var i = 0; i < testPoints.length; i++){ + orig = testPoints[i].times(viewer.source.dimensions.x); + expected = orig.divide(ZOOM_FACTOR); + actual = viewport.imageToViewerElementCoordinates(orig); + propEqual(actual, expected, "Coordinates converted correctly for " + orig); + } + + start(); + }; + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + + asyncTest('windowToImageCoordinates', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + var window_boundary = Math.min(window.innerWidth, window.innerHeight); + var orig, expected, actual; + for (var i = 0; i < testPoints.length; i++){ + orig = testPoints[i].times(window_boundary); + expected = orig.divide(viewport.getContainerSize().x).plus(VIEWER_PADDING); + actual = viewport.windowToViewportCoordinates(orig); + propEqual(actual, expected, "Coordinates converted correctly for " + orig); + } + + start(); + }; + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + + asyncTest('imageToWindowCoordinates', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + var orig, expected, actual; + for (var i = 0; i < testPoints.length; i++){ + orig = testPoints[i].times(viewer.source.dimensions.x); + position = viewer.element.getBoundingClientRect(); + expected = orig.divide(ZOOM_FACTOR).plus( new OpenSeadragon.Point(position.top, position.left) ); + actual = viewport.imageToWindowCoordinates(orig); + propEqual(actual, expected, "Coordinates converted correctly for " + orig); + } + + start(); + }; + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + + asyncTest('windowToViewportCoordinates', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + var window_boundary = Math.min(window.innerWidth, window.innerHeight); + var orig, expected, actual; + for (var i = 0; i < testPoints.length; i++){ + orig = testPoints[i].times(window_boundary); + expected = orig.divide(viewport.getContainerSize().x).plus(VIEWER_PADDING); + actual = viewport.windowToViewportCoordinates(orig); + propEqual(actual, expected, "Coordinates converted correctly for " + orig); + } + + start(); + }; + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + + asyncTest('viewportToWindowCoordinates', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + var orig, expected, actual; + for (var i = 0; i < testPoints.length; i++){ + orig = testPoints[i].times(viewer.source.dimensions.x); + expected = orig.minus(VIEWER_PADDING).times(viewport.getContainerSize().x); + actual = viewport.viewportToWindowCoordinates(orig); + propEqual(actual, expected, "Coordinates converted correctly for " + orig); + } + + start(); + }; + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + + asyncTest('viewportToImageZoom', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + var orig, expected, actual; + for (var i = 0; i < testPoints.length; i++){ + orig = testZoomLevels[i]; + expected = orig / ZOOM_FACTOR; + actual = viewport.viewportToImageZoom(orig); + equal(expected, actual, "Coordinates converted correctly for " + orig); + } + start(); + }; + + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + + asyncTest('imageToViewportZoom', function() { + var openHandler = function(event) { + viewer.removeHandler('open', openHandler); + var viewport = viewer.viewport; + viewport.zoomTo(ZOOM_FACTOR, null, true); + + + var orig, expected, actual; + for (var i = 0; i < testPoints.length; i++){ + orig = testZoomLevels[i]; + expected = orig * ZOOM_FACTOR; + actual = viewport.imageToViewportZoom(orig); + equal(expected, actual, "Coordinates converted correctly for " + orig); + } + start(); + }; + + viewer.addHandler('open', openHandler); + viewer.open(DZI_PATH); + }); + +})();