diff --git a/src/drawer.js b/src/drawer.js
index 9a3578f9..3ac2c1fa 100644
--- a/src/drawer.js
+++ b/src/drawer.js
@@ -94,7 +94,7 @@ $.Drawer = function( options ) {
* @member {Object} context
* @memberof OpenSeadragon.Drawer#
*/
- this.context = this.useCanvas ? this.canvas.getContext( "2d" ) : null;
+ this.context = this.useCanvas ? this.canvas.getContext( this.useCanvas.contextType || "2d" ) : null;
/**
* Sketch canvas used to temporarily draw tiles which cannot be drawn directly
@@ -142,33 +142,6 @@ $.Drawer = function( options ) {
/** @lends OpenSeadragon.Drawer.prototype */
$.Drawer.prototype = {
- // deprecated
- addOverlay: function( element, location, placement, onDraw ) {
- $.console.error("drawer.addOverlay is deprecated. Use viewer.addOverlay instead.");
- this.viewer.addOverlay( element, location, placement, onDraw );
- return this;
- },
-
- // deprecated
- updateOverlay: function( element, location, placement ) {
- $.console.error("drawer.updateOverlay is deprecated. Use viewer.updateOverlay instead.");
- this.viewer.updateOverlay( element, location, placement );
- return this;
- },
-
- // deprecated
- removeOverlay: function( element ) {
- $.console.error("drawer.removeOverlay is deprecated. Use viewer.removeOverlay instead.");
- this.viewer.removeOverlay( element );
- return this;
- },
-
- // deprecated
- clearOverlays: function() {
- $.console.error("drawer.clearOverlays is deprecated. Use viewer.clearOverlays instead.");
- this.viewer.clearOverlays();
- return this;
- },
/**
* This function converts the given point from to the drawer coordinate by
@@ -206,63 +179,9 @@ $.Drawer.prototype = {
context.clip();
},
- /**
- * Set the opacity of the drawer.
- * @param {Number} opacity
- * @returns {OpenSeadragon.Drawer} Chainable.
- */
- setOpacity: function( opacity ) {
- $.console.error("drawer.setOpacity is deprecated. Use tiledImage.setOpacity instead.");
- var world = this.viewer.world;
- for (var i = 0; i < world.getItemCount(); i++) {
- world.getItemAt( i ).setOpacity( opacity );
- }
- return this;
- },
- /**
- * Get the opacity of the drawer.
- * @returns {Number}
- */
- getOpacity: function() {
- $.console.error("drawer.getOpacity is deprecated. Use tiledImage.getOpacity instead.");
- var world = this.viewer.world;
- var maxOpacity = 0;
- for (var i = 0; i < world.getItemCount(); i++) {
- var opacity = world.getItemAt( i ).getOpacity();
- if ( opacity > maxOpacity ) {
- maxOpacity = opacity;
- }
- }
- return maxOpacity;
- },
- // deprecated
- needsUpdate: function() {
- $.console.error( "[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead." );
- return this.viewer.world.needsDraw();
- },
- // deprecated
- numTilesLoaded: function() {
- $.console.error( "[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead." );
- return this.viewer.tileCache.numTilesLoaded();
- },
-
- // deprecated
- reset: function() {
- $.console.error( "[Drawer.reset] this function is deprecated. Use World.resetItems instead." );
- this.viewer.world.resetItems();
- return this;
- },
-
- // deprecated
- update: function() {
- $.console.error( "[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead." );
- this.clear();
- this.viewer.world.draw();
- return this;
- },
/**
* @returns {Boolean} True if rotation is supported.
@@ -761,7 +680,92 @@ $.Drawer.prototype = {
x: sketchCanvasSize,
y: sketchCanvasSize
};
- }
+ },
+
+ // deprecated functions
+ // deprecated
+ addOverlay: function( element, location, placement, onDraw ) {
+ $.console.error("drawer.addOverlay is deprecated. Use viewer.addOverlay instead.");
+ this.viewer.addOverlay( element, location, placement, onDraw );
+ return this;
+ },
+
+ // deprecated
+ updateOverlay: function( element, location, placement ) {
+ $.console.error("drawer.updateOverlay is deprecated. Use viewer.updateOverlay instead.");
+ this.viewer.updateOverlay( element, location, placement );
+ return this;
+ },
+
+ // deprecated
+ removeOverlay: function( element ) {
+ $.console.error("drawer.removeOverlay is deprecated. Use viewer.removeOverlay instead.");
+ this.viewer.removeOverlay( element );
+ return this;
+ },
+
+ // deprecated
+ clearOverlays: function() {
+ $.console.error("drawer.clearOverlays is deprecated. Use viewer.clearOverlays instead.");
+ this.viewer.clearOverlays();
+ return this;
+ },
+ // deprecated
+ needsUpdate: function() {
+ $.console.error( "[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead." );
+ return this.viewer.world.needsDraw();
+ },
+
+ // deprecated
+ numTilesLoaded: function() {
+ $.console.error( "[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead." );
+ return this.viewer.tileCache.numTilesLoaded();
+ },
+
+ // deprecated
+ reset: function() {
+ $.console.error( "[Drawer.reset] this function is deprecated. Use World.resetItems instead." );
+ this.viewer.world.resetItems();
+ return this;
+ },
+
+ // deprecated
+ update: function() {
+ $.console.error( "[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead." );
+ this.clear();
+ this.viewer.world.draw();
+ return this;
+ },
+ /**
+ * Set the opacity of the drawer.
+ * @param {Number} opacity
+ * @returns {OpenSeadragon.Drawer} Chainable.
+ */
+ setOpacity: function( opacity ) {
+ $.console.error("drawer.setOpacity is deprecated. Use tiledImage.setOpacity instead.");
+ var world = this.viewer.world;
+ for (var i = 0; i < world.getItemCount(); i++) {
+ world.getItemAt( i ).setOpacity( opacity );
+ }
+ return this;
+ },
+
+ /**
+ * Get the opacity of the drawer.
+ * @returns {Number}
+ */
+ getOpacity: function() {
+ $.console.error("drawer.getOpacity is deprecated. Use tiledImage.getOpacity instead.");
+ var world = this.viewer.world;
+ var maxOpacity = 0;
+ for (var i = 0; i < world.getItemCount(); i++) {
+ var opacity = world.getItemAt( i ).getOpacity();
+ if ( opacity > maxOpacity ) {
+ maxOpacity = opacity;
+ }
+ }
+ return maxOpacity;
+ },
};
}( OpenSeadragon ));
diff --git a/src/tile.js b/src/tile.js
index 07e89b2b..c6ac95eb 100644
--- a/src/tile.js
+++ b/src/tile.js
@@ -34,525 +34,525 @@
(function( $ ){
-/**
- * @class Tile
- * @memberof OpenSeadragon
- * @param {Number} level The zoom level this tile belongs to.
- * @param {Number} x The vector component 'x'.
- * @param {Number} y The vector component 'y'.
- * @param {OpenSeadragon.Rect} bounds Where this tile fits, in normalized
- * coordinates.
- * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has
- * this tile failed to load? )
- * @param {String|Function} url The URL of this tile's image or a function that returns a url.
- * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it
- * is provided directly by the tile source.
- * @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request .
- * @param {Object} ajaxHeaders The headers to send with this tile's AJAX request (if applicable).
- * @param {OpenSeadragon.Rect} sourceBounds The portion of the tile to use as the source of the
- * drawing operation, in pixels. Note that this only works when drawing with canvas; when drawing
- * with HTML the entire tile is always used.
- * @param {String} postData HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
- * see TileSource::getPostData) or null
- * @param {String} cacheKey key to act as a tile cache, must be unique for tiles with unique image data
- */
-$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders, sourceBounds, postData, cacheKey) {
/**
- * The zoom level this tile belongs to.
- * @member {Number} level
- * @memberof OpenSeadragon.Tile#
- */
- this.level = level;
- /**
- * The vector component 'x'.
- * @member {Number} x
- * @memberof OpenSeadragon.Tile#
- */
- this.x = x;
- /**
- * The vector component 'y'.
- * @member {Number} y
- * @memberof OpenSeadragon.Tile#
- */
- this.y = y;
- /**
- * Where this tile fits, in normalized coordinates
- * @member {OpenSeadragon.Rect} bounds
- * @memberof OpenSeadragon.Tile#
- */
- this.bounds = bounds;
- /**
- * The portion of the tile to use as the source of the drawing operation, in pixels. Note that
- * this only works when drawing with canvas; when drawing with HTML the entire tile is always used.
- * @member {OpenSeadragon.Rect} sourceBounds
- * @memberof OpenSeadragon.Tile#
- */
- this.sourceBounds = sourceBounds;
- /**
- * Is this tile a part of a sparse image? Also has this tile failed to load?
- * @member {Boolean} exists
- * @memberof OpenSeadragon.Tile#
- */
- this.exists = exists;
- /**
- * Private property to hold string url or url retriever function.
- * Consumers should access via Tile.getUrl()
- * @private
- * @member {String|Function} url
- * @memberof OpenSeadragon.Tile#
- */
- this._url = url;
- /**
- * Post parameters for this tile. For example, it can be an URL-encoded string
- * in k1=v1&k2=v2... format, or a JSON, or a FormData instance... or null if no POST request used
- * @member {String} postData HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
+ * @class Tile
+ * @memberof OpenSeadragon
+ * @param {Number} level The zoom level this tile belongs to.
+ * @param {Number} x The vector component 'x'.
+ * @param {Number} y The vector component 'y'.
+ * @param {OpenSeadragon.Rect} bounds Where this tile fits, in normalized
+ * coordinates.
+ * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has
+ * this tile failed to load? )
+ * @param {String|Function} url The URL of this tile's image or a function that returns a url.
+ * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it
+ * is provided directly by the tile source.
+ * @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request .
+ * @param {Object} ajaxHeaders The headers to send with this tile's AJAX request (if applicable).
+ * @param {OpenSeadragon.Rect} sourceBounds The portion of the tile to use as the source of the
+ * drawing operation, in pixels. Note that this only works when drawing with canvas; when drawing
+ * with HTML the entire tile is always used.
+ * @param {String} postData HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getPostData) or null
- * @memberof OpenSeadragon.Tile#
+ * @param {String} cacheKey key to act as a tile cache, must be unique for tiles with unique image data
*/
- this.postData = postData;
- /**
- * The context2D of this tile if it is provided directly by the tile source.
- * @member {CanvasRenderingContext2D} context2D
- * @memberOf OpenSeadragon.Tile#
- */
- this.context2D = context2D;
- /**
- * Whether to load this tile's image with an AJAX request.
- * @member {Boolean} loadWithAjax
- * @memberof OpenSeadragon.Tile#
- */
- this.loadWithAjax = loadWithAjax;
- /**
- * The headers to be used in requesting this tile's image.
- * Only used if loadWithAjax is set to true.
- * @member {Object} ajaxHeaders
- * @memberof OpenSeadragon.Tile#
- */
- this.ajaxHeaders = ajaxHeaders;
+ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders, sourceBounds, postData, cacheKey) {
+ /**
+ * The zoom level this tile belongs to.
+ * @member {Number} level
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.level = level;
+ /**
+ * The vector component 'x'.
+ * @member {Number} x
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.x = x;
+ /**
+ * The vector component 'y'.
+ * @member {Number} y
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.y = y;
+ /**
+ * Where this tile fits, in normalized coordinates
+ * @member {OpenSeadragon.Rect} bounds
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.bounds = bounds;
+ /**
+ * The portion of the tile to use as the source of the drawing operation, in pixels. Note that
+ * this only works when drawing with canvas; when drawing with HTML the entire tile is always used.
+ * @member {OpenSeadragon.Rect} sourceBounds
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.sourceBounds = sourceBounds;
+ /**
+ * Is this tile a part of a sparse image? Also has this tile failed to load?
+ * @member {Boolean} exists
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.exists = exists;
+ /**
+ * Private property to hold string url or url retriever function.
+ * Consumers should access via Tile.getUrl()
+ * @private
+ * @member {String|Function} url
+ * @memberof OpenSeadragon.Tile#
+ */
+ this._url = url;
+ /**
+ * Post parameters for this tile. For example, it can be an URL-encoded string
+ * in k1=v1&k2=v2... format, or a JSON, or a FormData instance... or null if no POST request used
+ * @member {String} postData HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
+ * see TileSource::getPostData) or null
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.postData = postData;
+ /**
+ * The context2D of this tile if it is provided directly by the tile source.
+ * @member {CanvasRenderingContext2D} context2D
+ * @memberOf OpenSeadragon.Tile#
+ */
+ this.context2D = context2D;
+ /**
+ * Whether to load this tile's image with an AJAX request.
+ * @member {Boolean} loadWithAjax
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.loadWithAjax = loadWithAjax;
+ /**
+ * The headers to be used in requesting this tile's image.
+ * Only used if loadWithAjax is set to true.
+ * @member {Object} ajaxHeaders
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.ajaxHeaders = ajaxHeaders;
- if (cacheKey === undefined) {
- $.console.warn("Tile constructor needs 'cacheKey' variable: creation tile cache" +
- " in Tile class is deprecated. TileSource.prototype.getTileHashKey will be used.");
- cacheKey = $.TileSource.prototype.getTileHashKey(level, x, y, url, ajaxHeaders, postData);
- }
- /**
- * The unique cache key for this tile.
- * @member {String} cacheKey
- * @memberof OpenSeadragon.Tile#
- */
- this.cacheKey = cacheKey;
- /**
- * Is this tile loaded?
- * @member {Boolean} loaded
- * @memberof OpenSeadragon.Tile#
- */
- this.loaded = false;
- /**
- * Is this tile loading?
- * @member {Boolean} loading
- * @memberof OpenSeadragon.Tile#
- */
- this.loading = false;
-
- /**
- * The HTML div element for this tile
- * @member {Element} element
- * @memberof OpenSeadragon.Tile#
- */
- this.element = null;
- /**
- * The HTML img element for this tile.
- * @member {Element} imgElement
- * @memberof OpenSeadragon.Tile#
- */
- this.imgElement = null;
-
- /**
- * The alias of this.element.style.
- * @member {String} style
- * @memberof OpenSeadragon.Tile#
- */
- this.style = null;
- /**
- * This tile's position on screen, in pixels.
- * @member {OpenSeadragon.Point} position
- * @memberof OpenSeadragon.Tile#
- */
- this.position = null;
- /**
- * This tile's size on screen, in pixels.
- * @member {OpenSeadragon.Point} size
- * @memberof OpenSeadragon.Tile#
- */
- this.size = null;
- /**
- * Whether to flip the tile when rendering.
- * @member {Boolean} flipped
- * @memberof OpenSeadragon.Tile#
- */
- this.flipped = false;
- /**
- * The start time of this tile's blending.
- * @member {Number} blendStart
- * @memberof OpenSeadragon.Tile#
- */
- this.blendStart = null;
- /**
- * The current opacity this tile should be.
- * @member {Number} opacity
- * @memberof OpenSeadragon.Tile#
- */
- this.opacity = null;
- /**
- * The squared distance of this tile to the viewport center.
- * Use for comparing tiles.
- * @private
- * @member {Number} squaredDistance
- * @memberof OpenSeadragon.Tile#
- */
- this.squaredDistance = null;
- /**
- * The visibility score of this tile.
- * @member {Number} visibility
- * @memberof OpenSeadragon.Tile#
- */
- this.visibility = null;
-
- /**
- * The transparency indicator of this tile.
- * @member {Boolean} hasTransparency true if tile contains transparency for correct rendering
- * @memberof OpenSeadragon.Tile#
- */
- this.hasTransparency = false;
-
- /**
- * Whether this tile is currently being drawn.
- * @member {Boolean} beingDrawn
- * @memberof OpenSeadragon.Tile#
- */
- this.beingDrawn = false;
-
- /**
- * Timestamp the tile was last touched.
- * @member {Number} lastTouchTime
- * @memberof OpenSeadragon.Tile#
- */
- this.lastTouchTime = 0;
-
- /**
- * Whether this tile is in the right-most column for its level.
- * @member {Boolean} isRightMost
- * @memberof OpenSeadragon.Tile#
- */
- this.isRightMost = false;
-
- /**
- * Whether this tile is in the bottom-most row for its level.
- * @member {Boolean} isBottomMost
- * @memberof OpenSeadragon.Tile#
- */
- this.isBottomMost = false;
-};
-
-/** @lends OpenSeadragon.Tile.prototype */
-$.Tile.prototype = {
-
- /**
- * Provides a string representation of this tiles level and (x,y)
- * components.
- * @function
- * @returns {String}
- */
- toString: function() {
- return this.level + "/" + this.x + "_" + this.y;
- },
-
- // private
- _hasTransparencyChannel: function() {
- console.warn("Tile.prototype._hasTransparencyChannel() has been " +
- "deprecated and will be removed in the future. Use TileSource.prototype.hasTransparency() instead.");
- return !!this.context2D || this.getUrl().match('.png');
- },
-
- /**
- * Renders the tile in an html container.
- * @function
- * @param {Element} container
- */
- drawHTML: function( container ) {
- if (!this.cacheImageRecord) {
- $.console.warn(
- '[Tile.drawHTML] attempting to draw tile %s when it\'s not cached',
- this.toString());
- return;
+ if (cacheKey === undefined) {
+ $.console.warn("Tile constructor needs 'cacheKey' variable: creation tile cache" +
+ " in Tile class is deprecated. TileSource.prototype.getTileHashKey will be used.");
+ cacheKey = $.TileSource.prototype.getTileHashKey(level, x, y, url, ajaxHeaders, postData);
}
+ /**
+ * The unique cache key for this tile.
+ * @member {String} cacheKey
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.cacheKey = cacheKey;
+ /**
+ * Is this tile loaded?
+ * @member {Boolean} loaded
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.loaded = false;
+ /**
+ * Is this tile loading?
+ * @member {Boolean} loading
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.loading = false;
- if ( !this.loaded ) {
- $.console.warn(
- "Attempting to draw tile %s when it's not yet loaded.",
- this.toString()
- );
- return;
- }
+ /**
+ * The HTML div element for this tile
+ * @member {Element} element
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.element = null;
+ /**
+ * The HTML img element for this tile.
+ * @member {Element} imgElement
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.imgElement = null;
- //EXPERIMENTAL - trying to figure out how to scale the container
- // content during animation of the container size.
+ /**
+ * The alias of this.element.style.
+ * @member {String} style
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.style = null;
+ /**
+ * This tile's position on screen, in pixels.
+ * @member {OpenSeadragon.Point} position
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.position = null;
+ /**
+ * This tile's size on screen, in pixels.
+ * @member {OpenSeadragon.Point} size
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.size = null;
+ /**
+ * Whether to flip the tile when rendering.
+ * @member {Boolean} flipped
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.flipped = false;
+ /**
+ * The start time of this tile's blending.
+ * @member {Number} blendStart
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.blendStart = null;
+ /**
+ * The current opacity this tile should be.
+ * @member {Number} opacity
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.opacity = null;
+ /**
+ * The squared distance of this tile to the viewport center.
+ * Use for comparing tiles.
+ * @private
+ * @member {Number} squaredDistance
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.squaredDistance = null;
+ /**
+ * The visibility score of this tile.
+ * @member {Number} visibility
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.visibility = null;
- if ( !this.element ) {
- var image = this.getImage();
- if (!image) {
+ /**
+ * The transparency indicator of this tile.
+ * @member {Boolean} hasTransparency true if tile contains transparency for correct rendering
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.hasTransparency = false;
+
+ /**
+ * Whether this tile is currently being drawn.
+ * @member {Boolean} beingDrawn
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.beingDrawn = false;
+
+ /**
+ * Timestamp the tile was last touched.
+ * @member {Number} lastTouchTime
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.lastTouchTime = 0;
+
+ /**
+ * Whether this tile is in the right-most column for its level.
+ * @member {Boolean} isRightMost
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.isRightMost = false;
+
+ /**
+ * Whether this tile is in the bottom-most row for its level.
+ * @member {Boolean} isBottomMost
+ * @memberof OpenSeadragon.Tile#
+ */
+ this.isBottomMost = false;
+ };
+
+ /** @lends OpenSeadragon.Tile.prototype */
+ $.Tile.prototype = {
+
+ /**
+ * Provides a string representation of this tiles level and (x,y)
+ * components.
+ * @function
+ * @returns {String}
+ */
+ toString: function() {
+ return this.level + "/" + this.x + "_" + this.y;
+ },
+
+ // private
+ _hasTransparencyChannel: function() {
+ console.warn("Tile.prototype._hasTransparencyChannel() has been " +
+ "deprecated and will be removed in the future. Use TileSource.prototype.hasTransparency() instead.");
+ return !!this.context2D || this.getUrl().match('.png');
+ },
+
+ /**
+ * Renders the tile in an html container.
+ * @function
+ * @param {Element} container
+ */
+ drawHTML: function( container ) {
+ if (!this.cacheImageRecord) {
+ $.console.warn(
+ '[Tile.drawHTML] attempting to draw tile %s when it\'s not cached',
+ this.toString());
return;
}
- this.element = $.makeNeutralElement( "div" );
- this.imgElement = image.cloneNode();
- this.imgElement.style.msInterpolationMode = "nearest-neighbor";
- this.imgElement.style.width = "100%";
- this.imgElement.style.height = "100%";
-
- this.style = this.element.style;
- this.style.position = "absolute";
- }
- if ( this.element.parentNode !== container ) {
- container.appendChild( this.element );
- }
- if ( this.imgElement.parentNode !== this.element ) {
- this.element.appendChild( this.imgElement );
- }
-
- this.style.top = this.position.y + "px";
- this.style.left = this.position.x + "px";
- this.style.height = this.size.y + "px";
- this.style.width = this.size.x + "px";
-
- if (this.flipped) {
- this.style.transform = "scaleX(-1)";
- }
-
- $.setElementOpacity( this.element, this.opacity );
- },
-
- /**
- * The Image object for this tile.
- * @member {Object} image
- * @memberof OpenSeadragon.Tile#
- * @deprecated
- * @returns {Image}
- */
- get image() {
- $.console.error("[Tile.image] property has been deprecated. Use [Tile.prototype.getImage] instead.");
- return this.getImage();
- },
-
- /**
- * The URL of this tile's image.
- * @member {String} url
- * @memberof OpenSeadragon.Tile#
- * @deprecated
- * @returns {String}
- */
- get url() {
- $.console.error("[Tile.url] property has been deprecated. Use [Tile.prototype.getUrl] instead.");
- return this.getUrl();
- },
-
- /**
- * Get the Image object for this tile.
- * @returns {Image}
- */
- getImage: function() {
- return this.cacheImageRecord.getImage();
- },
-
- /**
- * Get the url string for this tile.
- * @returns {String}
- */
- getUrl: function() {
- if (typeof this._url === 'function') {
- return this._url();
- }
-
- return this._url;
- },
-
- /**
- * Get the CanvasRenderingContext2D instance for tile image data drawn
- * onto Canvas if enabled and available
- * @returns {CanvasRenderingContext2D}
- */
- getCanvasContext: function() {
- return this.context2D || this.cacheImageRecord.getRenderedContext();
- },
-
- /**
- * Renders the tile in a canvas-based context.
- * @function
- * @param {Canvas} context
- * @param {Function} drawingHandler - Method for firing the drawing event.
- * drawingHandler({context, tile, rendered})
- * where rendered
is the context with the pre-drawn image.
- * @param {Number} [scale=1] - Apply a scale to position and size
- * @param {OpenSeadragon.Point} [translate] - A translation vector
- * @param {Boolean} [shouldRoundPositionAndSize] - Tells whether to round
- * position and size of tiles supporting alpha channel in non-transparency
- * context.
- * @param {OpenSeadragon.TileSource} source - The source specification of the tile.
- */
- drawCanvas: function( context, drawingHandler, scale, translate, shouldRoundPositionAndSize, source) {
-
- var position = this.position.times($.pixelDensityRatio),
- size = this.size.times($.pixelDensityRatio),
- rendered;
-
- if (!this.context2D && !this.cacheImageRecord) {
- $.console.warn(
- '[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached',
- this.toString());
- return;
- }
-
- rendered = this.getCanvasContext();
-
- if ( !this.loaded || !rendered ){
- $.console.warn(
- "Attempting to draw tile %s when it's not yet loaded.",
- this.toString()
- );
-
- return;
- }
-
- context.save();
- context.globalAlpha = this.opacity;
-
- if (typeof scale === 'number' && scale !== 1) {
- // draw tile at a different scale
- position = position.times(scale);
- size = size.times(scale);
- }
-
- if (translate instanceof $.Point) {
- // shift tile position slightly
- position = position.plus(translate);
- }
-
- //if we are supposed to be rendering fully opaque rectangle,
- //ie its done fading or fading is turned off, and if we are drawing
- //an image with an alpha channel, then the only way
- //to avoid seeing the tile underneath is to clear the rectangle
- if (context.globalAlpha === 1 && this.hasTransparency) {
- if (shouldRoundPositionAndSize) {
- // Round to the nearest whole pixel so we don't get seams from overlap.
- position.x = Math.round(position.x);
- position.y = Math.round(position.y);
- size.x = Math.round(size.x);
- size.y = Math.round(size.y);
+ if ( !this.loaded ) {
+ $.console.warn(
+ "Attempting to draw tile %s when it's not yet loaded.",
+ this.toString()
+ );
+ return;
}
- //clearing only the inside of the rectangle occupied
- //by the png prevents edge flikering
- context.clearRect(
- position.x,
+ //EXPERIMENTAL - trying to figure out how to scale the container
+ // content during animation of the container size.
+
+ if ( !this.element ) {
+ var image = this.getImage();
+ if (!image) {
+ return;
+ }
+
+ this.element = $.makeNeutralElement( "div" );
+ this.imgElement = image.cloneNode();
+ this.imgElement.style.msInterpolationMode = "nearest-neighbor";
+ this.imgElement.style.width = "100%";
+ this.imgElement.style.height = "100%";
+
+ this.style = this.element.style;
+ this.style.position = "absolute";
+ }
+ if ( this.element.parentNode !== container ) {
+ container.appendChild( this.element );
+ }
+ if ( this.imgElement.parentNode !== this.element ) {
+ this.element.appendChild( this.imgElement );
+ }
+
+ this.style.top = this.position.y + "px";
+ this.style.left = this.position.x + "px";
+ this.style.height = this.size.y + "px";
+ this.style.width = this.size.x + "px";
+
+ if (this.flipped) {
+ this.style.transform = "scaleX(-1)";
+ }
+
+ $.setElementOpacity( this.element, this.opacity );
+ },
+
+ /**
+ * The Image object for this tile.
+ * @member {Object} image
+ * @memberof OpenSeadragon.Tile#
+ * @deprecated
+ * @returns {Image}
+ */
+ get image() {
+ $.console.error("[Tile.image] property has been deprecated. Use [Tile.prototype.getImage] instead.");
+ return this.getImage();
+ },
+
+ /**
+ * The URL of this tile's image.
+ * @member {String} url
+ * @memberof OpenSeadragon.Tile#
+ * @deprecated
+ * @returns {String}
+ */
+ get url() {
+ $.console.error("[Tile.url] property has been deprecated. Use [Tile.prototype.getUrl] instead.");
+ return this.getUrl();
+ },
+
+ /**
+ * Get the Image object for this tile.
+ * @returns {Image}
+ */
+ getImage: function() {
+ return this.cacheImageRecord.getImage();
+ },
+
+ /**
+ * Get the url string for this tile.
+ * @returns {String}
+ */
+ getUrl: function() {
+ if (typeof this._url === 'function') {
+ return this._url();
+ }
+
+ return this._url;
+ },
+
+ /**
+ * Get the CanvasRenderingContext2D instance for tile image data drawn
+ * onto Canvas if enabled and available
+ * @returns {CanvasRenderingContext2D}
+ */
+ getCanvasContext: function() {
+ return this.context2D || this.cacheImageRecord.getRenderedContext();
+ },
+
+ /**
+ * Renders the tile in a canvas-based context.
+ * @function
+ * @param {Canvas} context
+ * @param {Function} drawingHandler - Method for firing the drawing event.
+ * drawingHandler({context, tile, rendered})
+ * where rendered
is the context with the pre-drawn image.
+ * @param {Number} [scale=1] - Apply a scale to position and size
+ * @param {OpenSeadragon.Point} [translate] - A translation vector
+ * @param {Boolean} [shouldRoundPositionAndSize] - Tells whether to round
+ * position and size of tiles supporting alpha channel in non-transparency
+ * context.
+ * @param {OpenSeadragon.TileSource} source - The source specification of the tile.
+ */
+ drawCanvas: function( context, drawingHandler, scale, translate, shouldRoundPositionAndSize, source) {
+
+ var position = this.position.times($.pixelDensityRatio),
+ size = this.size.times($.pixelDensityRatio),
+ rendered;
+
+ if (!this.context2D && !this.cacheImageRecord) {
+ $.console.warn(
+ '[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached',
+ this.toString());
+ return;
+ }
+
+ rendered = this.getCanvasContext();
+
+ if ( !this.loaded || !rendered ){
+ $.console.warn(
+ "Attempting to draw tile %s when it's not yet loaded.",
+ this.toString()
+ );
+
+ return;
+ }
+
+ context.save();
+ context.globalAlpha = this.opacity;
+
+ if (typeof scale === 'number' && scale !== 1) {
+ // draw tile at a different scale
+ position = position.times(scale);
+ size = size.times(scale);
+ }
+
+ if (translate instanceof $.Point) {
+ // shift tile position slightly
+ position = position.plus(translate);
+ }
+
+ //if we are supposed to be rendering fully opaque rectangle,
+ //ie its done fading or fading is turned off, and if we are drawing
+ //an image with an alpha channel, then the only way
+ //to avoid seeing the tile underneath is to clear the rectangle
+ if (context.globalAlpha === 1 && this.hasTransparency) {
+ if (shouldRoundPositionAndSize) {
+ // Round to the nearest whole pixel so we don't get seams from overlap.
+ position.x = Math.round(position.x);
+ position.y = Math.round(position.y);
+ size.x = Math.round(size.x);
+ size.y = Math.round(size.y);
+ }
+
+ //clearing only the inside of the rectangle occupied
+ //by the png prevents edge flikering
+ context.clearRect(
+ position.x,
+ position.y,
+ size.x,
+ size.y
+ );
+ }
+
+ // This gives the application a chance to make image manipulation
+ // changes as we are rendering the image
+ drawingHandler({context: context, tile: this, rendered: rendered});
+
+ var sourceWidth, sourceHeight;
+ if (this.sourceBounds) {
+ sourceWidth = Math.min(this.sourceBounds.width, rendered.canvas.width);
+ sourceHeight = Math.min(this.sourceBounds.height, rendered.canvas.height);
+ } else {
+ sourceWidth = rendered.canvas.width;
+ sourceHeight = rendered.canvas.height;
+ }
+
+ context.translate(position.x + size.x / 2, 0);
+ if (this.flipped) {
+ context.scale(-1, 1);
+ }
+ context.drawImage(
+ rendered.canvas,
+ 0,
+ 0,
+ sourceWidth,
+ sourceHeight,
+ -size.x / 2,
position.y,
size.x,
size.y
);
+
+ context.restore();
+ },
+
+ /**
+ * Get the ratio between current and original size.
+ * @function
+ * @returns {Float}
+ */
+ getScaleForEdgeSmoothing: function() {
+ var context;
+ if (this.cacheImageRecord) {
+ context = this.cacheImageRecord.getRenderedContext();
+ } else if (this.context2D) {
+ context = this.context2D;
+ } else {
+ $.console.warn(
+ '[Tile.drawCanvas] attempting to get tile scale %s when tile\'s not cached',
+ this.toString());
+ return 1;
+ }
+ return context.canvas.width / (this.size.x * $.pixelDensityRatio);
+ },
+
+ /**
+ * Get a translation vector that when applied to the tile position produces integer coordinates.
+ * Needed to avoid swimming and twitching.
+ * @function
+ * @param {Number} [scale=1] - Scale to be applied to position.
+ * @returns {OpenSeadragon.Point}
+ */
+ getTranslationForEdgeSmoothing: function(scale, canvasSize, sketchCanvasSize) {
+ // The translation vector must have positive values, otherwise the image goes a bit off
+ // the sketch canvas to the top and left and we must use negative coordinates to repaint it
+ // to the main canvas. In that case, some browsers throw:
+ // INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value.
+ var x = Math.max(1, Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2));
+ var y = Math.max(1, Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2));
+ return new $.Point(x, y).minus(
+ this.position
+ .times($.pixelDensityRatio)
+ .times(scale || 1)
+ .apply(function(x) {
+ return x % 1;
+ })
+ );
+ },
+
+ /**
+ * Removes tile from its container.
+ * @function
+ */
+ unload: function() {
+ if ( this.imgElement && this.imgElement.parentNode ) {
+ this.imgElement.parentNode.removeChild( this.imgElement );
+ }
+ if ( this.element && this.element.parentNode ) {
+ this.element.parentNode.removeChild( this.element );
+ }
+
+ this.element = null;
+ this.imgElement = null;
+ this.loaded = false;
+ this.loading = false;
}
+ };
- // This gives the application a chance to make image manipulation
- // changes as we are rendering the image
- drawingHandler({context: context, tile: this, rendered: rendered});
-
- var sourceWidth, sourceHeight;
- if (this.sourceBounds) {
- sourceWidth = Math.min(this.sourceBounds.width, rendered.canvas.width);
- sourceHeight = Math.min(this.sourceBounds.height, rendered.canvas.height);
- } else {
- sourceWidth = rendered.canvas.width;
- sourceHeight = rendered.canvas.height;
- }
-
- context.translate(position.x + size.x / 2, 0);
- if (this.flipped) {
- context.scale(-1, 1);
- }
- context.drawImage(
- rendered.canvas,
- 0,
- 0,
- sourceWidth,
- sourceHeight,
- -size.x / 2,
- position.y,
- size.x,
- size.y
- );
-
- context.restore();
- },
-
- /**
- * Get the ratio between current and original size.
- * @function
- * @returns {Float}
- */
- getScaleForEdgeSmoothing: function() {
- var context;
- if (this.cacheImageRecord) {
- context = this.cacheImageRecord.getRenderedContext();
- } else if (this.context2D) {
- context = this.context2D;
- } else {
- $.console.warn(
- '[Tile.drawCanvas] attempting to get tile scale %s when tile\'s not cached',
- this.toString());
- return 1;
- }
- return context.canvas.width / (this.size.x * $.pixelDensityRatio);
- },
-
- /**
- * Get a translation vector that when applied to the tile position produces integer coordinates.
- * Needed to avoid swimming and twitching.
- * @function
- * @param {Number} [scale=1] - Scale to be applied to position.
- * @returns {OpenSeadragon.Point}
- */
- getTranslationForEdgeSmoothing: function(scale, canvasSize, sketchCanvasSize) {
- // The translation vector must have positive values, otherwise the image goes a bit off
- // the sketch canvas to the top and left and we must use negative coordinates to repaint it
- // to the main canvas. In that case, some browsers throw:
- // INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value.
- var x = Math.max(1, Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2));
- var y = Math.max(1, Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2));
- return new $.Point(x, y).minus(
- this.position
- .times($.pixelDensityRatio)
- .times(scale || 1)
- .apply(function(x) {
- return x % 1;
- })
- );
- },
-
- /**
- * Removes tile from its container.
- * @function
- */
- unload: function() {
- if ( this.imgElement && this.imgElement.parentNode ) {
- this.imgElement.parentNode.removeChild( this.imgElement );
- }
- if ( this.element && this.element.parentNode ) {
- this.element.parentNode.removeChild( this.element );
- }
-
- this.element = null;
- this.imgElement = null;
- this.loaded = false;
- this.loading = false;
- }
-};
-
-}( OpenSeadragon ));
+ }( OpenSeadragon ));
diff --git a/src/tiledimage.js b/src/tiledimage.js
index 928e135d..ad33bd02 100644
--- a/src/tiledimage.js
+++ b/src/tiledimage.js
@@ -301,6 +301,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
if (xUpdated || yUpdated || scaleUpdated || degreesUpdated) {
this._updateForScale();
+ this._raiseBoundsChange();
this._needsDraw = true;
return true;
}
@@ -407,7 +408,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
var yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y;
var bounds = this.source.getTileBounds(level, xMod, yMod);
if (this.getFlip()) {
- bounds.x = 1 - bounds.x - bounds.width;
+ bounds.x = Math.max(0, 1 - bounds.x - bounds.width);
}
bounds.x += (x - xMod) / numTiles.x;
bounds.y += (this._worldHeightCurrent / this._worldWidthCurrent) * ((y - yMod) / numTiles.y);
@@ -421,6 +422,46 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
return new $.Point(this.source.dimensions.x, this.source.dimensions.y);
},
+ /**
+ * Returns the x position and width of each column and y position and height of each row
+ * @function
+ * @param {Number} level
+ * @returns {Object} Dictionary which defines numRows, numColumns,
+ * dimensions (in pixels), normalizedDimensions (by image width), rowInfo (Array of [x, width]),
+ * and columnInfo (Array of [y, height]) for this level of the image
+ */
+ getGridDefinition: function( level ) {
+ var numTiles = this.source.getNumTiles(level),
+ levelScale = this.source.getLevelScale(level),
+ tileWidth = this.source.getTileWidth(level) / levelScale,
+ tileHeight = this.source.getTileHeight(level) / levelScale,
+ size = this.getContentSize(),
+
+ def = {
+ numRows: numTiles.y,
+ numColumns: numTiles.x,
+ dimensions: size,
+ normalizedDimensions: size.divide(size.x),
+ rowInfo: [],
+ columnInfo: []
+ };
+ var i;
+ for(i = 0; i < numTiles.x; i++){
+ def.columnInfo[i] = {
+ x: i * tileWidth / size.x, // x is defined by regular grid spacing
+ width: (i === (numTiles.x - 1) ? Math.min(size.x - i * tileWidth, size.x) : tileWidth) / size.x, // width is standard except for last column
+ };
+ }
+ for(i = 0; i < numTiles.y; i++){
+ def.rowInfo[i] = {
+ y: i * tileHeight / size.x, // y is defined by regular grid spacing
+ height: (i === (numTiles.y - 1) ? Math.min(size.y - i * tileHeight, size.y) : tileHeight) / size.x, // height is standard except for last row
+ };
+ }
+
+ return def;
+ },
+
/**
* @returns {OpenSeadragon.Point} The TiledImage's content size, in window coordinates.
*/
@@ -1182,8 +1223,10 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
}
// Perform the actual drawing
+
this._drawTiles(this.lastDrawn);
+
// Load the new 'best' tile
if (bestTile && !bestTile.context2D) {
this._loadTile(bestTile, currentTime);
@@ -1656,9 +1699,14 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
*/
_setTileLoaded: function(tile, data, cutoff, tileRequest) {
var increment = 0,
+ eventFinished = false,
_this = this;
function getCompletionCallback() {
+ if (eventFinished) {
+ $.console.error("Event 'tile-loaded' argument getCompletionCallback must be called synchronously. " +
+ "Its return value should be called asynchronously.");
+ }
increment++;
return completionCallback;
}
@@ -1679,6 +1727,24 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
tiledImage: _this
});
}
+ /**
+ * Triggered when a tile has just been loaded in memory. That means that the
+ * image has been downloaded and can be modified before being drawn to the canvas.
+ *
+ * @event tile-ready
+ * @memberof OpenSeadragon.Viewer
+ * @type {object}
+ * @property {*} data image data, the data sent to ImageJob.prototype.finish(), by default an Image object
+ * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile.
+ * @property {OpenSeadragon.Tile} tile - The tile which has been loaded.
+ * @property {XMLHttpRequest} tileRequest - The AJAX request that loaded this tile (if applicable).
+ */
+ _this.viewer.raiseEvent("tile-ready", {
+ tile: tile,
+ tiledImage: _this,
+ tileRequest: tileRequest,
+ data: data
+ });
_this._needsDraw = true;
}
}
@@ -1700,6 +1766,8 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
* marked as entirely loaded when the callback has been called once for each
* call to getCompletionCallback.
*/
+
+ var fallbackCompletion = getCompletionCallback();
this.viewer.raiseEvent("tile-loaded", {
tile: tile,
tiledImage: this,
@@ -1711,8 +1779,9 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
data: data,
getCompletionCallback: getCompletionCallback
});
+ eventFinished = true;
// In case the completion callback is never called, we at least force it once.
- getCompletionCallback()();
+ fallbackCompletion();
},
/**
diff --git a/src/tilesource.js b/src/tilesource.js
index bdebebcc..e1cbd13b 100644
--- a/src/tilesource.js
+++ b/src/tilesource.js
@@ -420,6 +420,41 @@ $.TileSource.prototype = {
return new $.Rect( px * scale, py * scale, sx * scale, sy * scale );
},
+ /**
+ * @function
+ * @param {Number} level
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Boolean} [isSource=false] Whether to return the source bounds of the tile.
+ * @returns {OpenSeadragon.Rect} Either where this tile fits (in normalized coordinates unless imageCoordinates == true) or the
+ * portion of the tile to use as the source of the drawing operation (in pixels), depending on
+ * the isSource parameter, without overlap.
+ */
+ getTileBoundsNoOverlap: function( level, x, y, isSource, imageCoordinates ) {
+ var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ),
+ tileWidth = this.getTileWidth(level),
+ tileHeight = this.getTileHeight(level),
+ tileOverlap = this.tileOverlap || 0,
+ px = tileWidth * x,
+ py = tileHeight * y,
+ sx = tileWidth,
+ sy = tileHeight,
+ scale = 1.0 / dimensionsScaled.x;
+
+ sx = Math.min( sx, dimensionsScaled.x - px );
+ sy = Math.min( sy, dimensionsScaled.y - py );
+
+ if (isSource) {
+ return new $.Rect((x === 0 ? 0 : tileOverlap), (y === 0 ? 0 : tileOverlap), sx, sy);
+ } else if ( imageCoordinates ){
+ return new $.Rect( px, py, sx, sy).times(scale * this.width);
+ } else {
+ return new $.Rect( px, py, sx, sy).times(scale);
+ }
+
+
+ },
+
/**
* Responsible for retrieving, and caching the
diff --git a/test/demo/overlay.html b/test/demo/overlay.html
index 527ebef3..52422af8 100644
--- a/test/demo/overlay.html
+++ b/test/demo/overlay.html
@@ -18,18 +18,34 @@
0deg
+
+
+
+
+
+
+
+
+
+
+