mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-25 06:36:11 +03:00
Move cache creation, image downloading process and transparency deduction to the TileSource instance to allow custom data fetching, caching, processing.
This commit is contained in:
parent
b2eda881e8
commit
4f79f29238
@ -347,15 +347,16 @@ $.Drawer.prototype = {
|
||||
* @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.
|
||||
*/
|
||||
drawTile: function(tile, drawingHandler, useSketch, scale, translate, shouldRoundPositionAndSize) {
|
||||
drawTile: function( tile, drawingHandler, useSketch, scale, translate, shouldRoundPositionAndSize, source) {
|
||||
$.console.assert(tile, '[Drawer.drawTile] tile is required');
|
||||
$.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required');
|
||||
|
||||
if (this.useCanvas) {
|
||||
var context = this._getContext(useSketch);
|
||||
scale = scale || 1;
|
||||
tile.drawCanvas(context, drawingHandler, scale, translate, shouldRoundPositionAndSize);
|
||||
tile.drawCanvas(context, drawingHandler, scale, translate, shouldRoundPositionAndSize, source);
|
||||
} else {
|
||||
tile.drawHTML( this.canvas );
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
* @classdesc Handles downloading of a single image.
|
||||
* @param {Object} options - Options for this ImageJob.
|
||||
* @param {String} [options.src] - URL of image to download.
|
||||
* @param {TileSource} [options.source] - Image loading strategy
|
||||
* @param {String} [options.loadWithAjax] - Whether to load this image with AJAX.
|
||||
* @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX.
|
||||
* @param {String} [options.crossOriginPolicy] - CORS policy to use for downloads
|
||||
@ -58,7 +59,7 @@ function ImageJob (options) {
|
||||
|
||||
/**
|
||||
* Image object which will contain downloaded image.
|
||||
* @member {Image} image
|
||||
* @member {Image|*} image element (default) or other form of image data (depends on TileSource)
|
||||
* @memberof OpenSeadragon.ImageJob#
|
||||
*/
|
||||
this.image = null;
|
||||
@ -71,93 +72,29 @@ ImageJob.prototype = {
|
||||
* Starts the image job.
|
||||
* @method
|
||||
*/
|
||||
start: function(){
|
||||
start: function() {
|
||||
var self = this;
|
||||
var selfAbort = this.abort;
|
||||
|
||||
this.image = new Image();
|
||||
|
||||
this.image.onload = function(){
|
||||
self.finish(true);
|
||||
};
|
||||
this.image.onabort = this.image.onerror = function() {
|
||||
self.errorMsg = "Image load aborted";
|
||||
self.finish(false);
|
||||
};
|
||||
|
||||
this.jobId = window.setTimeout(function(){
|
||||
this.jobId = window.setTimeout(function () {
|
||||
self.errorMsg = "Image load exceeded timeout (" + self.timeout + " ms)";
|
||||
self.finish(false);
|
||||
}, this.timeout);
|
||||
|
||||
// Load the tile with an AJAX request if the loadWithAjax option is
|
||||
// set. Otherwise load the image by setting the source proprety of the image object.
|
||||
if (this.loadWithAjax) {
|
||||
this.request = $.makeAjaxRequest({
|
||||
url: this.src,
|
||||
withCredentials: this.ajaxWithCredentials,
|
||||
headers: this.ajaxHeaders,
|
||||
responseType: "arraybuffer",
|
||||
postData: this.postData,
|
||||
success: function(request) {
|
||||
var blb;
|
||||
// Make the raw data into a blob.
|
||||
// BlobBuilder fallback adapted from
|
||||
// http://stackoverflow.com/questions/15293694/blob-constructor-browser-compatibility
|
||||
try {
|
||||
blb = new window.Blob([request.response]);
|
||||
} catch (e) {
|
||||
var BlobBuilder = (
|
||||
window.BlobBuilder ||
|
||||
window.WebKitBlobBuilder ||
|
||||
window.MozBlobBuilder ||
|
||||
window.MSBlobBuilder
|
||||
);
|
||||
if (e.name === 'TypeError' && BlobBuilder) {
|
||||
var bb = new BlobBuilder();
|
||||
bb.append(request.response);
|
||||
blb = bb.getBlob();
|
||||
}
|
||||
}
|
||||
// If the blob is empty for some reason consider the image load a failure.
|
||||
if (blb.size === 0) {
|
||||
self.errorMsg = "Empty image response.";
|
||||
self.finish(false);
|
||||
}
|
||||
// Create a URL for the blob data and make it the source of the image object.
|
||||
// This will still trigger Image.onload to indicate a successful tile load.
|
||||
var url = (window.URL || window.webkitURL).createObjectURL(blb);
|
||||
self.image.src = url;
|
||||
},
|
||||
error: function(request) {
|
||||
self.errorMsg = "Image load aborted - XHR error: Ajax returned " + request.status;
|
||||
self.finish(false);
|
||||
}
|
||||
});
|
||||
|
||||
// Provide a function to properly abort the request.
|
||||
this.abort = function() {
|
||||
self.request.abort();
|
||||
|
||||
// Call the existing abort function if available
|
||||
if (typeof selfAbort === "function") {
|
||||
selfAbort();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
if (this.crossOriginPolicy !== false) {
|
||||
this.image.crossOrigin = this.crossOriginPolicy;
|
||||
}
|
||||
|
||||
this.image.src = this.src;
|
||||
}
|
||||
this.source.downloadTileStart(this);
|
||||
},
|
||||
|
||||
finish: function(successful) {
|
||||
this.image.onload = this.image.onerror = this.image.onabort = null;
|
||||
if (!successful) {
|
||||
this.image = null;
|
||||
}
|
||||
finish: function(successful, errorMessage) {
|
||||
this.errorMsg = errorMessage;
|
||||
//consider deprecation of .image attribute
|
||||
this.image = this.source.downloadTileFinish(this, successful);
|
||||
|
||||
if (this.jobId) {
|
||||
window.clearTimeout(this.jobId);
|
||||
@ -196,6 +133,7 @@ $.ImageLoader.prototype = {
|
||||
* @method
|
||||
* @param {Object} options - Options for this job.
|
||||
* @param {String} [options.src] - URL of image to download.
|
||||
* @param {TileSource} [options.source] - Image loading strategy
|
||||
* @param {String} [options.loadWithAjax] - Whether to load this image with AJAX.
|
||||
* @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX.
|
||||
* @param {String|Boolean} [options.crossOriginPolicy] - CORS policy to use for downloads
|
||||
@ -213,6 +151,7 @@ $.ImageLoader.prototype = {
|
||||
},
|
||||
jobOptions = {
|
||||
src: options.src,
|
||||
source: options.source,
|
||||
loadWithAjax: options.loadWithAjax,
|
||||
ajaxHeaders: options.loadWithAjax ? options.ajaxHeaders : null,
|
||||
crossOriginPolicy: options.crossOriginPolicy,
|
||||
|
54
src/tile.js
54
src/tile.js
@ -127,18 +127,18 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.ajaxHeaders = ajaxHeaders;
|
||||
/**
|
||||
* The unique cache key for this tile.
|
||||
* @member {String} cacheKey
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
|
||||
if (cacheKey === undefined) {
|
||||
$.console.error("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
|
||||
@ -266,6 +266,8 @@ $.Tile.prototype = {
|
||||
|
||||
// private
|
||||
_hasTransparencyChannel: function() {
|
||||
console.warn("Tile.prototype._hasTransparencyChannel has been " +
|
||||
"deprecated and will be removed in the future.");
|
||||
return !!this.context2D || this.url.match('.png');
|
||||
},
|
||||
|
||||
@ -295,7 +297,7 @@ $.Tile.prototype = {
|
||||
|
||||
if ( !this.element ) {
|
||||
this.element = $.makeNeutralElement( "div" );
|
||||
this.imgElement = this.cacheImageRecord.getImage().cloneNode();
|
||||
this.imgElement = this.imageData();
|
||||
this.imgElement.style.msInterpolationMode = "nearest-neighbor";
|
||||
this.imgElement.style.width = "100%";
|
||||
this.imgElement.style.height = "100%";
|
||||
@ -322,6 +324,26 @@ $.Tile.prototype = {
|
||||
$.setElementOpacity( this.element, this.opacity );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the tile image data as <img> element if
|
||||
* supported
|
||||
*
|
||||
* @return {Image || undefined}
|
||||
*/
|
||||
imageData: function() {
|
||||
return this.image || this.cacheImageRecord.getImage();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the CanvasRenderingContext2D instance for tile image data drawn
|
||||
* onto Canvas if supported
|
||||
*
|
||||
* @return {CanvasRenderingContext2D || undefined}
|
||||
*/
|
||||
canvasContext: function() {
|
||||
return this.context2D || this.cacheImageRecord.getRenderedContext();
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the tile in a canvas-based context.
|
||||
* @function
|
||||
@ -334,12 +356,14 @@ $.Tile.prototype = {
|
||||
* @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 ) {
|
||||
drawCanvas: function( context, drawingHandler, scale, translate, shouldRoundPositionAndSize, source) {
|
||||
|
||||
var position = this.position.times($.pixelDensityRatio),
|
||||
size = this.size.times($.pixelDensityRatio),
|
||||
rendered;
|
||||
rendered,
|
||||
hasTransparency;
|
||||
|
||||
if (!this.context2D && !this.cacheImageRecord) {
|
||||
$.console.warn(
|
||||
@ -348,7 +372,7 @@ $.Tile.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
rendered = this.context2D || this.cacheImageRecord.getRenderedContext();
|
||||
rendered = this.canvasContext();
|
||||
|
||||
if ( !this.loaded || !rendered ){
|
||||
$.console.warn(
|
||||
@ -374,11 +398,19 @@ $.Tile.prototype = {
|
||||
position = position.plus(translate);
|
||||
}
|
||||
|
||||
if (source === undefined) {
|
||||
$.console.warn('[Tile.drawCanvas] deprecated call without argument \'hasTransparency\'.');
|
||||
hasTransparency = context.globalAlpha === 1 && this._hasTransparencyChannel();
|
||||
} else {
|
||||
hasTransparency = context.globalAlpha === 1 &&
|
||||
source.hasTransparency(this.context2D, this.url, this.ajaxHeaders, this.postData);
|
||||
}
|
||||
|
||||
//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._hasTransparencyChannel()) {
|
||||
if (hasTransparency) {
|
||||
if (shouldRoundPositionAndSize) {
|
||||
// Round to the nearest whole pixel so we don't get seams from overlap.
|
||||
position.x = Math.round(position.x);
|
||||
|
@ -45,43 +45,31 @@ var TileRecord = function( options ) {
|
||||
|
||||
// private class
|
||||
var ImageRecord = function(options) {
|
||||
//private scope: changed image -> data
|
||||
$.console.assert( options, "[ImageRecord] options is required" );
|
||||
$.console.assert( options.image, "[ImageRecord] options.image is required" );
|
||||
this._image = options.image;
|
||||
$.console.assert( options.data, "[ImageRecord] options.data is required" );
|
||||
this._tiles = [];
|
||||
|
||||
options.create.apply(null, [this, options.data, options.ownerTile]);
|
||||
this._destroyImplementation = options.destroy.bind(null, this);
|
||||
this.getImage = options.getImage.bind(null, this);
|
||||
this.getData = options.getData.bind(null, this);
|
||||
this.getRenderedContext = options.getRenderedContext.bind(null, this);
|
||||
};
|
||||
|
||||
ImageRecord.prototype = {
|
||||
destroy: function() {
|
||||
this._image = null;
|
||||
this._renderedContext = null;
|
||||
this._destroyImplementation();
|
||||
this._tiles = null;
|
||||
},
|
||||
|
||||
getImage: function() {
|
||||
return this._image;
|
||||
},
|
||||
|
||||
getRenderedContext: function() {
|
||||
if (!this._renderedContext) {
|
||||
var canvas = document.createElement( 'canvas' );
|
||||
canvas.width = this._image.width;
|
||||
canvas.height = this._image.height;
|
||||
this._renderedContext = canvas.getContext('2d');
|
||||
this._renderedContext.drawImage( this._image, 0, 0 );
|
||||
//since we are caching the prerendered image on a canvas
|
||||
//allow the image to not be held in memory
|
||||
this._image = null;
|
||||
}
|
||||
return this._renderedContext;
|
||||
},
|
||||
|
||||
setRenderedContext: function(renderedContext) {
|
||||
$.console.error("ImageRecord.setRenderedContext is deprecated. " +
|
||||
"The rendered context should be created by the ImageRecord " +
|
||||
"itself when calling ImageRecord.getRenderedContext.");
|
||||
this._renderedContext = renderedContext;
|
||||
},
|
||||
// Removed (left as a comment so that it stands out)
|
||||
// setRenderedContext: function(renderedContext) {
|
||||
// $.console.error("ImageRecord.setRenderedContext is deprecated. " +
|
||||
// "The rendered context should be created by the ImageRecord " +
|
||||
// "itself when calling ImageRecord.getRenderedContext.");
|
||||
// this._renderedContext = renderedContext;
|
||||
// },
|
||||
|
||||
addTile: function(tile) {
|
||||
$.console.assert(tile, '[ImageRecord.addTile] tile is required');
|
||||
@ -160,7 +148,13 @@ $.TileCache.prototype = {
|
||||
if (!imageRecord) {
|
||||
$.console.assert( options.image, "[TileCache.cacheTile] options.image is required to create an ImageRecord" );
|
||||
imageRecord = this._imagesLoaded[options.tile.cacheKey] = new ImageRecord({
|
||||
image: options.image
|
||||
data: options.image,
|
||||
ownerTile: options.tile,
|
||||
create: options.tiledImage.source.createTileCache,
|
||||
destroy: options.tiledImage.source.destroyTileCache,
|
||||
getImage: options.tiledImage.source.getTileCacheDataAsImage,
|
||||
getData: options.tiledImage.source.getTileCacheData,
|
||||
getRenderedContext: options.tiledImage.source.getTileCacheDataAsContext2D,
|
||||
});
|
||||
|
||||
this._imagesLoadedCount++;
|
||||
|
@ -1427,8 +1427,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
} else {
|
||||
var imageRecord = this._tileCache.getImageRecord(tile.cacheKey);
|
||||
if (imageRecord) {
|
||||
var image = imageRecord.getImage();
|
||||
this._setTileLoaded(tile, image);
|
||||
this._setTileLoaded(tile, imageRecord.getData());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1571,6 +1570,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
tile.loading = true;
|
||||
this._imageLoader.addJob({
|
||||
src: tile.url,
|
||||
source: this.source,
|
||||
postData: tile.postData,
|
||||
loadWithAjax: tile.loadWithAjax,
|
||||
ajaxHeaders: tile.ajaxHeaders,
|
||||
@ -1649,7 +1649,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
* @private
|
||||
* @inner
|
||||
* @param {OpenSeadragon.Tile} tile
|
||||
* @param {Image || undefined} image
|
||||
* @param {Image|* || undefined} image
|
||||
* @param {Number || undefined} cutoff
|
||||
* @param {XMLHttpRequest || undefined} tileRequest
|
||||
*/
|
||||
@ -1686,7 +1686,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
* @event tile-loaded
|
||||
* @memberof OpenSeadragon.Viewer
|
||||
* @type {object}
|
||||
* @property {Image} image - The image of the tile.
|
||||
* @property {Image|*} image - The image (data) of the tile.
|
||||
* @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).
|
||||
@ -1842,7 +1842,8 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
if (tile) {
|
||||
useSketch = this.opacity < 1 ||
|
||||
(this.compositeOperation && this.compositeOperation !== 'source-over') ||
|
||||
(!this._isBottomItem() && tile._hasTransparencyChannel());
|
||||
(!this._isBottomItem() &&
|
||||
this.source.hasTransparency(tile.context2D, tile.url, tile.ajaxHeaders, tile.postData));
|
||||
}
|
||||
|
||||
var sketchScale;
|
||||
@ -1984,7 +1985,8 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
|
||||
for (var i = lastDrawn.length - 1; i >= 0; i--) {
|
||||
tile = lastDrawn[ i ];
|
||||
this._drawer.drawTile( tile, this._drawingHandler, useSketch, sketchScale, sketchTranslate, shouldRoundPositionAndSize );
|
||||
this._drawer.drawTile( tile, this._drawingHandler, useSketch, sketchScale,
|
||||
sketchTranslate, shouldRoundPositionAndSize, this.source );
|
||||
tile.beingDrawn = true;
|
||||
|
||||
if( this.viewer ){
|
||||
|
@ -709,6 +709,166 @@ $.TileSource.prototype = {
|
||||
y >= 0 &&
|
||||
x < numTiles.x &&
|
||||
y < numTiles.y;
|
||||
},
|
||||
|
||||
/**
|
||||
* Decide whether tiles have transparency: this is crucial for
|
||||
* @return {boolean} true if the image has transparency
|
||||
*/
|
||||
hasTransparency: function(context2D, url, ajaxHeaders, post) {
|
||||
return !!context2D || url.match('.png');
|
||||
},
|
||||
|
||||
/**
|
||||
* Download tile data
|
||||
* @param {object} context job context that you have to call finish(...) on. It also contains abort(...) function
|
||||
* that can be called to abort the job.
|
||||
* @param {String} [context.src] - URL of image to download.
|
||||
* @param {String} [context.loadWithAjax] - Whether to load this image with AJAX.
|
||||
* @param {String} [context.ajaxHeaders] - Headers to add to the image request if using AJAX.
|
||||
* @param {String} [context.crossOriginPolicy] - CORS policy to use for downloads
|
||||
* @param {String} [context.postData] - HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
|
||||
* see TileSrouce::getPostData) or null
|
||||
* @param {Function} [context.callback] - Called once image has been downloaded.
|
||||
* @param {Function} [context.abort] - Called when this image job is aborted.
|
||||
* @param {Number} [context.timeout] - The max number of milliseconds that this image job may take to complete.
|
||||
*/
|
||||
downloadTileStart: function (context) {
|
||||
context.image = new Image();
|
||||
|
||||
context.image.onload = function(){
|
||||
context.finish(true);
|
||||
};
|
||||
context.image.onabort = context.image.onerror = function() {
|
||||
context.finish(false, "Image load aborted");
|
||||
};
|
||||
|
||||
// Load the tile with an AJAX request if the loadWithAjax option is
|
||||
// set. Otherwise load the image by setting the source proprety of the image object.
|
||||
if (context.loadWithAjax) {
|
||||
context.request = $.makeAjaxRequest({
|
||||
url: context.src,
|
||||
withCredentials: context.ajaxWithCredentials,
|
||||
headers: context.ajaxHeaders,
|
||||
responseType: "arraybuffer",
|
||||
postData: context.postData,
|
||||
success: function(request) {
|
||||
var blb;
|
||||
// Make the raw data into a blob.
|
||||
// BlobBuilder fallback adapted from
|
||||
// http://stackoverflow.com/questions/15293694/blob-constructor-browser-compatibility
|
||||
try {
|
||||
blb = new window.Blob([request.response]);
|
||||
} catch (e) {
|
||||
var BlobBuilder = (
|
||||
window.BlobBuilder ||
|
||||
window.WebKitBlobBuilder ||
|
||||
window.MozBlobBuilder ||
|
||||
window.MSBlobBuilder
|
||||
);
|
||||
if (e.name === 'TypeError' && BlobBuilder) {
|
||||
var bb = new BlobBuilder();
|
||||
bb.append(request.response);
|
||||
blb = bb.getBlob();
|
||||
}
|
||||
}
|
||||
// If the blob is empty for some reason consider the image load a failure.
|
||||
if (blb.size === 0) {
|
||||
context.finish(false, "Empty image response.");
|
||||
} else {
|
||||
// Create a URL for the blob data and make it the source of the image object.
|
||||
// This will still trigger Image.onload to indicate a successful tile load.
|
||||
context.image.src = (window.URL || window.webkitURL).createObjectURL(blb);
|
||||
}
|
||||
},
|
||||
error: function(request) {
|
||||
context.finish(false, "Image load aborted - XHR error");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (context.crossOriginPolicy !== false) {
|
||||
context.image.crossOrigin = context.crossOriginPolicy;
|
||||
}
|
||||
|
||||
context.image.src = context.src;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} context job, the same object as with downloadTileStart(..)
|
||||
* @param successful true if successful
|
||||
* @return {null|*} null to indicate missing data or data object
|
||||
* for example, can return default value if the request was unsuccessful such as default error image
|
||||
*/
|
||||
downloadTileFinish: function (context, successful) {
|
||||
if (!context.image) {
|
||||
return null;
|
||||
}
|
||||
context.image.onload = context.image.onerror = context.image.onabort = null;
|
||||
if (!successful) {
|
||||
return null;
|
||||
}
|
||||
return context.image;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create cache object from the result of the download process
|
||||
* @param {Tile} tile instance the cache was created with
|
||||
* @param {object} cacheObject context cache object
|
||||
* @param {*} data the result of downloadTileFinish() function
|
||||
*/
|
||||
createTileCache: function(cacheObject, data, tile) {
|
||||
cacheObject._data = data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Cache object destructor, unset all properties to allow GC collection.
|
||||
* @param {object} cacheObject context cache object
|
||||
*/
|
||||
destroyTileCache: function (cacheObject) {
|
||||
cacheObject._data = null;
|
||||
cacheObject._renderedContext = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Raw data getter
|
||||
* @param {object} cacheObject context cache object
|
||||
* @return {*} cache data
|
||||
*/
|
||||
getTileCacheData: function(cacheObject) {
|
||||
return cacheObject._data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Compatibility image element getter
|
||||
* - plugins might need image representation of the data
|
||||
* - div HTML rendering relies on image element presence
|
||||
* @param {object} cacheObject context cache object
|
||||
* @return {Image} cache data as an Image
|
||||
*/
|
||||
getTileCacheDataAsImage: function(cacheObject) {
|
||||
return cacheObject._data; //the data itself by default is Image
|
||||
},
|
||||
|
||||
/**
|
||||
* Compatibility context 2D getter
|
||||
* - most heavily used rendering method is a canvas-based approach,
|
||||
* convert the data to a canvas and return it's 2D context
|
||||
* @param {object} cacheObject context cache object
|
||||
* @return {CanvasRenderingContext2D} context of the canvas representation of the cache data
|
||||
*/
|
||||
getTileCacheDataAsContext2D: function(cacheObject) {
|
||||
if (!cacheObject._renderedContext) {
|
||||
var canvas = document.createElement( 'canvas' );
|
||||
canvas.width = cacheObject._data.width;
|
||||
canvas.height = cacheObject._data.height;
|
||||
cacheObject._renderedContext = canvas.getContext('2d');
|
||||
cacheObject._renderedContext.drawImage( cacheObject._data, 0, 0 );
|
||||
//since we are caching the prerendered image on a canvas
|
||||
//allow the image to not be held in memory
|
||||
cacheObject._data = null;
|
||||
}
|
||||
return cacheObject._renderedContext;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,35 @@
|
||||
|
||||
(function() {
|
||||
|
||||
var tileSourceCacheAPI = {
|
||||
createTileCache: function(cacheObject, data, tile) {
|
||||
cacheObject._data = data;
|
||||
},
|
||||
destroyTileCache: function (cacheObject) {
|
||||
cacheObject._data = null;
|
||||
cacheObject._renderedContext = null;
|
||||
},
|
||||
getTileCacheData: function(cacheObject) {
|
||||
return cacheObject._data;
|
||||
},
|
||||
getTileCacheDataAsImage: function(cacheObject) {
|
||||
return cacheObject._data; //the data itself by default is Image
|
||||
},
|
||||
getTileCacheDataAsContext2D: function(cacheObject) {
|
||||
if (!cacheObject._renderedContext) {
|
||||
var canvas = document.createElement( 'canvas' );
|
||||
canvas.width = cacheObject._data.width;
|
||||
canvas.height = cacheObject._data.height;
|
||||
cacheObject._renderedContext = canvas.getContext('2d');
|
||||
cacheObject._renderedContext.drawImage( cacheObject._data, 0, 0 );
|
||||
//since we are caching the prerendered image on a canvas
|
||||
//allow the image to not be held in memory
|
||||
cacheObject._data = null;
|
||||
}
|
||||
return cacheObject._renderedContext;
|
||||
}
|
||||
};
|
||||
|
||||
// ----------
|
||||
QUnit.module('TileCache', {
|
||||
beforeEach: function () {
|
||||
@ -19,10 +48,12 @@
|
||||
raiseEvent: function() {}
|
||||
};
|
||||
var fakeTiledImage0 = {
|
||||
viewer: fakeViewer
|
||||
viewer: fakeViewer,
|
||||
source: tileSourceCacheAPI
|
||||
};
|
||||
var fakeTiledImage1 = {
|
||||
viewer: fakeViewer
|
||||
viewer: fakeViewer,
|
||||
source: tileSourceCacheAPI
|
||||
};
|
||||
|
||||
var fakeTile0 = {
|
||||
@ -74,7 +105,8 @@
|
||||
raiseEvent: function() {}
|
||||
};
|
||||
var fakeTiledImage0 = {
|
||||
viewer: fakeViewer
|
||||
viewer: fakeViewer,
|
||||
source: tileSourceCacheAPI
|
||||
};
|
||||
|
||||
var fakeTile0 = {
|
||||
|
Loading…
Reference in New Issue
Block a user