Merge pull request #526 from openseadragon/ian

Collections stretch goals
This commit is contained in:
Ian Gilman 2014-11-24 13:31:20 -08:00
commit a24e4f8210
11 changed files with 279 additions and 76 deletions

View File

@ -8,7 +8,8 @@
"*.sublime-workspace" "*.sublime-workspace"
], ],
"folder_exclude_patterns": [ "folder_exclude_patterns": [
"node_modules" "node_modules",
"coverage"
] ]
} }
], ],

View File

@ -116,27 +116,6 @@ $.Drawer = function( options ) {
// explicit left-align // explicit left-align
this.container.style.textAlign = "left"; this.container.style.textAlign = "left";
this.container.appendChild( this.canvas ); this.container.appendChild( this.canvas );
// We need a callback to give image manipulation a chance to happen
this._drawingHandler = function(args) {
if (_this.viewer) {
/**
* This event is fired just before the tile is drawn giving the application a chance to alter the image.
*
* NOTE: This event is only fired when the drawer is using a <canvas>.
*
* @event tile-drawing
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.Tile} tile - The Tile being drawn.
* @property {OpenSeadragon.Tile} context - The HTML canvas context being drawn into.
* @property {OpenSeadragon.Tile} rendered - The HTML canvas context containing the tile imagery.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.viewer.raiseEvent('tile-drawing', args);
}
};
}; };
$.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
@ -249,17 +228,23 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
/** /**
* Draws the given tile. * Draws the given tile.
* @param {OpenSeadragon.Tile} tile - The tile to draw. * @param {OpenSeadragon.Tile} tile - The tile to draw.
* @param {Function} drawingHandler - Method for firing the drawing event if using canvas.
* drawingHandler({context, tile, rendered})
* where <code>rendered</code> is the context with the pre-drawn image.
*/ */
drawTile: function( tile ) { drawTile: function( tile, drawingHandler ) {
$.console.assert(tile, '[Drawer.drawTile] tile is required');
$.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required');
if ( this.useCanvas ) { if ( this.useCanvas ) {
// TODO do this in a more performant way // TODO do this in a more performant way
// specifically, don't save,rotate,restore every time we draw a tile // specifically, don't save,rotate,restore every time we draw a tile
if( this.viewport.degrees !== 0 ) { if( this.viewport.degrees !== 0 ) {
this._offsetForRotation( tile, this.viewport.degrees ); this._offsetForRotation( tile, this.viewport.degrees );
tile.drawCanvas( this.context, this._drawingHandler ); tile.drawCanvas( this.context, drawingHandler );
this._restoreRotationChanges( tile ); this._restoreRotationChanges( tile );
} else { } else {
tile.drawCanvas( this.context, this._drawingHandler ); tile.drawCanvas( this.context, drawingHandler );
} }
} else { } else {
tile.drawHTML( this.canvas ); tile.drawHTML( this.canvas );

View File

@ -544,11 +544,11 @@
* If collectionMode is true, specifies whether to arrange vertically or horizontally. * If collectionMode is true, specifies whether to arrange vertically or horizontally.
* *
* @property {Number} [collectionTileSize=800] * @property {Number} [collectionTileSize=800]
* If collectionMode is true, specifies the size, in world coordinates, for each TiledImage to fit into. * If collectionMode is true, specifies the size, in viewport coordinates, for each TiledImage to fit into.
* The TiledImage will be centered within a square of the specified size. * The TiledImage will be centered within a square of the specified size.
* *
* @property {Number} [collectionTileMargin=80] * @property {Number} [collectionTileMargin=80]
* If collectionMode is true, specifies the margin, in world coordinates, between each TiledImage. * If collectionMode is true, specifies the margin, in viewport coordinates, between each TiledImage.
* *
* @property {String|Boolean} [crossOriginPolicy=false] * @property {String|Boolean} [crossOriginPolicy=false]
* Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will * Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will

View File

@ -231,7 +231,8 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
* Renders the tile in a canvas-based context. * Renders the tile in a canvas-based context.
* @function * @function
* @param {Canvas} context * @param {Canvas} context
* @param {Function} method for firing the drawing event. drawingHandler({context, tile, rendered}) * @param {Function} drawingHandler - Method for firing the drawing event.
* drawingHandler({context, tile, rendered})
* where <code>rendered</code> is the context with the pre-drawn image. * where <code>rendered</code> is the context with the pre-drawn image.
*/ */
drawCanvas: function( context, drawingHandler ) { drawCanvas: function( context, drawingHandler ) {

View File

@ -48,10 +48,10 @@
* @param {OpenSeadragon.TileCache} options.tileCache - The TileCache for this TiledImage to use. * @param {OpenSeadragon.TileCache} options.tileCache - The TileCache for this TiledImage to use.
* @param {OpenSeadragon.Drawer} options.drawer - The Drawer for this TiledImage to draw onto. * @param {OpenSeadragon.Drawer} options.drawer - The Drawer for this TiledImage to draw onto.
* @param {OpenSeadragon.ImageLoader} options.imageLoader - The ImageLoader for this TiledImage to use. * @param {OpenSeadragon.ImageLoader} options.imageLoader - The ImageLoader for this TiledImage to use.
* @param {Number} [options.x=0] - Left position, in world coordinates. * @param {Number} [options.x=0] - Left position, in viewport coordinates.
* @param {Number} [options.y=0] - Top position, in world coordinates. * @param {Number} [options.y=0] - Top position, in viewport coordinates.
* @param {Number} [options.width=1] - Width, in world coordinates. * @param {Number} [options.width=1] - Width, in viewport coordinates.
* @param {Number} [options.height] - Height, in world coordinates. * @param {Number} [options.height] - Height, in viewport coordinates.
* @param {Number} [options.minZoomImageRatio] - See {@link OpenSeadragon.Options}. * @param {Number} [options.minZoomImageRatio] - See {@link OpenSeadragon.Options}.
* @param {Boolean} [options.wrapHorizontal] - See {@link OpenSeadragon.Options}. * @param {Boolean} [options.wrapHorizontal] - See {@link OpenSeadragon.Options}.
* @param {Boolean} [options.wrapVertical] - See {@link OpenSeadragon.Options}. * @param {Boolean} [options.wrapVertical] - See {@link OpenSeadragon.Options}.
@ -63,6 +63,8 @@
* @param {String|Boolean} [options.crossOriginPolicy] - See {@link OpenSeadragon.Options}. * @param {String|Boolean} [options.crossOriginPolicy] - See {@link OpenSeadragon.Options}.
*/ */
$.TiledImage = function( options ) { $.TiledImage = function( options ) {
var _this = this;
$.console.assert( options.tileCache, "[TiledImage] options.tileCache is required" ); $.console.assert( options.tileCache, "[TiledImage] options.tileCache is required" );
$.console.assert( options.drawer, "[TiledImage] options.drawer is required" ); $.console.assert( options.drawer, "[TiledImage] options.drawer is required" );
$.console.assert( options.viewer, "[TiledImage] options.viewer is required" ); $.console.assert( options.viewer, "[TiledImage] options.viewer is required" );
@ -87,6 +89,7 @@ $.TiledImage = function( options ) {
// Ratio of zoomable image height to width. // Ratio of zoomable image height to width.
this.normHeight = options.source.dimensions.y / options.source.dimensions.x; this.normHeight = options.source.dimensions.y / options.source.dimensions.x;
this.contentAspectX = options.source.dimensions.x / options.source.dimensions.y;
if ( options.width ) { if ( options.width ) {
this._setScale(options.width); this._setScale(options.width);
@ -126,6 +129,28 @@ $.TiledImage = function( options ) {
crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy
}, options ); }, options );
// We need a callback to give image manipulation a chance to happen
this._drawingHandler = function(args) {
/**
* This event is fired just before the tile is drawn giving the application a chance to alter the image.
*
* NOTE: This event is only fired when the drawer is using a <canvas>.
*
* @event tile-drawing
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.Tile} tile - The Tile being drawn.
* @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.
* @property {OpenSeadragon.Tile} context - The HTML canvas context being drawn into.
* @property {OpenSeadragon.Tile} rendered - The HTML canvas context containing the tile imagery.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.viewer.raiseEvent('tile-drawing', $.extend({
tiledImage: _this
}, args));
};
}; };
$.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.TiledImage.prototype */{ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.TiledImage.prototype */{
@ -164,7 +189,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
}, },
/** /**
* @returns {OpenSeadragon.Rect} This TiledImage's bounds in world coordinates. * @returns {OpenSeadragon.Rect} This TiledImage's bounds in viewport coordinates.
*/ */
getBounds: function() { getBounds: function() {
return new $.Rect( this._worldX, this._worldY, this._worldWidth, this._worldHeight ); return new $.Rect( this._worldX, this._worldY, this._worldWidth, this._worldHeight );
@ -183,9 +208,136 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
return new $.Point(this.source.dimensions.x, this.source.dimensions.y); return new $.Point(this.source.dimensions.x, this.source.dimensions.y);
}, },
// private
_viewportToImageDelta: function( viewerX, viewerY ) {
return new $.Point(viewerX * (this.source.dimensions.x / this._scale),
viewerY * ((this.source.dimensions.y * this.contentAspectX) / this._scale));
},
/**
* Translates from OpenSeadragon viewer coordinate system to image coordinate system.
* This method can be called either by passing X,Y coordinates or an
* OpenSeadragon.Point
* @function
* @param {OpenSeadragon.Point} viewerX the point in viewport coordinate system.
* @param {Number} viewerX X coordinate in viewport coordinate system.
* @param {Number} viewerY Y coordinate in viewport coordinate system.
* @return {OpenSeadragon.Point} a point representing the coordinates in the image.
*/
viewportToImageCoordinates: function( viewerX, viewerY ) {
if ( arguments.length == 1 ) {
//they passed a point instead of individual components
return this.viewportToImageCoordinates( viewerX.x, viewerX.y );
}
return this._viewportToImageDelta(viewerX - this._worldX, viewerY - this._worldY);
},
// private
_imageToViewportDelta: function( imageX, imageY ) {
return new $.Point((imageX / this.source.dimensions.x) * this._scale,
(imageY / this.source.dimensions.y / this.contentAspectX) * this._scale);
},
/**
* Translates from image coordinate system to OpenSeadragon viewer coordinate system
* This method can be called either by passing X,Y coordinates or an
* OpenSeadragon.Point
* @function
* @param {OpenSeadragon.Point} imageX the point in image coordinate system.
* @param {Number} imageX X coordinate in image coordinate system.
* @param {Number} imageY Y coordinate in image coordinate system.
* @return {OpenSeadragon.Point} a point representing the coordinates in the viewport.
*/
imageToViewportCoordinates: function( imageX, imageY ) {
if ( arguments.length == 1 ) {
//they passed a point instead of individual components
return this.imageToViewportCoordinates( imageX.x, imageX.y );
}
var point = this._imageToViewportDelta(imageX, imageY);
point.x += this._worldX;
point.y += this._worldY;
return point;
},
/**
* Translates from a rectangle which describes a portion of the image in
* pixel coordinates to OpenSeadragon viewport rectangle coordinates.
* This method can be called either by passing X,Y,width,height or an
* OpenSeadragon.Rect
* @function
* @param {OpenSeadragon.Rect} imageX the rectangle in image coordinate system.
* @param {Number} imageX the X coordinate of the top left corner of the rectangle
* in image coordinate system.
* @param {Number} imageY the Y coordinate of the top left corner of the rectangle
* in image coordinate system.
* @param {Number} pixelWidth the width in pixel of the rectangle.
* @param {Number} pixelHeight the height in pixel of the rectangle.
*/
imageToViewportRectangle: function( imageX, imageY, pixelWidth, pixelHeight ) {
var coordA,
coordB,
rect;
if( arguments.length == 1 ) {
//they passed a rectangle instead of individual components
rect = imageX;
return this.imageToViewportRectangle(
rect.x, rect.y, rect.width, rect.height
);
}
coordA = this.imageToViewportCoordinates(
imageX, imageY
);
coordB = this._imageToViewportDelta(
pixelWidth, pixelHeight
);
return new $.Rect(
coordA.x,
coordA.y,
coordB.x,
coordB.y
);
},
/**
* Translates from a rectangle which describes a portion of
* the viewport in point coordinates to image rectangle coordinates.
* This method can be called either by passing X,Y,width,height or an
* OpenSeadragon.Rect
* @function
* @param {OpenSeadragon.Rect} viewerX the rectangle in viewport coordinate system.
* @param {Number} viewerX the X coordinate of the top left corner of the rectangle
* in viewport coordinate system.
* @param {Number} imageY the Y coordinate of the top left corner of the rectangle
* in viewport coordinate system.
* @param {Number} pointWidth the width of the rectangle in viewport coordinate system.
* @param {Number} pointHeight the height of the rectangle in viewport coordinate system.
*/
viewportToImageRectangle: function( viewerX, viewerY, pointWidth, pointHeight ) {
var coordA,
coordB,
rect;
if ( arguments.length == 1 ) {
//they passed a rectangle instead of individual components
rect = viewerX;
return this.viewportToImageRectangle(
rect.x, rect.y, rect.width, rect.height
);
}
coordA = this.viewportToImageCoordinates( viewerX, viewerY );
coordB = this._viewportToImageDelta(pointWidth, pointHeight);
return new $.Rect(
coordA.x,
coordA.y,
coordB.x,
coordB.y
);
},
/** /**
* Sets the TiledImage's position in the world. * Sets the TiledImage's position in the world.
* @param {OpenSeadragon.Point} position - The new position, in world coordinates. * @param {OpenSeadragon.Point} position - The new position, in viewport coordinates.
* @fires OpenSeadragon.TiledImage.event:bounds-change * @fires OpenSeadragon.TiledImage.event:bounds-change
*/ */
setPosition: function(position) { setPosition: function(position) {
@ -201,7 +353,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
/** /**
* Sets the TiledImage's width in the world, adjusting the height to match based on aspect ratio. * Sets the TiledImage's width in the world, adjusting the height to match based on aspect ratio.
* @param {Number} width - The new width, in world coordinates. * @param {Number} width - The new width, in viewport coordinates.
* @fires OpenSeadragon.TiledImage.event:bounds-change * @fires OpenSeadragon.TiledImage.event:bounds-change
*/ */
setWidth: function(width) { setWidth: function(width) {
@ -216,7 +368,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
/** /**
* Sets the TiledImage's height in the world, adjusting the width to match based on aspect ratio. * Sets the TiledImage's height in the world, adjusting the width to match based on aspect ratio.
* @param {Number} height - The new height, in world coordinates. * @param {Number} height - The new height, in viewport coordinates.
* @fires OpenSeadragon.TiledImage.event:bounds-change * @fires OpenSeadragon.TiledImage.event:bounds-change
*/ */
setHeight: function(height) { setHeight: function(height) {
@ -874,7 +1026,7 @@ function drawTiles( tiledImage, lastDrawn ){
for ( i = lastDrawn.length - 1; i >= 0; i-- ) { for ( i = lastDrawn.length - 1; i >= 0; i-- ) {
tile = lastDrawn[ i ]; tile = lastDrawn[ i ];
tiledImage._drawer.drawTile( tile ); tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler );
tile.beingDrawn = true; tile.beingDrawn = true;
if( tiledImage.debugMode ){ if( tiledImage.debugMode ){

View File

@ -608,6 +608,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
if (successes) { if (successes) {
if (_this._firstOpen || !_this.preserveViewport) { if (_this._firstOpen || !_this.preserveViewport) {
_this.viewport.goHome( true ); _this.viewport.goHome( true );
_this.viewport.update();
} }
_this._firstOpen = false; _this._firstOpen = false;
@ -1249,10 +1250,10 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
* named 'getTileUrl', it is treated as a custom TileSource. * named 'getTileUrl', it is treated as a custom TileSource.
* @param {Number} [options.index] The index of the item. Added on top of * @param {Number} [options.index] The index of the item. Added on top of
* all other items if not specified. * all other items if not specified.
* @param {Number} [options.x=0] The X position for the image in world coordinates. * @param {Number} [options.x=0] The X position for the image in viewport coordinates.
* @param {Number} [options.y=0] The Y position for the image in world coordinates. * @param {Number} [options.y=0] The Y position for the image in viewport coordinates.
* @param {Number} [options.width=1] The width for the image in world coordinates. * @param {Number} [options.width=1] The width for the image in viewport coordinates.
* @param {Number} [options.height] The height for the image in world coordinates. * @param {Number} [options.height] The height for the image in viewport coordinates.
* @param {Function} [options.success] A function that gets called when the image is * @param {Function} [options.success] A function that gets called when the image is
* successfully added. It's passed the event object which contains a single property: * successfully added. It's passed the event object which contains a single property:
* "item", the resulting TiledImage. * "item", the resulting TiledImage.

View File

@ -163,8 +163,8 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/** /**
* Updates the viewport's home bounds and constraints. * Updates the viewport's home bounds and constraints.
* @function * @function
* @param {OpenSeadragon.Rect} bounds - the new bounds in world coordinates * @param {OpenSeadragon.Rect} bounds - the new bounds in viewport coordinates
* @param {Number} contentFactor - how many content units per world unit * @param {Number} contentFactor - how many content units per viewport unit
* @fires OpenSeadragon.Viewer.event:reset-size * @fires OpenSeadragon.Viewer.event:reset-size
*/ */
setHomeBounds: function(bounds, contentFactor) { setHomeBounds: function(bounds, contentFactor) {
@ -303,7 +303,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/** /**
* @function * @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location). * @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. * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.
*/ */
getBounds: function( current ) { getBounds: function( current ) {
var center = this.getCenter( current ), var center = this.getCenter( current ),
@ -322,7 +322,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
* @function * @function
* @param {Boolean} current - Pass true for the current location; defaults to false (target location). * @param {Boolean} current - Pass true for the current location; defaults to false (target location).
* @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to,
* including the space taken by margins, in world coordinates. * including the space taken by margins, in viewport coordinates.
*/ */
getBoundsWithMargins: function( current ) { getBoundsWithMargins: function( current ) {
var bounds = this.getBounds(current); var bounds = this.getBounds(current);
@ -938,10 +938,18 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
); );
}, },
// private
_viewportToImageDelta: function( viewerX, viewerY ) {
var scale = this.homeBounds.width;
return new $.Point(viewerX * (this.contentSize.x / scale),
viewerY * ((this.contentSize.y * this.contentAspectX) / scale));
},
/** /**
* Translates from OpenSeadragon viewer coordinate system to image coordinate system. * Translates from OpenSeadragon viewer coordinate system to image coordinate system.
* This method can be called either by passing X,Y coordinates or an * This method can be called either by passing X,Y coordinates or an
* OpenSeadragon.Point * OpenSeadragon.Point
* Note: not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead.
* @function * @function
* @param {OpenSeadragon.Point} viewerX the point in viewport coordinate system. * @param {OpenSeadragon.Point} viewerX the point in viewport coordinate system.
* @param {Number} viewerX X coordinate in viewport coordinate system. * @param {Number} viewerX X coordinate in viewport coordinate system.
@ -953,13 +961,26 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
//they passed a point instead of individual components //they passed a point instead of individual components
return this.viewportToImageCoordinates( viewerX.x, viewerX.y ); return this.viewportToImageCoordinates( viewerX.x, viewerX.y );
} }
return new $.Point( viewerX * this.contentSize.x, viewerY * this.contentSize.y * this.contentAspectX );
if (this.viewer && this.viewer.world.getItemCount() > 1) {
$.console.error('[Viewport.viewportToImageCoordinates] is not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead.');
}
return this._viewportToImageDelta(viewerX - this.homeBounds.x, viewerY - this.homeBounds.y);
},
// private
_imageToViewportDelta: function( imageX, imageY ) {
var scale = this.homeBounds.width;
return new $.Point((imageX / this.contentSize.x) * scale,
(imageY / this.contentSize.y / this.contentAspectX) * scale);
}, },
/** /**
* Translates from image coordinate system to OpenSeadragon viewer coordinate system * Translates from image coordinate system to OpenSeadragon viewer coordinate system
* This method can be called either by passing X,Y coordinates or an * This method can be called either by passing X,Y coordinates or an
* OpenSeadragon.Point * OpenSeadragon.Point
* Note: not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.
* @function * @function
* @param {OpenSeadragon.Point} imageX the point in image coordinate system. * @param {OpenSeadragon.Point} imageX the point in image coordinate system.
* @param {Number} imageX X coordinate in image coordinate system. * @param {Number} imageX X coordinate in image coordinate system.
@ -971,7 +992,15 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
//they passed a point instead of individual components //they passed a point instead of individual components
return this.imageToViewportCoordinates( imageX.x, imageX.y ); return this.imageToViewportCoordinates( imageX.x, imageX.y );
} }
return new $.Point( imageX / this.contentSize.x, imageY / this.contentSize.y / this.contentAspectX );
if (this.viewer && this.viewer.world.getItemCount() > 1) {
$.console.error('[Viewport.imageToViewportCoordinates] is not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.');
}
var point = this._imageToViewportDelta(imageX, imageY);
point.x += this.homeBounds.x;
point.y += this.homeBounds.y;
return point;
}, },
/** /**
@ -979,6 +1008,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
* pixel coordinates to OpenSeadragon viewport rectangle coordinates. * pixel coordinates to OpenSeadragon viewport rectangle coordinates.
* This method can be called either by passing X,Y,width,height or an * This method can be called either by passing X,Y,width,height or an
* OpenSeadragon.Rect * OpenSeadragon.Rect
* Note: not accurate with multi-image; use TiledImage.imageToViewportRectangle instead.
* @function * @function
* @param {OpenSeadragon.Rect} imageX the rectangle in image coordinate system. * @param {OpenSeadragon.Rect} imageX the rectangle in image coordinate system.
* @param {Number} imageX the X coordinate of the top left corner of the rectangle * @param {Number} imageX the X coordinate of the top left corner of the rectangle
@ -999,10 +1029,11 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
rect.x, rect.y, rect.width, rect.height rect.x, rect.y, rect.width, rect.height
); );
} }
coordA = this.imageToViewportCoordinates( coordA = this.imageToViewportCoordinates(
imageX, imageY imageX, imageY
); );
coordB = this.imageToViewportCoordinates( coordB = this._imageToViewportDelta(
pixelWidth, pixelHeight pixelWidth, pixelHeight
); );
return new $.Rect( return new $.Rect(
@ -1018,6 +1049,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
* the viewport in point coordinates to image rectangle coordinates. * the viewport in point coordinates to image rectangle coordinates.
* This method can be called either by passing X,Y,width,height or an * This method can be called either by passing X,Y,width,height or an
* OpenSeadragon.Rect * OpenSeadragon.Rect
* Note: not accurate with multi-image; use TiledImage.viewportToImageRectangle instead.
* @function * @function
* @param {OpenSeadragon.Rect} viewerX the rectangle in viewport coordinate system. * @param {OpenSeadragon.Rect} viewerX the rectangle in viewport coordinate system.
* @param {Number} viewerX the X coordinate of the top left corner of the rectangle * @param {Number} viewerX the X coordinate of the top left corner of the rectangle
@ -1038,8 +1070,9 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
rect.x, rect.y, rect.width, rect.height rect.x, rect.y, rect.width, rect.height
); );
} }
coordA = this.viewportToImageCoordinates( viewerX, viewerY ); coordA = this.viewportToImageCoordinates( viewerX, viewerY );
coordB = this.viewportToImageCoordinates( pointWidth, pointHeight ); coordB = this._viewportToImageDelta(pointWidth, pointHeight);
return new $.Rect( return new $.Rect(
coordA.x, coordA.x,
coordA.y, coordA.y,
@ -1051,6 +1084,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/** /**
* Convert pixel coordinates relative to the viewer element to image * Convert pixel coordinates relative to the viewer element to image
* coordinates. * coordinates.
* Note: not accurate with multi-image.
* @param {OpenSeadragon.Point} pixel * @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
@ -1062,6 +1096,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/** /**
* Convert pixel coordinates relative to the image to * Convert pixel coordinates relative to the image to
* viewer element coordinates. * viewer element coordinates.
* Note: not accurate with multi-image.
* @param {OpenSeadragon.Point} pixel * @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
@ -1072,6 +1107,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/** /**
* Convert pixel coordinates relative to the window to image coordinates. * Convert pixel coordinates relative to the window to image coordinates.
* Note: not accurate with multi-image.
* @param {OpenSeadragon.Point} pixel * @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
@ -1083,6 +1119,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/** /**
* Convert image coordinates to pixel coordinates relative to the window. * Convert image coordinates to pixel coordinates relative to the window.
* Note: not accurate with multi-image.
* @param {OpenSeadragon.Point} pixel * @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
@ -1140,15 +1177,21 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
* 1 means original image size, 0.5 half size... * 1 means original image size, 0.5 half size...
* Viewport zoom: ratio of the displayed image's width to viewport's width. * 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... * 1 means identical width, 2 means image's width is twice the viewport's width...
* Note: not accurate with multi-image.
* @function * @function
* @param {Number} viewportZoom The viewport zoom * @param {Number} viewportZoom The viewport zoom
* target zoom. * target zoom.
* @returns {Number} imageZoom The image zoom * @returns {Number} imageZoom The image zoom
*/ */
viewportToImageZoom: function( viewportZoom ) { viewportToImageZoom: function( viewportZoom ) {
var imageWidth = this.viewer.source.dimensions.x; if (this.viewer && this.viewer.world.getItemCount() > 1) {
$.console.error('[Viewport.viewportToImageZoom] is not accurate with multi-image.');
}
var imageWidth = this.contentSize.x;
var containerWidth = this._containerInnerSize.x; var containerWidth = this._containerInnerSize.x;
var viewportToImageZoomRatio = containerWidth / imageWidth; var scale = this.homeBounds.width;
var viewportToImageZoomRatio = (containerWidth / imageWidth) * scale;
return viewportZoom * viewportToImageZoomRatio; return viewportZoom * viewportToImageZoomRatio;
}, },
@ -1158,15 +1201,21 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
* 1 means original image size, 0.5 half size... * 1 means original image size, 0.5 half size...
* Viewport zoom: ratio of the displayed image's width to viewport's width. * 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... * 1 means identical width, 2 means image's width is twice the viewport's width...
* Note: not accurate with multi-image.
* @function * @function
* @param {Number} imageZoom The image zoom * @param {Number} imageZoom The image zoom
* target zoom. * target zoom.
* @returns {Number} viewportZoom The viewport zoom * @returns {Number} viewportZoom The viewport zoom
*/ */
imageToViewportZoom: function( imageZoom ) { imageToViewportZoom: function( imageZoom ) {
var imageWidth = this.viewer.source.dimensions.x; if (this.viewer && this.viewer.world.getItemCount() > 1) {
$.console.error('[Viewport.imageToViewportZoom] is not accurate with multi-image.');
}
var imageWidth = this.contentSize.x;
var containerWidth = this._containerInnerSize.x; var containerWidth = this._containerInnerSize.x;
var viewportToImageZoomRatio = imageWidth / containerWidth; var scale = this.homeBounds.width;
var viewportToImageZoomRatio = (imageWidth / containerWidth) / scale;
return imageZoom * viewportToImageZoomRatio; return imageZoom * viewportToImageZoomRatio;
} }
}; };

View File

@ -245,7 +245,7 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
}, },
/** /**
* @returns {OpenSeadragon.Rect} The smallest rectangle that encloses all items, in world coordinates. * @returns {OpenSeadragon.Rect} The smallest rectangle that encloses all items, in viewport coordinates.
*/ */
getHomeBounds: function() { getHomeBounds: function() {
return this._homeBounds.clone(); return this._homeBounds.clone();
@ -253,9 +253,9 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
/** /**
* To facilitate zoom constraints, we keep track of the pixel density of the * To facilitate zoom constraints, we keep track of the pixel density of the
* densest item in the World (i.e. the item whose content size to world size * densest item in the World (i.e. the item whose content size to viewport size
* ratio is the highest) and save it as this "content factor". * ratio is the highest) and save it as this "content factor".
* @returns {Number} the number of content units per world unit. * @returns {Number} the number of content units per viewport unit.
*/ */
getContentFactor: function() { getContentFactor: function() {
return this._contentFactor; return this._contentFactor;

View File

@ -7,7 +7,7 @@
var self = this; var self = this;
var testInitialOpen = true; var testInitialOpen = true;
var testOverlays = true; var testOverlays = false;
var testMargins = false; var testMargins = false;
var testNavigator = false; var testNavigator = false;
var margins; var margins;
@ -34,6 +34,12 @@
if (testInitialOpen) { if (testInitialOpen) {
config.tileSources = [ config.tileSources = [
{
tileSource: "../../data/testpattern.dzi",
x: 4,
y: 2,
width: 2
},
{ {
tileSource: "../../data/tall.dzi", tileSource: "../../data/tall.dzi",
x: 1.5, x: 1.5,

View File

@ -39,22 +39,6 @@
start(); start();
}); });
// ----------
asyncTest('tile-drawing event', function() {
createViewer({
tileSources: '/test/data/testpattern.dzi'
});
viewer.addHandler('tile-drawing', function handler(event) {
viewer.removeHandler('tile-drawing', handler);
equal(event.eventSource, viewer, 'sender of tile-drawing event was viewer');
ok(event.tile, 'tile-drawing event includes a tile');
ok(event.context, 'tile-drawing event includes a context');
ok(event.rendered, 'tile-drawing event includes a rendered');
start();
});
});
// ---------- // ----------
asyncTest('rotation', function() { asyncTest('rotation', function() {
createViewer({ createViewer({

View File

@ -1,4 +1,4 @@
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */ /* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog, propEqual */
(function() { (function() {
var viewer; var viewer;
@ -45,6 +45,20 @@
checkBounds(image, new OpenSeadragon.Rect(5, 6, 10, 40), 'initial bounds'); checkBounds(image, new OpenSeadragon.Rect(5, 6, 10, 40), 'initial bounds');
var scale = image.getContentSize().x / image.getBounds().width;
var viewportPoint = new OpenSeadragon.Point(10, 11);
var imagePoint = viewportPoint.minus(image.getBounds().getTopLeft()).times(scale);
propEqual(image.viewportToImageCoordinates(viewportPoint), imagePoint, 'viewportToImageCoordinates');
propEqual(image.imageToViewportCoordinates(imagePoint), viewportPoint, 'imageToViewportCoordinates');
var viewportRect = new OpenSeadragon.Rect(viewportPoint.x, viewportPoint.y, 6, 7);
var imageRect = new OpenSeadragon.Rect(imagePoint.x, imagePoint.y,
viewportRect.width * scale, viewportRect.height * scale);
propEqual(image.viewportToImageRectangle(viewportRect), imageRect, 'viewportToImageRectangle');
propEqual(image.imageToViewportRectangle(imageRect), viewportRect, 'imageToViewportRectangle');
image.addHandler('bounds-change', function boundsChangeHandler(event) { image.addHandler('bounds-change', function boundsChangeHandler(event) {
image.removeHandler('bounds-change', boundsChangeHandler); image.removeHandler('bounds-change', boundsChangeHandler);
handlerCount++; handlerCount++;
@ -102,6 +116,16 @@
ok(event.tile, 'update-tile event includes tile'); ok(event.tile, 'update-tile event includes tile');
}); });
viewer.addHandler('tile-drawing', function tileDrawingHandler(event) {
viewer.removeHandler('tile-drawing', tileDrawingHandler);
handlerCount++;
equal(event.eventSource, viewer, 'sender of tile-drawing event was viewer');
equal(event.tiledImage, image, 'tiledImage of update-level event is correct');
ok(event.tile, 'tile-drawing event includes a tile');
ok(event.context, 'tile-drawing event includes a context');
ok(event.rendered, 'tile-drawing event includes a rendered');
});
viewer.addHandler('tile-drawn', function tileDrawnHandler(event) { viewer.addHandler('tile-drawn', function tileDrawnHandler(event) {
viewer.removeHandler('tile-drawn', tileDrawnHandler); viewer.removeHandler('tile-drawn', tileDrawnHandler);
handlerCount++; handlerCount++;
@ -109,7 +133,7 @@
equal(event.tiledImage, image, 'tiledImage of update-level event is correct'); equal(event.tiledImage, image, 'tiledImage of update-level event is correct');
ok(event.tile, 'tile-drawn event includes tile'); ok(event.tile, 'tile-drawn event includes tile');
equal(handlerCount, 3, 'correct number of handlers called'); equal(handlerCount, 4, 'correct number of handlers called');
start(); start();
}); });