Fix docs, commit before upstream merge.

This commit is contained in:
Aiosa 2024-03-03 14:50:01 +01:00
parent 63f0adbc15
commit 360f0d6796
7 changed files with 107 additions and 54 deletions

View File

@ -48,7 +48,7 @@
* @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX requests.
* @param {String} [options.crossOriginPolicy] - CORS policy to use for downloads
* @param {String} [options.postData] - HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getPostData) or null
* see TileSource::getTilePostData) or null
* @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.
@ -193,7 +193,7 @@ $.ImageLoader.prototype = {
* @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
* @param {String} [options.postData] - POST parameters (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getPostData) or null
* see TileSource::getTilePostData) or null
* @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX
* requests.
* @param {Function} [options.callback] - Called once image has been downloaded.

View File

@ -2383,7 +2383,7 @@ function OpenSeadragon( options ){
* @param {Object} options.headers - headers to add to the AJAX request
* @param {String} options.responseType - the response type of the AJAX request
* @param {String} options.postData - HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getPostData), GET method used if null
* see TileSource::getTilePostData), GET method used if null
* @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials
* @throws {Error}
* @returns {XMLHttpRequest}
@ -2697,7 +2697,7 @@ function OpenSeadragon( options ){
//@private, runs tile update event
invalidateTile: function(tile, image, tStamp, viewer, i = -1) {
console.log(i, "tile: process", tile);
//console.log(i, "tile: process", tile);
//todo consider also ability to cut execution of ongoing event if outdated by providing comparison timestamp
viewer.raiseEventAwaiting('tile-needs-update', {

View File

@ -53,7 +53,7 @@
* 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
* see TileSource::getTilePostData) 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) {
@ -112,7 +112,7 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
* 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
* see TileSource::getTilePostData) or null
* @memberof OpenSeadragon.Tile#
*/
this.postData = postData;
@ -300,14 +300,15 @@ $.Tile.prototype = {
return this._cKey;
},
set cacheKey(value) {
if (this._cKey !== value) {
let ref = this._caches[this._cKey];
if (ref) {
// make sure we free drawer internal cache
ref.destroyInternalCache();
if (value === this.cacheKey) {
return;
}
this._cKey = value;
const cache = this.getCache(value);
if (!cache) {
// It's better to first set cache, then change the key to existing one. Warn if otherwise.
$.console.warn("[Tile.cacheKey] should not be set manually. Use addCache() with setAsMain=true.");
}
this._updateMainCacheKey(value);
},
/**
@ -431,11 +432,19 @@ $.Tile.prototype = {
$.console.error("[Tile.cacheImageRecord] property has been deprecated. Use Tile::addCache.");
const cache = this._caches[this.cacheKey];
if (!value) {
if (cache) {
this.removeCache(this.cacheKey);
}
if (value) {
// Note: the value's data is probably not preserved - if a cacheKey cache exists, it will ignore
// data - it would have to call setData(...)
// TODO: call setData() ?
if (value.loaded) {
this.addCache(this.cacheKey, value.data, value.type, true, false);
} else {
const _this = this;
cache.await().then(x => _this.addCache(this.cacheKey, x, cache.type, false));
value.await().then(x => this.addCache(this.cacheKey, x, value.type, true, false));
}
}
},
@ -492,11 +501,8 @@ $.Tile.prototype = {
if (preserveOriginalData && this.cacheKey === this.originalCacheKey) {
//caches equality means we have only one cache:
// change current pointer to a new cache and create it: new tiles will
// not arrive at this data, but at originalCacheKey state
// todo setting cache key makes the notification trigger ensure we do not do unnecessary stuff
this.cacheKey = "mod://" + this.originalCacheKey;
return this.addCache(this.cacheKey, value, type)._promise;
// create new cache record with main cache key changed to 'mod'
return this.addCache("mod://" + this.originalCacheKey, value, type, true)._promise;
}
//else overwrite cache
const cache = this.getCache(this.cacheKey);
@ -512,7 +518,7 @@ $.Tile.prototype = {
* @param {string} [key=this.cacheKey] cache key to read that belongs to this tile
* @return {OpenSeadragon.CacheRecord}
*/
getCache: function(key = this.cacheKey) {
getCache: function(key = this._cKey) {
const cache = this._caches[key];
if (cache) {
cache.withTileReference(this);
@ -526,20 +532,21 @@ $.Tile.prototype = {
* value and extend it with some another unique content, by default overrides the existing
* main cache used for drawing, if not existing.
* @param {*} data data to cache - this data will be IGNORED if cache already exists!
* @param {?string} type data type, will be guessed if not provided
* @param {string} [type=undefined] data type, will be guessed if not provided
* @param {boolean} [setAsMain=false] if true, the key will be set as the tile.cacheKey
* @param [_safely=true] private
* @returns {OpenSeadragon.CacheRecord|null} - The cache record the tile was attached to.
*/
addCache: function(key, data, type = undefined, _safely = true) {
addCache: function(key, data, type = undefined, setAsMain = false, _safely = true) {
if (!this.tiledImage) {
return null; //async can access outside its lifetime
}
if (!type) {
if (!this.tiledImage.__typeWarningReported) {
if (!this.__typeWarningReported) {
$.console.warn(this, "[Tile.addCache] called without type specification. " +
"Automated deduction is potentially unsafe: prefer specification of data type explicitly.");
this.tiledImage.__typeWarningReported = true;
this.__typeWarningReported = true;
}
type = $.convertor.guessType(data);
}
@ -568,9 +575,31 @@ $.Tile.prototype = {
}
this._caches[key] = cachedItem;
}
// Update cache key if differs and main requested
if (!writesToRenderingCache && setAsMain) {
this._updateMainCacheKey(key);
}
return cachedItem;
},
/**
* Sets the main cache key for this tile and
* performs necessary updates
* @param value
* @private
*/
_updateMainCacheKey: function(value) {
let ref = this._caches[this._cKey];
if (ref) {
// make sure we free drawer internal cache
ref.destroyInternalCache();
}
this._cKey = value;
// when key changes the image probably needs re-render
this.tiledImage.redraw();
},
/**
* Get the number of caches available to this tile
* @returns {number} number of caches
@ -585,11 +614,32 @@ $.Tile.prototype = {
* @param {boolean} [freeIfUnused=true] set to false if zombie should be created
*/
removeCache: function(key, freeIfUnused = true) {
if (this.cacheKey === key) {
if (this.cacheKey !== this.originalCacheKey) {
this.cacheKey = this.originalCacheKey;
if (!this._caches[key]) {
// try to erase anyway in case the cache got stuck in memory
this.tiledImage._tileCache.unloadCacheForTile(this, key, freeIfUnused);
return;
}
const currentMainKey = this.cacheKey,
originalDataKey = this.originalCacheKey,
sameBuiltinKeys = currentMainKey === originalDataKey;
if (!sameBuiltinKeys && originalDataKey === key) {
$.console.warn("[Tile.removeCache] original data must not be manually deleted: other parts of the code might rely on it!",
"If you want the tile not to preserve the original data, toggle of data perseverance in tile.setData().");
return;
}
if (currentMainKey === key) {
if (!sameBuiltinKeys && this._caches[originalDataKey]) {
// if we have original data let's revert back
// TODO consider calling drawer.getDataToDraw(...)
// or even better, first ensure the data is compatible and then update...?
this._updateMainCacheKey(originalDataKey);
} else {
$.console.warn("[Tile.removeCache] trying to remove the only cache that is used to draw the tile!");
$.console.warn("[Tile.removeCache] trying to remove the only cache that can be used to draw the tile!",
"If you want to remove the main cache, first set different cache as main with tile.addCache()");
return;
}
}
if (this.tiledImage._tileCache.unloadCacheForTile(this, key, freeIfUnused)) {

View File

@ -106,7 +106,7 @@
*/
setDataAs(data, type) {
//allow set data with destroyed state, destroys the data if necessary
$.console.assert(data !== undefined, "[CacheRecord.setDataAs] needs valid data to set!");
$.console.assert(data !== undefined && data !== null, "[CacheRecord.setDataAs] needs valid data to set!");
if (this._conversionJobQueue) {
//delay saving if ongiong conversion, these were registered first
let resolver = null;
@ -412,7 +412,7 @@
_triggerNeedsDraw() {
for (let tile of this._tiles) {
tile.tiledImage._needsDraw = true;
tile.tiledImage.redraw();
}
}

View File

@ -2095,14 +2095,9 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
* @param {?Boolean} [withEvent=true] do not trigger event if true
*/
_setTileLoaded: function(tile, data, cutoff, tileRequest, dataType, withEvent = true) {
const originalDelete = tile.unload;
tile.unload = (function () {
throw `Cannot unload tile while being loaded!`;
});
tile.tiledImage = this; //unloaded with tile.unload(), so we need to set it back
// does nothing if tile.cacheKey already present
tile.addCache(tile.cacheKey, data, dataType, false);
tile.addCache(tile.cacheKey, data, dataType, false, false);
let resolver = null,
increment = 0,
@ -2135,13 +2130,11 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
}
return cacheRef;
}).then(_ => {
tile.unload = originalDelete;
tile.loading = false;
tile.loaded = true;
resolver(tile);
});
} else {
tile.unload = originalDelete;
tile.loading = false;
tile.loaded = true;
resolver(tile);

View File

@ -55,7 +55,8 @@
* @param {Object} options
* You can either specify a URL, or literally define the TileSource (by specifying
* width, height, tileSize, tileOverlap, minLevel, and maxLevel). For the former,
* the extending class is expected to implement 'getImageInfo' and 'configure'.
* the extending class is expected to implement 'supports' and 'configure'.
* Note that _in this case, the child class of getImageInfo() is ignored!_
* For the latter, the construction is assumed to occur through
* the extending classes implementation of 'configure'.
* @param {String} [options.url]
@ -72,6 +73,7 @@
* @param {Boolean} [options.splitHashDataForPost]
* First occurrence of '#' in the options.url is used to split URL
* and the latter part is treated as POST data (applies to getImageInfo(...))
* Does not work if getImageInfo() is overridden and used (see the options description)
* @param {Number} [options.width]
* Width of the source image at max resolution in pixels.
* @param {Number} [options.height]
@ -176,6 +178,8 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
* @memberof OpenSeadragon.TileSource#
*/
// TODO potentially buggy behavior: what if .url is used by child class before it calls super constructor?
// this can happen if old JS class definition is used
if( 'string' === $.type( arguments[ 0 ] ) ){
this.url = arguments[0];
}
@ -431,6 +435,12 @@ $.TileSource.prototype = {
/**
* Responsible for retrieving, and caching the
* image metadata pertinent to this TileSources implementation.
* There are three scenarios of opening a tile source:
* 1) if it is a string parseable as XML or JSON, the string is converted to an object
* 2) if it is a string, then
* internally, this method
* else
*
* @function
* @param {String} url
* @throws {Error}
@ -560,7 +570,7 @@ $.TileSource.prototype = {
* @property {String} message
* @property {String} source
* @property {String} postData - HTTP POST data (usually but not necessarily in k=v&k2=v2... form,
* see TileSource::getPostData) or null
* see TileSource::getTilePostData) or null
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
_this.raiseEvent( 'open-failed', {
@ -777,7 +787,7 @@ $.TileSource.prototype = {
* @param {Boolean} [context.ajaxWithCredentials] - Whether to set withCredentials on AJAX requests.
* @param {String} [context.crossOriginPolicy] - CORS policy to use for downloads
* @param {?String|?Object} [context.postData] - HTTP POST data (usually but not necessarily
* in k=v&k2=v2... form, see TileSource::getPostData) or null
* in k=v&k2=v2... form, see TileSource::getTilePostData) or null
* @param {*} [context.userData] - Empty object to attach your own data and helper variables to.
* @param {Function} [context.finish] - Should be called unless abort() was executed upon successful
* data retrieval.

View File

@ -252,15 +252,15 @@
//load data
const tile00 = createFakeTile('foo.jpg', fakeTiledImage0);
tile00.addCache(tile00.cacheKey, 0, T_A, false);
tile00.addCache(tile00.cacheKey, 0, T_A, false, false);
const tile01 = createFakeTile('foo2.jpg', fakeTiledImage0);
tile01.addCache(tile01.cacheKey, 0, T_B, false);
tile01.addCache(tile01.cacheKey, 0, T_B, false, false);
const tile10 = createFakeTile('foo3.jpg', fakeTiledImage1);
tile10.addCache(tile10.cacheKey, 0, T_C, false);
tile10.addCache(tile10.cacheKey, 0, T_C, false, false);
const tile11 = createFakeTile('foo3.jpg', fakeTiledImage1);
tile11.addCache(tile11.cacheKey, 0, T_C, false);
tile11.addCache(tile11.cacheKey, 0, T_C, false, false);
const tile12 = createFakeTile('foo.jpg', fakeTiledImage1);
tile12.addCache(tile12.cacheKey, 0, T_A, false);
tile12.addCache(tile12.cacheKey, 0, T_A, false, false);
const collideGetSet = async (tile, type) => {
const value = await tile.getData(type, false);
@ -446,15 +446,15 @@
//load data
const tile00 = createFakeTile('foo.jpg', fakeTiledImage0);
tile00.addCache(tile00.cacheKey, 0, T_A, false);
tile00.addCache(tile00.cacheKey, 0, T_A, false, false);
const tile01 = createFakeTile('foo2.jpg', fakeTiledImage0);
tile01.addCache(tile01.cacheKey, 0, T_B, false);
tile01.addCache(tile01.cacheKey, 0, T_B, false, false);
const tile10 = createFakeTile('foo3.jpg', fakeTiledImage1);
tile10.addCache(tile10.cacheKey, 0, T_C, false);
tile10.addCache(tile10.cacheKey, 0, T_C, false, false);
const tile11 = createFakeTile('foo3.jpg', fakeTiledImage1);
tile11.addCache(tile11.cacheKey, 0, T_C, false);
tile11.addCache(tile11.cacheKey, 0, T_C, false, false);
const tile12 = createFakeTile('foo.jpg', fakeTiledImage1);
tile12.addCache(tile12.cacheKey, 0, T_A, false);
tile12.addCache(tile12.cacheKey, 0, T_A, false, false);
//test set/get data in async env
(async function() {