diff --git a/src/imageloader.js b/src/imageloader.js index 91d33b50..365c5c79 100644 --- a/src/imageloader.js +++ b/src/imageloader.js @@ -50,12 +50,14 @@ * @param {Function} [options.callback] - Called once image has been downloaded. * @param {Function} [options.abort] - Called when this image job is aborted. * @param {Number} [options.timeout] - The max number of milliseconds that this image job may take to complete. + * @param {Number} [options.tries] - Actual number of the current try. */ $.ImageJob = function(options) { $.extend(true, this, { timeout: $.DEFAULT_SETTINGS.timeout, - jobId: null + jobId: null, + tries: 0 }, options); /** @@ -87,6 +89,8 @@ $.ImageJob.prototype = { * @method */ start: function() { + this.tries++; + var self = this; var selfAbort = this.abort; @@ -138,6 +142,7 @@ $.ImageLoader = function(options) { jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit, timeout: $.DEFAULT_SETTINGS.timeout, jobQueue: [], + failedTiles: [], jobsInProgress: 0 }, options); @@ -220,7 +225,8 @@ $.ImageLoader.prototype = { }; /** - * Cleans up ImageJob once completed. + * Cleans up ImageJob once completed. Restarts job after tileRetryDelay seconds if failed + * but max tileRetryMax times * @method * @private * @param loader - ImageLoader used to start job. @@ -228,6 +234,9 @@ $.ImageLoader.prototype = { * @param callback - Called once cleanup is finished. */ function completeJob(loader, job, callback) { + if (job.errorMsg !== '' && (job.image === null || job.image === undefined) && job.tries < 1 + loader.tileRetryMax) { + loader.failedTiles.push(job); + } var nextJob; loader.jobsInProgress--; @@ -238,6 +247,16 @@ function completeJob(loader, job, callback) { loader.jobsInProgress++; } + if (loader.tileRetryMax > 0 && loader.jobQueue.length === 0) { + if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.failedTiles.length > 0) { + nextJob = loader.failedTiles.shift(); + setTimeout(function () { + nextJob.start(); + }, loader.tileRetryDelay); + loader.jobsInProgress++; + } + } + callback(job.data, job.errorMsg, job.request); } diff --git a/src/openseadragon.js b/src/openseadragon.js index cb111195..f10769ae 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -495,6 +495,12 @@ * @property {Number} [timeout=30000] * The max number of milliseconds that an image job may take to complete. * + * @property {Number} [tileRetryMax=0] + * The max number of retries when a tile download fails. By default it's 0, so retries are disabled. + * + * @property {Number} [tileRetryDelay=2500] + * Milliseconds to wait after each tile retry if tileRetryMax is set. + * * @property {Boolean} [useCanvas=true] * Set to false to not use an HTML canvas element for image rendering even if canvas is supported. * @@ -1355,6 +1361,8 @@ function OpenSeadragon( options ){ maxImageCacheCount: 200, timeout: 30000, useCanvas: true, // Use canvas element for drawing if available + tileRetryMax: 0, + tileRetryDelay: 2500, //INTERFACE RESOURCE SETTINGS prefixUrl: "/images/", diff --git a/src/viewer.js b/src/viewer.js index 33f5d22d..9107a329 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -406,7 +406,9 @@ $.Viewer = function( options ) { // Create the image loader this.imageLoader = new $.ImageLoader({ jobLimit: this.imageLoaderLimit, - timeout: options.timeout + timeout: options.timeout, + tileRetryMax: this.tileRetryMax, + tileRetryDelay: this.tileRetryDelay }); // Create the tile cache