mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-21 20:56:09 +03:00
Merge pull request #2247 from JohnReagan/1970/support-tile-source-url-getter
Add support for dynamic urls from tile source. Fixes #1970
This commit is contained in:
commit
eb85b4498f
36
src/tile.js
36
src/tile.js
@ -44,7 +44,7 @@
|
||||
* coordinates.
|
||||
* @param {Boolean} exists Is this tile a part of a sparse image? ( Also has
|
||||
* this tile failed to load? )
|
||||
* @param {String} url The URL of this tile's image.
|
||||
* @param {String|() => String} 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 .
|
||||
@ -95,11 +95,13 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
|
||||
*/
|
||||
this.exists = exists;
|
||||
/**
|
||||
* The URL of this tile's image.
|
||||
* @member {String} url
|
||||
* Private property to hold string url or url retriever function.
|
||||
* Consumers should access via Tile.getUrl()
|
||||
* @private
|
||||
* @member {String|() => String} url
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.url = url;
|
||||
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
|
||||
@ -269,7 +271,7 @@ $.Tile.prototype = {
|
||||
_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.url.match('.png');
|
||||
return !!this.context2D || this.getUrl().match('.png');
|
||||
},
|
||||
|
||||
/**
|
||||
@ -342,6 +344,18 @@ $.Tile.prototype = {
|
||||
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}
|
||||
@ -350,6 +364,18 @@ $.Tile.prototype = {
|
||||
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
|
||||
|
@ -1480,7 +1480,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
bounds,
|
||||
sourceBounds,
|
||||
exists,
|
||||
url,
|
||||
urlOrGetter,
|
||||
post,
|
||||
ajaxHeaders,
|
||||
context2D,
|
||||
@ -1501,7 +1501,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
bounds = this.getTileBounds( level, x, y );
|
||||
sourceBounds = tileSource.getTileBounds( level, xMod, yMod, true );
|
||||
exists = tileSource.tileExists( level, xMod, yMod );
|
||||
url = tileSource.getTileUrl( level, xMod, yMod );
|
||||
urlOrGetter = tileSource.getTileUrl( level, xMod, yMod );
|
||||
post = tileSource.getTilePostData( level, xMod, yMod );
|
||||
|
||||
// Headers are only applicable if loadTilesWithAjax is set
|
||||
@ -1524,13 +1524,13 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
y,
|
||||
bounds,
|
||||
exists,
|
||||
url,
|
||||
urlOrGetter,
|
||||
context2D,
|
||||
this.loadTilesWithAjax,
|
||||
ajaxHeaders,
|
||||
sourceBounds,
|
||||
post,
|
||||
tileSource.getTileHashKey(level, xMod, yMod, url, ajaxHeaders, post)
|
||||
tileSource.getTileHashKey(level, xMod, yMod, urlOrGetter, ajaxHeaders, post)
|
||||
);
|
||||
|
||||
if (this.getFlip()) {
|
||||
@ -1569,7 +1569,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
var _this = this;
|
||||
tile.loading = true;
|
||||
this._imageLoader.addJob({
|
||||
src: tile.url,
|
||||
src: tile.getUrl(),
|
||||
tile: tile,
|
||||
source: this.source,
|
||||
postData: tile.postData,
|
||||
@ -1598,7 +1598,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
*/
|
||||
_onTileLoad: function( tile, time, data, errorMsg, tileRequest ) {
|
||||
if ( !data ) {
|
||||
$.console.error( "Tile %s failed to load: %s - error: %s", tile, tile.url, errorMsg );
|
||||
$.console.error( "Tile %s failed to load: %s - error: %s", tile, tile.getUrl(), errorMsg );
|
||||
/**
|
||||
* Triggered when a tile fails to load.
|
||||
*
|
||||
@ -1624,7 +1624,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
}
|
||||
|
||||
if ( time < this.lastResetTime ) {
|
||||
$.console.warn( "Ignoring tile %s loaded before reset: %s", tile, tile.url );
|
||||
$.console.warn( "Ignoring tile %s loaded before reset: %s", tile, tile.getUrl() );
|
||||
tile.loading = false;
|
||||
return;
|
||||
}
|
||||
@ -1669,7 +1669,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
tile.loading = false;
|
||||
tile.loaded = true;
|
||||
tile.hasTransparency = _this.source.hasTransparency(
|
||||
tile.context2D, tile.url, tile.ajaxHeaders, tile.postData
|
||||
tile.context2D, tile.getUrl(), tile.ajaxHeaders, tile.postData
|
||||
);
|
||||
if (!tile.context2D) {
|
||||
_this._tileCache.cacheTile({
|
||||
@ -1852,7 +1852,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
useSketch = this.opacity < 1 ||
|
||||
(this.compositeOperation && this.compositeOperation !== 'source-over') ||
|
||||
(!this._isBottomItem() &&
|
||||
this.source.hasTransparency(tile.context2D, tile.url, tile.ajaxHeaders, tile.postData));
|
||||
this.source.hasTransparency(tile.context2D, tile.getUrl(), tile.ajaxHeaders, tile.postData));
|
||||
}
|
||||
|
||||
var sketchScale;
|
||||
|
@ -618,6 +618,7 @@ $.TileSource.prototype = {
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @returns {String|() => string} url - A string for the url or a function that returns a url string.
|
||||
* @throws {Error}
|
||||
*/
|
||||
getTileUrl: function( level, x, y ) {
|
||||
|
199
test/modules/tilesource-dynamic-url.js
Normal file
199
test/modules/tilesource-dynamic-url.js
Normal file
@ -0,0 +1,199 @@
|
||||
/* global QUnit, testLog, Util */
|
||||
|
||||
//Testing of TileSource with getTileUrl that returns a function
|
||||
|
||||
(function() {
|
||||
var ASSERT = null;
|
||||
var DYNAMIC_URL = "";
|
||||
var viewer = null;
|
||||
var OriginalAjax = OpenSeadragon.makeAjaxRequest;
|
||||
var OriginalTile = OpenSeadragon.Tile;
|
||||
// These variables allow tracking when the first request for data has finished
|
||||
var firstUrlPromise = null;
|
||||
var isFirstUrlPromiseResolved = false;
|
||||
var firstUrlPromiseResolver = null;
|
||||
|
||||
/**
|
||||
* Set up shared variables for test
|
||||
*/
|
||||
var configure = function(assert, url) {
|
||||
ASSERT = assert;
|
||||
DYNAMIC_URL = url;
|
||||
firstUrlPromise = new Promise(resolve => {
|
||||
firstUrlPromiseResolver = () => {
|
||||
isFirstUrlPromiseResolved = true;
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
QUnit.module('TileSourceDynamicUrl', {
|
||||
beforeEach: function () {
|
||||
testLog.reset();
|
||||
$("#qunit-fixture").html("<div id='example'></div>");
|
||||
|
||||
// Add test tile source to OSD
|
||||
OpenSeadragon.DynamicUrlTestTileSource = function(options) {
|
||||
OpenSeadragon.TileSource.apply(this, [options]);
|
||||
};
|
||||
|
||||
OpenSeadragon.extend( OpenSeadragon.DynamicUrlTestTileSource.prototype, OpenSeadragon.TileSource.prototype, {
|
||||
supports: function(_data, url){
|
||||
return url.indexOf('dynamic') !== -1;
|
||||
},
|
||||
|
||||
configure: function(_data, url, postData){
|
||||
//some default data to trigger painting
|
||||
return {
|
||||
postData: postData,
|
||||
tilesUrl: url,
|
||||
fileFormat: "jpg",
|
||||
sizeData: {Width: 55, Height: 55},
|
||||
width: 55,
|
||||
height: 55,
|
||||
tileSize: 55,
|
||||
tileOverlap: 55,
|
||||
minLevel: 1,
|
||||
maxLevel: 1,
|
||||
displayRects: []
|
||||
};
|
||||
},
|
||||
|
||||
// getTileUrl return a function that must be called by Tile.getUrl
|
||||
getTileUrl: function(_level, _x, _y) {
|
||||
// Assert that custom tile source is called correctly
|
||||
ASSERT.ok(true, 'DynamicUrlTileSource.getTileUrl called');
|
||||
return () => DYNAMIC_URL;
|
||||
},
|
||||
|
||||
tileExists: function (_level, _x, _y) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
var hasCompletedImageInfoRequest = false;
|
||||
OpenSeadragon.makeAjaxRequest = function(url, onSuccess, onError) {
|
||||
// Note that our preferred API is that you pass in a single object; the named
|
||||
// arguments are for legacy support.
|
||||
if( $.isPlainObject(url)){
|
||||
onSuccess = url.success;
|
||||
onError = url.error;
|
||||
withCredentials = url.withCredentials;
|
||||
headers = url.headers;
|
||||
responseType = url.responseType || null;
|
||||
postData = url.postData || null;
|
||||
options = url; //save original stuff
|
||||
url = url.url;
|
||||
}
|
||||
|
||||
//first AJAX firing is the image info getter, second is the first tile request: can exit
|
||||
if (hasCompletedImageInfoRequest) {
|
||||
// Assert dynamic url from tileSource is called
|
||||
ASSERT.equal(url, DYNAMIC_URL, 'Called dynamic url correctly: ' + DYNAMIC_URL);
|
||||
// If we've only queried for one url, resolve that promise to set up second query
|
||||
// Otherwise close viewer
|
||||
if (isFirstUrlPromiseResolved) {
|
||||
viewer.close();
|
||||
} else {
|
||||
firstUrlPromiseResolver();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
hasCompletedImageInfoRequest = true;
|
||||
|
||||
var request = Promise.resolve(url);
|
||||
//some required properties to pass through processResponse(...)
|
||||
request.responseText = "some text";
|
||||
request.status = 200;
|
||||
|
||||
onSuccess(request);
|
||||
return request;
|
||||
};
|
||||
|
||||
// Override Tile to ensure getUrl is called successfully.
|
||||
var Tile = function(...params) {
|
||||
OriginalTile.apply(this, params);
|
||||
};
|
||||
|
||||
OpenSeadragon.extend( Tile.prototype, OpenSeadragon.Tile.prototype, {
|
||||
getUrl: function() {
|
||||
ASSERT.ok(true, 'Tile.getUrl called');
|
||||
return OriginalTile.prototype.getUrl.apply(this);
|
||||
}
|
||||
});
|
||||
OpenSeadragon.Tile = Tile;
|
||||
},
|
||||
|
||||
afterEach: function () {
|
||||
ASSERT = null;
|
||||
|
||||
if (viewer && viewer.close) {
|
||||
viewer.close();
|
||||
}
|
||||
viewer = null;
|
||||
|
||||
OpenSeadragon.makeAjaxRequest = OriginalAjax;
|
||||
OpenSeadragon.Tile = OriginalTile;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Create viewer for test
|
||||
*/
|
||||
var testUrlCall = function(tileSourceUrl) {
|
||||
var timeWatcher = Util.timeWatcher(ASSERT, 7000);
|
||||
|
||||
viewer = OpenSeadragon({
|
||||
id: 'example',
|
||||
prefixUrl: '/build/openseadragon/images/',
|
||||
tileSources: tileSourceUrl,
|
||||
loadTilesWithAjax: true,
|
||||
});
|
||||
|
||||
var failHandler = function (event) {
|
||||
testPostData(event.postData, "event: 'open-failed'");
|
||||
viewer.removeHandler('open-failed', failHandler);
|
||||
viewer.close();
|
||||
};
|
||||
viewer.addHandler('open-failed', failHandler);
|
||||
|
||||
var readyHandler = function (event) {
|
||||
//relies on Tilesource contructor extending itself with options object
|
||||
testPostData(event.postData, "event: 'ready'");
|
||||
viewer.removeHandler('ready', readyHandler);
|
||||
};
|
||||
viewer.addHandler('ready', readyHandler);
|
||||
|
||||
|
||||
var openHandler = function(_event) {
|
||||
viewer.removeHandler('open', openHandler);
|
||||
ASSERT.ok(true, 'Open event was sent');
|
||||
viewer.addHandler('close', closeHandler);
|
||||
viewer.world.draw();
|
||||
};
|
||||
|
||||
var closeHandler = function(_event) {
|
||||
viewer.removeHandler('close', closeHandler);
|
||||
$('#example').empty();
|
||||
ASSERT.ok(true, 'Close event was sent');
|
||||
timeWatcher.done();
|
||||
};
|
||||
viewer.addHandler('open', openHandler);
|
||||
|
||||
return viewer;
|
||||
};
|
||||
|
||||
// ----------
|
||||
QUnit.test('TileSource.getTileUrl supports returning a function', function(assert) {
|
||||
configure(assert, 'dynamicUrl');
|
||||
const viewer = testUrlCall('dynamicUrl');
|
||||
firstUrlPromise.then(() => {
|
||||
// after querying with first dynamic url, update the url and trigger new request
|
||||
DYNAMIC_URL = 'dyanmicUrl2';
|
||||
delete viewer.world.getItemAt(0).tilesMatrix[1][0][0];
|
||||
})
|
||||
});
|
||||
})();
|
@ -47,6 +47,7 @@
|
||||
<script src="/test/modules/ajax-tiles.js"></script>
|
||||
<script src="/test/modules/ajax-post-data.js"></script>
|
||||
<script src="/test/modules/imageloader.js"></script>
|
||||
<script src="/test/modules/tilesource-dynamic-url.js"></script>
|
||||
<!--The navigator tests are the slowest (for now; hopefully they can be sped up)
|
||||
so we put them last. -->
|
||||
<script src="/test/modules/navigator.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user