Merge pull request #659 from avandecreme/master

Move tile caching code inside tilecache.js.
This commit is contained in:
Ian Gilman 2015-06-12 16:23:11 -07:00
commit a3183183b2
14 changed files with 250 additions and 73 deletions

View File

@ -1,7 +1,8 @@
# editorconfig.org # editorconfig.org
root = true root = true
[*] # We need to specify each folder specifically to avoid including test/lib and test/data
[{Gruntfile.js,src/**,test/*,test/demo/**,test/helpers/**,test/modules/**}]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
end_of_line = lf end_of_line = lf

View File

@ -2,6 +2,11 @@ OPENSEADRAGON CHANGELOG
======================= =======================
2.0.1: (in progress) 2.0.1: (in progress)
* BREAKING CHANGE: the tile does not hold a reference to its image anymore. Only the tile cache keep a reference to images.
* DEPRECATION: let ImageRecord.getRenderedContext create the rendered context instead of using ImageRecord.setRenderedContext.
* Added "tile-loaded" event on the viewer allowing to modify a tile before it is marked ready to be drawn. (#659)
* Added "tile-unloaded" event on the viewer allowing to free up memory one has allocated on a tile. (#659)
* Fix flickering tiles with useCanvas=false when no cache is used. (#661)
2.0.0: 2.0.0:

View File

@ -68,7 +68,7 @@ $.ButtonGroup = function( options ) {
*/ */
this.element = options.element || $.makeNeutralElement( "div" ); this.element = options.element || $.makeNeutralElement( "div" );
// TODO What if there IS an options.group specified? // TODO What if there IS an options.group specified?
if( !options.group ){ if( !options.group ){
this.label = $.makeNeutralElement( "label" ); this.label = $.makeNeutralElement( "label" );
//TODO: support labels for ButtonGroups //TODO: support labels for ButtonGroups

View File

@ -94,7 +94,7 @@ $.IIIFTileSource = function( options ){
// If we're smaller than 256, just use the short side. // If we're smaller than 256, just use the short side.
options.tileSize = shortDim; options.tileSize = shortDim;
} }
this.tile_width = options.tileSize; // So that 'full' gets used for this.tile_width = options.tileSize; // So that 'full' gets used for
this.tile_height = options.tileSize; // the region below this.tile_height = options.tileSize; // the region below
} }

View File

@ -133,7 +133,7 @@
*/ */
this.element = $.getElement( options.element ); this.element = $.getElement( options.element );
/** /**
* The number of milliseconds within which a pointer down-up event combination * The number of milliseconds within which a pointer down-up event combination
* will be treated as a click gesture. * will be treated as a click gesture.
* @member {Number} clickTimeThreshold * @member {Number} clickTimeThreshold
* @memberof OpenSeadragon.MouseTracker# * @memberof OpenSeadragon.MouseTracker#
@ -244,7 +244,7 @@
// Active pointers lists. Array of GesturePointList objects, one for each pointer device type. // Active pointers lists. Array of GesturePointList objects, one for each pointer device type.
// GesturePointList objects are added each time a pointer is tracked by a new pointer device type (see getActivePointersListByType()). // GesturePointList objects are added each time a pointer is tracked by a new pointer device type (see getActivePointersListByType()).
// Active pointers are any pointer being tracked for this element which are in the hit-test area // Active pointers are any pointer being tracked for this element which are in the hit-test area
// of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. // of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.
activePointersLists: [], activePointersLists: [],
@ -1032,7 +1032,7 @@
$.MouseTracker.mousePointerId = "legacy-mouse"; $.MouseTracker.mousePointerId = "legacy-mouse";
$.MouseTracker.maxTouchPoints = 10; $.MouseTracker.maxTouchPoints = 10;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Classes and typedefs // Classes and typedefs
@ -1078,7 +1078,7 @@
/** /**
* @class GesturePointList * @class GesturePointList
* @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type. * @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type.
* Active pointers are any pointer being tracked for this element which are in the hit-test area * Active pointers are any pointer being tracked for this element which are in the hit-test area
* of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. * of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.
* @memberof OpenSeadragon.MouseTracker * @memberof OpenSeadragon.MouseTracker
* @param {String} type - The pointer device type: "mouse", "touch", "pen", etc. * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc.
@ -1198,7 +1198,7 @@
return null; return null;
} }
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Utility functions // Utility functions
@ -1282,7 +1282,7 @@
false false
); );
} }
clearTrackedPointers( tracker ); clearTrackedPointers( tracker );
delegate.tracking = true; delegate.tracking = true;
@ -1694,7 +1694,7 @@
/** /**
* Handles 'wheel' events. * Handles 'wheel' events.
* The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()). * The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()).
* *
* @private * @private
@ -1943,7 +1943,7 @@
handleMouseMove( tracker, event ); handleMouseMove( tracker, event );
} }
/** /**
* This handler is attached to the window object (on the capture phase) to emulate mouse capture. * This handler is attached to the window object (on the capture phase) to emulate mouse capture.
* onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice. * onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice.
@ -2191,7 +2191,7 @@
var i, var i,
touchCount = event.changedTouches.length, touchCount = event.changedTouches.length,
gPoints = []; gPoints = [];
for ( i = 0; i < touchCount; i++ ) { for ( i = 0; i < touchCount; i++ ) {
gPoints.push( { gPoints.push( {
id: event.changedTouches[ i ].identifier, id: event.changedTouches[ i ].identifier,
@ -2420,7 +2420,7 @@
*/ */
function startTrackingPointer( pointsList, gPoint ) { function startTrackingPointer( pointsList, gPoint ) {
// If isPrimary is not known for the pointer then set it according to our rules: // If isPrimary is not known for the pointer then set it according to our rules:
// true if the first pointer in the gesture, otherwise false // true if the first pointer in the gesture, otherwise false
if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) { if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) {
if ( pointsList.getLength() === 0 ) { if ( pointsList.getLength() === 0 ) {
@ -2617,7 +2617,7 @@
* Gesture points associated with the event. * Gesture points associated with the event.
* @param {Number} buttonChanged * @param {Number} buttonChanged
* The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
* Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,
* only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.
* *
* @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false. * @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false.
@ -2779,7 +2779,7 @@
* Gesture points associated with the event. * Gesture points associated with the event.
* @param {Number} buttonChanged * @param {Number} buttonChanged
* The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
* Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,
* only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.
* *
* @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false. * @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false.

View File

@ -190,7 +190,14 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
* @param {Element} container * @param {Element} container
*/ */
drawHTML: function( container ) { drawHTML: function( container ) {
if ( !this.loaded || !this.image ) { if (!this.cacheImageRecord) {
$.console.warn(
'[Tile.drawHTML] attempting to draw tile %s when it\'s not cached',
this.toString());
return;
}
if ( !this.loaded ) {
$.console.warn( $.console.warn(
"Attempting to draw tile %s when it's not yet loaded.", "Attempting to draw tile %s when it's not yet loaded.",
this.toString() this.toString()
@ -203,8 +210,7 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
if ( !this.element ) { if ( !this.element ) {
this.element = $.makeNeutralElement( "div" ); this.element = $.makeNeutralElement( "div" );
this.imgElement = $.makeNeutralElement( "img" ); this.imgElement = this.cacheImageRecord.getImage().cloneNode();
this.imgElement.src = this.url;
this.imgElement.style.msInterpolationMode = "nearest-neighbor"; this.imgElement.style.msInterpolationMode = "nearest-neighbor";
this.imgElement.style.width = "100%"; this.imgElement.style.width = "100%";
this.imgElement.style.height = "100%"; this.imgElement.style.height = "100%";
@ -239,17 +245,18 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
var position = this.position, var position = this.position,
size = this.size, size = this.size,
rendered, rendered;
canvas;
if (!this.cacheImageRecord) { if (!this.cacheImageRecord) {
$.console.warn('[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached', this.toString()); $.console.warn(
'[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached',
this.toString());
return; return;
} }
rendered = this.cacheImageRecord.getRenderedContext(); rendered = this.cacheImageRecord.getRenderedContext();
if ( !this.loaded || !( this.image || rendered) ){ if ( !this.loaded || !rendered ){
$.console.warn( $.console.warn(
"Attempting to draw tile %s when it's not yet loaded.", "Attempting to draw tile %s when it's not yet loaded.",
this.toString() this.toString()
@ -276,19 +283,8 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
} }
if(!rendered){ // This gives the application a chance to make image manipulation
canvas = document.createElement( 'canvas' ); // changes as we are rendering the image
canvas.width = this.image.width;
canvas.height = this.image.height;
rendered = canvas.getContext('2d');
rendered.drawImage( this.image, 0, 0 );
this.cacheImageRecord.setRenderedContext(rendered);
//since we are caching the prerendered image on a canvas
//allow the image to not be held in memory
this.image = null;
}
// This gives the application a chance to make image manipulation changes as we are rendering the image
drawingHandler({context: context, tile: this, rendered: rendered}); drawingHandler({context: context, tile: this, rendered: rendered});
context.drawImage( context.drawImage(
@ -318,7 +314,6 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
this.element = null; this.element = null;
this.imgElement = null; this.imgElement = null;
this.image = null;
this.loaded = false; this.loaded = false;
this.loading = false; this.loading = false;
} }

View File

@ -63,10 +63,23 @@ ImageRecord.prototype = {
}, },
getRenderedContext: function() { 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; return this._renderedContext;
}, },
setRenderedContext: function(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; this._renderedContext = renderedContext;
}, },
@ -126,6 +139,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
* may temporarily surpass that number, but should eventually come back down to the max specified. * may temporarily surpass that number, but should eventually come back down to the max specified.
* @param {Object} options - Tile info. * @param {Object} options - Tile info.
* @param {OpenSeadragon.Tile} options.tile - The tile to cache. * @param {OpenSeadragon.Tile} options.tile - The tile to cache.
* @param {Image} options.image - The image of the tile to cache.
* @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile. * @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile.
* @param {Number} [options.cutoff=0] - If adding this tile goes over the cache max count, this * @param {Number} [options.cutoff=0] - If adding this tile goes over the cache max count, this
* function will release an old tile. The cutoff option specifies a tile level at or below which * function will release an old tile. The cutoff option specifies a tile level at or below which
@ -135,7 +149,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
$.console.assert( options, "[TileCache.cacheTile] options is required" ); $.console.assert( options, "[TileCache.cacheTile] options is required" );
$.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" ); $.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" );
$.console.assert( options.tile.url, "[TileCache.cacheTile] options.tile.url is required" ); $.console.assert( options.tile.url, "[TileCache.cacheTile] options.tile.url is required" );
$.console.assert( options.tile.image, "[TileCache.cacheTile] options.tile.image is required" ); $.console.assert( options.image, "[TileCache.cacheTile] options.image is required" );
$.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" ); $.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" );
var cutoff = options.cutoff || 0; var cutoff = options.cutoff || 0;
@ -144,7 +158,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
var imageRecord = this._imagesLoaded[options.tile.url]; var imageRecord = this._imagesLoaded[options.tile.url];
if (!imageRecord) { if (!imageRecord) {
imageRecord = this._imagesLoaded[options.tile.url] = new ImageRecord({ imageRecord = this._imagesLoaded[options.tile.url] = new ImageRecord({
image: options.tile.image image: options.image
}); });
this._imagesLoadedCount++; this._imagesLoadedCount++;
@ -158,6 +172,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
if ( this._imagesLoadedCount > this._maxImageCacheCount ) { if ( this._imagesLoadedCount > this._maxImageCacheCount ) {
var worstTile = null; var worstTile = null;
var worstTileIndex = -1; var worstTileIndex = -1;
var worstTileRecord = null;
var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord; var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord;
for ( var i = this._tilesLoaded.length - 1; i >= 0; i-- ) { for ( var i = this._tilesLoaded.length - 1; i >= 0; i-- ) {
@ -169,6 +184,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
} else if ( !worstTile ) { } else if ( !worstTile ) {
worstTile = prevTile; worstTile = prevTile;
worstTileIndex = i; worstTileIndex = i;
worstTileRecord = prevTileRecord;
continue; continue;
} }
@ -181,11 +197,12 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
( prevTime == worstTime && prevLevel > worstLevel ) ) { ( prevTime == worstTime && prevLevel > worstLevel ) ) {
worstTile = prevTile; worstTile = prevTile;
worstTileIndex = i; worstTileIndex = i;
worstTileRecord = prevTileRecord;
} }
} }
if ( worstTile && worstTileIndex >= 0 ) { if ( worstTile && worstTileIndex >= 0 ) {
this._unloadTile(worstTile); this._unloadTile(worstTileRecord);
insertionIndex = worstTileIndex; insertionIndex = worstTileIndex;
} }
} }
@ -206,7 +223,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
for ( var i = 0; i < this._tilesLoaded.length; ++i ) { for ( var i = 0; i < this._tilesLoaded.length; ++i ) {
tileRecord = this._tilesLoaded[ i ]; tileRecord = this._tilesLoaded[ i ];
if ( tileRecord.tiledImage === tiledImage ) { if ( tileRecord.tiledImage === tiledImage ) {
this._unloadTile(tileRecord.tile); this._unloadTile(tileRecord);
this._tilesLoaded.splice( i, 1 ); this._tilesLoaded.splice( i, 1 );
i--; i--;
} }
@ -220,8 +237,11 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
}, },
// private // private
_unloadTile: function(tile) { _unloadTile: function(tileRecord) {
$.console.assert(tile, '[TileCache._unloadTile] tile is required'); $.console.assert(tileRecord, '[TileCache._unloadTile] tileRecord is required');
var tile = tileRecord.tile;
var tiledImage = tileRecord.tiledImage;
tile.unload(); tile.unload();
tile.cacheImageRecord = null; tile.cacheImageRecord = null;
@ -232,6 +252,20 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
delete this._imagesLoaded[tile.url]; delete this._imagesLoaded[tile.url];
this._imagesLoadedCount--; this._imagesLoadedCount--;
} }
/**
* Triggered when a tile has just been unloaded from memory.
*
* @event tile-unloaded
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the unloaded tile.
* @property {OpenSeadragon.Tile} tile - The tile which has been unloaded.
*/
tiledImage.viewer.raiseEvent("tile-unloaded", {
tile: tile,
tiledImage: tiledImage
});
} }
}; };

View File

@ -715,8 +715,6 @@ function updateViewport( tiledImage ) {
// Load the new 'best' tile // Load the new 'best' tile
if ( best ) { if ( best ) {
loadTile( tiledImage, best, currentTime ); loadTile( tiledImage, best, currentTime );
// because we haven't finished drawing, so
tiledImage._needsDraw = true;
} }
} }
@ -862,13 +860,8 @@ function updateTile( tiledImage, drawLevel, haveDrawn, x, y, level, levelOpacity
if (!tile.loaded) { if (!tile.loaded) {
var imageRecord = tiledImage._tileCache.getImageRecord(tile.url); var imageRecord = tiledImage._tileCache.getImageRecord(tile.url);
if (imageRecord) { if (imageRecord) {
tile.loaded = true; var image = imageRecord.getImage();
tile.image = imageRecord.getImage(); setTileLoaded(tiledImage, tile, image);
tiledImage._tileCache.cacheTile({
tile: tile,
tiledImage: tiledImage
});
} }
} }
@ -965,16 +958,9 @@ function onTileLoad( tiledImage, tile, time, image ) {
} }
var finish = function() { var finish = function() {
tile.loading = false; var cutoff = Math.ceil( Math.log(
tile.loaded = true; tiledImage.source.getTileSize(tile.level) ) / Math.log( 2 ) );
tile.image = image; setTileLoaded(tiledImage, tile, image, cutoff);
var cutoff = Math.ceil( Math.log( tiledImage.source.getTileSize(tile.level) ) / Math.log( 2 ) );
tiledImage._tileCache.cacheTile({
tile: tile,
cutoff: cutoff,
tiledImage: tiledImage
});
}; };
// Check if we're mid-update; this can happen on IE8 because image load events for // Check if we're mid-update; this can happen on IE8 because image load events for
@ -985,10 +971,55 @@ function onTileLoad( tiledImage, tile, time, image ) {
// Wait until after the update, in case caching unloads any tiles // Wait until after the update, in case caching unloads any tiles
window.setTimeout( finish, 1); window.setTimeout( finish, 1);
} }
tiledImage._needsDraw = true;
} }
function setTileLoaded(tiledImage, tile, image, cutoff) {
var increment = 0;
function getCompletionCallback() {
increment++;
return completionCallback;
}
function completionCallback() {
increment--;
if (increment === 0) {
tile.loading = false;
tile.loaded = true;
tiledImage._tileCache.cacheTile({
image: image,
tile: tile,
cutoff: cutoff,
tiledImage: tiledImage
});
tiledImage._needsDraw = true;
}
}
/**
* 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-loaded
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {Image} image - The image 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 {function} getCompletionCallback - A function giving a callback to call
* when the asynchronous processing of the image is done. The image will be
* marked as entirely loaded when the callback has been called once for each
* call to getCompletionCallback.
*/
tiledImage.viewer.raiseEvent("tile-loaded", {
tile: tile,
tiledImage: tiledImage,
image: image,
getCompletionCallback: getCompletionCallback
});
// In case the completion callback is never called, we at least force it once.
getCompletionCallback()();
}
function positionTile( tile, overlap, viewport, viewportCenter, levelVisibility, tiledImage ){ function positionTile( tile, overlap, viewport, viewportCenter, levelVisibility, tiledImage ){
var boundsTL = tile.bounds.getTopLeft(); var boundsTL = tile.bounds.getTopLeft();

View File

@ -23,19 +23,19 @@
<script type="text/javascript"> <script type="text/javascript">
var _viewer; var _viewer;
var generateUniqueHash = (function() { var generateUniqueHash = (function() {
var counter = 0; var counter = 0;
return function() { return function() {
return "openseadragon_" + (counter++); return "openseadragon_" + (counter++);
}; };
})(); })();
function createViewer() { function createViewer() {
if ( _viewer ) { if ( _viewer ) {
destroyViewer(); destroyViewer();
} }
_viewer = OpenSeadragon({ _viewer = OpenSeadragon({
element: document.getElementById("contentDiv"), element: document.getElementById("contentDiv"),
showNavigationControl: false, showNavigationControl: false,
@ -44,7 +44,7 @@
tileSources: "../data/testpattern.dzi" tileSources: "../data/testpattern.dzi"
}); });
} }
function destroyViewer() { function destroyViewer() {
if ( _viewer ) { if ( _viewer ) {
_viewer.destroy(); _viewer.destroy();

File diff suppressed because one or more lines are too long

View File

@ -968,4 +968,103 @@
viewer.open( '/test/data/testpattern.dzi' ); viewer.open( '/test/data/testpattern.dzi' );
} ); } );
// tile-loaded event tests
asyncTest( 'Viewer: tile-loaded event without callback.', function () {
function tileLoaded ( event ) {
viewer.removeHandler( 'tile-loaded', tileLoaded);
var tile = event.tile;
ok( tile.loading, "The tile should be marked as loading.");
notOk( tile.loaded, "The tile should not be marked as loaded.");
setTimeout(function() {
notOk( tile.loading, "The tile should not be marked as loading.");
ok( tile.loaded, "The tile should be marked as loaded.");
start();
}, 0);
}
viewer.addHandler( 'tile-loaded', tileLoaded);
viewer.open( '/test/data/testpattern.dzi' );
} );
asyncTest( 'Viewer: tile-loaded event with 1 callback.', function () {
function tileLoaded ( event ) {
viewer.removeHandler( 'tile-loaded', tileLoaded);
var tile = event.tile;
var callback = event.getCompletionCallback();
ok( tile.loading, "The tile should be marked as loading.");
notOk( tile.loaded, "The tile should not be marked as loaded.");
ok( callback, "The event should have a callback.");
setTimeout(function() {
ok( tile.loading, "The tile should be marked as loading.");
notOk( tile.loaded, "The tile should not be marked as loaded.");
callback();
notOk( tile.loading, "The tile should not be marked as loading.");
ok( tile.loaded, "The tile should be marked as loaded.");
start();
}, 0);
}
viewer.addHandler( 'tile-loaded', tileLoaded);
viewer.open( '/test/data/testpattern.dzi' );
} );
asyncTest( 'Viewer: tile-loaded event with 2 callbacks.', function () {
function tileLoaded ( event ) {
viewer.removeHandler( 'tile-loaded', tileLoaded);
var tile = event.tile;
var callback1 = event.getCompletionCallback();
var callback2 = event.getCompletionCallback();
ok( tile.loading, "The tile should be marked as loading.");
notOk( tile.loaded, "The tile should not be marked as loaded.");
setTimeout(function() {
ok( tile.loading, "The tile should be marked as loading.");
notOk( tile.loaded, "The tile should not be marked as loaded.");
callback1();
ok( tile.loading, "The tile should be marked as loading.");
notOk( tile.loaded, "The tile should not be marked as loaded.");
setTimeout(function() {
ok( tile.loading, "The tile should be marked as loading.");
notOk( tile.loaded, "The tile should not be marked as loaded.");
callback2();
notOk( tile.loading, "The tile should not be marked as loading.");
ok( tile.loaded, "The tile should be marked as loaded.");
start();
}, 0);
}, 0);
}
viewer.addHandler( 'tile-loaded', tileLoaded);
viewer.open( '/test/data/testpattern.dzi' );
} );
asyncTest( 'Viewer: tile-unloaded event.', function() {
var tiledImage;
var tile;
function tileLoaded( event ) {
viewer.removeHandler( 'tile-loaded', tileLoaded);
tiledImage = event.tiledImage;
tile = event.tile;
setTimeout(function() {
tiledImage.reset();
}, 0);
}
function tileUnloaded( event ) {
viewer.removeHandler( 'tile-unloaded', tileUnloaded );
equal( tile, event.tile,
"The unloaded tile should be the same than the loaded one." );
equal( tiledImage, event.tiledImage,
"The tiledImage of the unloaded tile should be the same than the one of the loaded one." );
start();
}
viewer.addHandler( 'tile-loaded', tileLoaded );
viewer.addHandler( 'tile-unloaded', tileUnloaded );
viewer.open( '/test/data/testpattern.dzi' );
} );
} )(); } )();

