diff --git a/src/tiledimage.js b/src/tiledimage.js index 0100e3cd..363df7c6 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -406,6 +406,83 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag ); }, + /** + * Convert pixel coordinates relative to the viewer element to image + * coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + viewerElementToImageCoordinates: function( pixel ) { + var point = this.viewport.pointFromPixel( pixel, true ); + return this.viewportToImageCoordinates( point ); + }, + + /** + * Convert pixel coordinates relative to the image to + * viewer element coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToViewerElementCoordinates: function( pixel ) { + var point = this.imageToViewportCoordinates( pixel ); + return this.viewport.pixelFromPoint( point, true ); + }, + + /** + * Convert pixel coordinates relative to the window to image coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + windowToImageCoordinates: function( pixel ) { + var viewerCoordinates = pixel.minus( + OpenSeadragon.getElementPosition( this.viewer.element )); + return this.viewerElementToImageCoordinates( viewerCoordinates ); + }, + + /** + * Convert image coordinates to pixel coordinates relative to the window. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToWindowCoordinates: function( pixel ) { + var viewerCoordinates = this.imageToViewerElementCoordinates( pixel ); + return viewerCoordinates.plus( + OpenSeadragon.getElementPosition( this.viewer.element )); + }, + + /** + * Convert a viewport zoom to an image zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 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... + * @function + * @param {Number} viewportZoom The viewport zoom + * @returns {Number} imageZoom The image zoom + */ + viewportToImageZoom: function( viewportZoom ) { + var ratio = this._scaleSpring.current.value * + this.viewport._containerInnerSize.x / this.source.dimensions.x; + return ratio * viewportZoom ; + }, + + /** + * Convert an image zoom to a viewport zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 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. + * @function + * @param {Number} imageZoom The image zoom + * @returns {Number} viewportZoom The viewport zoom + */ + imageToViewportZoom: function( imageZoom ) { + var ratio = this._scaleSpring.current.value * + this.viewport._containerInnerSize.x / this.source.dimensions.x; + return imageZoom / ratio; + }, + /** * Sets the TiledImage's position in the world. * @param {OpenSeadragon.Point} position - The new position, in viewport coordinates. diff --git a/test/demo/coordinates.html b/test/demo/coordinates.html index c240120a..188e87ee 100644 --- a/test/demo/coordinates.html +++ b/test/demo/coordinates.html @@ -1,21 +1,21 @@ - OpenSeadragon Basic Demo + OpenSeadragon Coordinates Demo
- Simple demo page to show a default OpenSeadragon viewer. + Simple demo page to show OpenSeadragon coordinates system.
@@ -24,16 +24,26 @@ Window (pixel) Container (pixel) - Image (pixel) + Image 1 - top left (pixel) + Image 2 - bottom right (pixel) Viewport (point) Cursor position - + + + + Zoom + - + - + + + +
diff --git a/test/modules/units.js b/test/modules/units.js index b1d10d5c..eada67b8 100644 --- a/test/modules/units.js +++ b/test/modules/units.js @@ -1,6 +1,6 @@ /* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */ -(function() { +(function () { var viewer; module('Units', { @@ -10,8 +10,8 @@ testLog.reset(); viewer = OpenSeadragon({ - id: 'unitsexample', - prefixUrl: '/build/openseadragon/images/', + id: 'unitsexample', + prefixUrl: '/build/openseadragon/images/', springStiffness: 100 // Faster animation = faster tests }); }, @@ -30,38 +30,57 @@ Util.assessNumericValue(a.y, b.y, 0.00000001, message); } - // ---------- - asyncTest('Coordinates conversions', function() { + // Check that f^-1 ( f(x) ) = x + function checkPoint(context) { + var viewport = viewer.viewport; - function checkPoint(context) { - var viewport = viewer.viewport; - - var point = new OpenSeadragon.Point(15, 12); - var result = viewport.viewerElementToImageCoordinates( + var point = new OpenSeadragon.Point(15, 12); + var result = viewport.viewerElementToImageCoordinates( viewport.imageToViewerElementCoordinates(point)); - pointEqual(result, point, 'viewerElement and image ' + context); + pointEqual(result, point, 'viewerElement and image ' + context); - var result = viewport.windowToImageCoordinates( + result = viewport.windowToImageCoordinates( viewport.imageToWindowCoordinates(point)); - pointEqual(result, point, 'window and image ' + context); + pointEqual(result, point, 'window and image ' + context); - var result = viewport.viewerElementToViewportCoordinates( + result = viewport.viewerElementToViewportCoordinates( viewport.viewportToViewerElementCoordinates(point)); - pointEqual(result, point, 'viewerElement and viewport ' + context); + pointEqual(result, point, 'viewerElement and viewport ' + context); - var result = viewport.windowToViewportCoordinates( + result = viewport.windowToViewportCoordinates( viewport.viewportToWindowCoordinates(point)); - pointEqual(result, point, 'window and viewport ' + context); + pointEqual(result, point, 'window and viewport ' + context); + + for (var i = 0; i < viewer.world.getItemCount(); i++) { + var tiledImage = viewer.world.getItemAt(i); + result = tiledImage.viewportToImageCoordinates( + tiledImage.imageToViewportCoordinates(point)); + pointEqual(result, point, 'viewport and tiled image ' + i + context); + + result = tiledImage.viewerElementToImageCoordinates( + tiledImage.imageToViewerElementCoordinates(point)); + pointEqual(result, point, 'viewerElement and tiled image ' + i + context); + + result = tiledImage.windowToImageCoordinates( + tiledImage.imageToWindowCoordinates(point)); + pointEqual(result, point, 'window and tiled image ' + i + context); } + } + + // ---------- + asyncTest('Single image coordinates conversions', function () { viewer.addHandler("open", function () { var viewport = viewer.viewport; + var tiledImage = viewer.world.getItemAt(0); var point0_0 = new OpenSeadragon.Point(0, 0); var point = viewport.viewerElementToViewportCoordinates(point0_0); pointEqual(point, point0_0, 'When opening, viewer coordinate 0,0 is also point 0,0'); - var pixel = viewport.viewerElementToImageCoordinates(point0_0); - pointEqual(pixel, point0_0, 'When opening, viewer coordinate 0,0 is also pixel 0,0'); + var viewportPixel = viewport.viewerElementToImageCoordinates(point0_0); + pointEqual(viewportPixel, point0_0, 'When opening, viewer coordinate 0,0 is also viewport pixel 0,0'); + var imagePixel = tiledImage.viewerElementToImageCoordinates(point0_0); + pointEqual(imagePixel, point0_0, 'When opening, viewer coordinate 0,0 is also image pixel 0,0'); var viewerWidth = $(viewer.element).width(); var imageWidth = viewer.source.dimensions.x; @@ -69,15 +88,17 @@ var viewerTopRight = new OpenSeadragon.Point(viewerWidth, 0); var imageTopRight = new OpenSeadragon.Point(imageWidth, 0); - var point = viewport.viewerElementToViewportCoordinates(viewerTopRight); + point = viewport.viewerElementToViewportCoordinates(viewerTopRight); pointEqual(point, point1_0, 'Viewer top right has viewport coordinates 1,0.'); - var pixel = viewport.viewerElementToImageCoordinates(viewerTopRight); - pointEqual(pixel, imageTopRight, 'Viewer top right has viewport coordinates imageWidth,0.'); + viewportPixel = viewport.viewerElementToImageCoordinates(viewerTopRight); + pointEqual(viewportPixel, imageTopRight, 'Viewer top right has viewport pixel coordinates imageWidth,0.'); + imagePixel = tiledImage.viewerElementToImageCoordinates(viewerTopRight); + pointEqual(imagePixel, imageTopRight, 'Viewer top right has image pixel coordinates imageWidth,0.'); - checkPoint('after opening'); + checkPoint(' after opening'); viewer.addHandler('animation-finish', function animationHandler() { viewer.removeHandler('animation-finish', animationHandler); - checkPoint('after zoom and pan'); + checkPoint(' after zoom and pan'); start(); }); viewer.viewport.zoomTo(0.8).panTo(new OpenSeadragon.Point(0.1, 0.2)); @@ -85,19 +106,80 @@ viewer.open('/test/data/testpattern.dzi'); }); + + // --------- + asyncTest('Multiple images coordinates conversion', function () { + + viewer.addHandler("open", function () { + var viewport = viewer.viewport; + var tiledImage1 = viewer.world.getItemAt(0); + var tiledImage2 = viewer.world.getItemAt(1); + var imageWidth = viewer.source.dimensions.x; + var imageHeight = viewer.source.dimensions.y; + + var point0_0 = new OpenSeadragon.Point(0, 0); + var point = viewport.viewerElementToViewportCoordinates(point0_0); + pointEqual(point, point0_0, 'When opening, viewer coordinate 0,0 is also point 0,0'); + var image1Pixel = tiledImage1.viewerElementToImageCoordinates(point0_0); + pointEqual(image1Pixel, point0_0, 'When opening, viewer coordinate 0,0 is also image 1 pixel 0,0'); + var image2Pixel = tiledImage2.viewerElementToImageCoordinates(point0_0); + pointEqual(image2Pixel, + new OpenSeadragon.Point(-2 * imageWidth, -2 * imageHeight), + 'When opening, viewer coordinates 0,0 is also image 2 pixel -2*imageWidth, -2*imageHeight'); + + var viewerWidth = $(viewer.element).width(); + var viewerHeight = $(viewer.element).height(); + var viewerBottomRight = new OpenSeadragon.Point(viewerWidth, viewerHeight); + + point = viewport.viewerElementToViewportCoordinates(viewerBottomRight); + pointEqual(point, new OpenSeadragon.Point(1.5, 1.5), + 'Viewer bottom right has viewport coordinates 1.5,1.5.'); + image1Pixel = tiledImage1.viewerElementToImageCoordinates(viewerBottomRight); + pointEqual(image1Pixel, + new OpenSeadragon.Point(imageWidth * 1.5, imageHeight * 1.5), + 'Viewer bottom right has image 1 pixel coordinates imageWidth * 1.5, imageHeight * 1.5'); + image2Pixel = tiledImage2.viewerElementToImageCoordinates(viewerBottomRight); + pointEqual(image2Pixel, + new OpenSeadragon.Point(imageWidth, imageHeight), + 'Viewer bottom right has image 2 pixel coordinates imageWidth,imageHeight.'); + + + checkPoint(' after opening'); + viewer.addHandler('animation-finish', function animationHandler() { + viewer.removeHandler('animation-finish', animationHandler); + checkPoint(' after zoom and pan'); + start(); + }); + viewer.viewport.zoomTo(0.8).panTo(new OpenSeadragon.Point(0.1, 0.2)); + + start(); + }); + + viewer.open([{ + tileSource: "/test/data/testpattern.dzi" + }, { + tileSource: "/test/data/testpattern.dzi", + x: 1, + y: 1, + width: 0.5 + } + ]); + }); + + // ---------- - asyncTest('ZoomRatio', function() { + asyncTest('ZoomRatio 1 image', function () { viewer.addHandler("open", function () { var viewport = viewer.viewport; - var imageWidth = 1000; + var imageWidth = viewer.source.dimensions.x; function getCurrentImageWidth() { return viewport.viewportToViewerElementCoordinates( - new OpenSeadragon.Point(1, 0)).minus( + new OpenSeadragon.Point(1, 0)).minus( viewport.viewportToViewerElementCoordinates( - new OpenSeadragon.Point(0, 0))).x; + new OpenSeadragon.Point(0, 0))).x; } function checkZoom() { @@ -105,7 +187,7 @@ var expectedImageZoom = currentImageWidth / imageWidth; var expectedViewportZoom = viewport.getZoom(true); var actualImageZoom = viewport.viewportToImageZoom( - expectedViewportZoom); + expectedViewportZoom); equal(actualImageZoom, expectedImageZoom); var actualViewportZoom = viewport.imageToViewportZoom(actualImageZoom); @@ -114,7 +196,7 @@ checkZoom(); - var zoomHandler = function() { + var zoomHandler = function () { viewer.removeHandler('animation-finish', zoomHandler); checkZoom(); start(); @@ -127,5 +209,61 @@ viewer.open('/test/data/testpattern.dzi'); }); + // ---------- + asyncTest('ZoomRatio 2 images', function () { + viewer.addHandler("open", function () { + + var viewport = viewer.viewport; + + var imageWidth = viewer.source.dimensions.x; + var image1 = viewer.world.getItemAt(0); + var image2 = viewer.world.getItemAt(1); + + function getCurrentImageWidth(image) { + var bounds = image.getBounds(); + return viewport.viewportToViewerElementCoordinates( + bounds.getTopRight()).minus( + viewport.viewportToViewerElementCoordinates( + bounds.getTopLeft())).x; + } + + function checkZoom(image) { + var currentImageWidth = getCurrentImageWidth(image); + var expectedImageZoom = currentImageWidth / imageWidth; + var expectedViewportZoom = viewport.getZoom(true); + var actualImageZoom = image.viewportToImageZoom( + expectedViewportZoom); + Util.assessNumericValue(actualImageZoom, expectedImageZoom, + 0.00000001); + + var actualViewportImage1Zoom = image.imageToViewportZoom(actualImageZoom); + Util.assessNumericValue( + actualViewportImage1Zoom, expectedViewportZoom, 0.00000001); + } + + checkZoom(image1); + checkZoom(image2); + + var zoomHandler = function () { + viewer.removeHandler('animation-finish', zoomHandler); + checkZoom(image1); + checkZoom(image2); + start(); + }; + + viewer.addHandler('animation-finish', zoomHandler); + viewport.zoomTo(2); + }); + + viewer.open([{ + tileSource: "/test/data/testpattern.dzi" + }, { + tileSource: "/test/data/testpattern.dzi", + x: 1, + y: 1, + width: 0.5 + } + ]); + }); })();