View File

@ -108,6 +108,6 @@
// ---------- // ----------
asyncTest('IIIF 2.0 JSON', function() { asyncTest('IIIF 2.0 JSON', function() {
testOpen('iiif_2_0_tiled/info.json'); testOpen('iiif_2_0_tiled/info.json');
}); });
})(); })();

View File

@ -13,8 +13,15 @@
// ---------- // ----------
asyncTest('basics', function() { asyncTest('basics', function() {
var fakeTiledImage0 = {}; var fakeViewer = {
var fakeTiledImage1 = {}; raiseEvent: function() {}
};
var fakeTiledImage0 = {
viewer: fakeViewer
};
var fakeTiledImage1 = {
viewer: fakeViewer
};
var fakeTile0 = { var fakeTile0 = {
url: 'foo.jpg', url: 'foo.jpg',
@ -58,7 +65,12 @@
// ---------- // ----------
asyncTest('maxImageCacheCount', function() { asyncTest('maxImageCacheCount', function() {
var fakeTiledImage0 = {}; var fakeViewer = {
raiseEvent: function() {}
};
var fakeTiledImage0 = {
viewer: fakeViewer
};
var fakeTile0 = { var fakeTile0 = {
url: 'different.jpg', url: 'different.jpg',

View File

@ -107,7 +107,7 @@
var actualImageZoom = viewport.viewportToImageZoom( var actualImageZoom = viewport.viewportToImageZoom(
expectedViewportZoom); expectedViewportZoom);
equal(actualImageZoom, expectedImageZoom); equal(actualImageZoom, expectedImageZoom);
var actualViewportZoom = viewport.imageToViewportZoom(actualImageZoom); var actualViewportZoom = viewport.imageToViewportZoom(actualImageZoom);
equal(actualViewportZoom, expectedViewportZoom); equal(actualViewportZoom, expectedViewportZoom);
} }