work-in-progress refactor of Drawer.prototype._updateActual

This commit is contained in:
thatcher 2012-01-18 20:15:54 -05:00
parent b3d1fcdbb4
commit f325804ff6
3 changed files with 762 additions and 528 deletions

View File

@ -330,11 +330,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
getElementPosition: function( element ) {
var element = $.getElement( element );
var result = new $.Point(),
isFixed,
offsetParent;
var isFixed = $.getElementStyle( element ).position == "fixed",
offsetParent = $.getOffsetParent( element, isFixed ),
result = new $.Point();
element = $.getElement( element );
isFixed = $.getElementStyle( element ).position == "fixed";
offsetParent = $.getOffsetParent( element, isFixed );
while ( offsetParent ) {
@ -354,7 +356,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
getElementSize: function( element ) {
var element = $.getElement( element );
element = $.getElement( element );
return new $.Point(
element.clientWidth,
@ -363,7 +365,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
getElementStyle: function( element ) {
var element = $.getElement( element );
element = $.getElement( element );
if ( element.currentStyle ) {
return element.currentStyle;
@ -379,15 +381,14 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
getMousePosition: function( event ) {
var event = $.getEvent( event );
var result = new $.Point();
event = $.getEvent( event );
if ( typeof( event.pageX ) == "number" ) {
result.x = event.pageX;
result.y = event.pageY;
} else if ( typeof( event.clientX ) == "number" ) {
result.x =
event.clientX +
document.body.scrollLeft +
@ -446,18 +447,19 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
imageFormatSupported: function( extension ) {
var extension = extension ? extension : "";
extension = extension ? extension : "";
return !!FILEFORMATS[ extension.toLowerCase() ];
},
makeCenteredNode: function( element ) {
var element = $.getElement( element );
var div = $.makeNeutralElement( "div" ),
html = [],
innerDiv,
innerDivs;
element = $.getElement( element );
//TODO: I dont understand the use of # inside the style attributes
// below. Invetigate the results of the constructed html in
// the browser and clean up the mark-up to make this clearer.
@ -534,12 +536,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
setElementOpacity: function( element, opacity, usesAlpha ) {
var element = $.getElement( element );
var previousFilter,
ieOpacity,
ieFilter;
element = $.getElement( element );
if ( usesAlpha && !$.Browser.alpha ) {
opacity = Math.round( opacity );
}
@ -573,7 +576,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
addEvent: function( element, eventName, handler, useCapture ) {
var element = $.getElement( element );
element = $.getElement( element );
//TODO: Why do this if/else on every method call instead of just
// defining this function once based on the same logic
@ -592,7 +595,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
removeEvent: function( element, eventName, handler, useCapture ) {
var element = $.getElement( element );
element = $.getElement( element );
//TODO: Why do this if/else on every method call instead of just
// defining this function once based on the same logic
@ -611,7 +614,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
cancelEvent: function( event ) {
var event = $.getEvent( event );
event = $.getEvent( event );
if ( event.preventDefault ) {
event.preventDefault(); // W3C for preventing default
@ -622,7 +625,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
stopEvent: function( event ) {
var event = $.getEvent( event );
event = $.getEvent( event );
if ( event.stopPropagation ) {
event.stopPropagation(); // W3C for stopping propagation
@ -3508,6 +3511,13 @@ $.Drawer.prototype = {
_getTile: function( level, x, y, time, numTilesX, numTilesY ) {
var xMod,
yMod,
bounds,
exists,
url,
tile;
if ( !this.tilesMatrix[ level ] ) {
this.tilesMatrix[ level ] = {};
}
@ -3516,20 +3526,26 @@ $.Drawer.prototype = {
}
if ( !this.tilesMatrix[ level ][ x ][ y ] ) {
var xMod = (numTilesX + (x % numTilesX)) % numTilesX;
var yMod = (numTilesY + (y % numTilesY)) % numTilesY;
var bounds = this.source.getTileBounds(level, xMod, yMod);
var exists = this.source.tileExists(level, xMod, yMod);
var url = this.source.getTileUrl(level, xMod, yMod);
xMod = ( numTilesX + ( x % numTilesX ) ) % numTilesX;
yMod = ( numTilesY + ( y % numTilesY ) ) % numTilesY;
bounds = this.source.getTileBounds( level, xMod, yMod );
exists = this.source.tileExists( level, xMod, yMod );
url = this.source.getTileUrl( level, xMod, yMod );
bounds.x += 1.0 * ( x - xMod ) / numTilesX;
bounds.y += this.normHeight * ( y - yMod ) / numTilesY;
this.tilesMatrix[level][x][y] = new $.Tile(level, x, y, bounds, exists, url);
this.tilesMatrix[ level ][ x ][ y ] = new $.Tile(
level,
x,
y,
bounds,
exists,
url
);
}
var tile = this.tilesMatrix[level][x][y];
tile = this.tilesMatrix[ level ][ x ][ y ];
tile.lastTouchTime = time;
return tile;
@ -3548,6 +3564,17 @@ $.Drawer.prototype = {
},
_onTileLoad: function(tile, time, image) {
var insertionIndex,
cutoff,
worstTile,
worstTime,
worstLevel,
worstTileIndex,
prevTile,
prevTime,
prevLevel,
i;
tile.loading = false;
if ( this.midUpdate ) {
@ -3565,16 +3592,16 @@ $.Drawer.prototype = {
tile.loaded = true;
tile.image = image;
var insertionIndex = this.tilesLoaded.length;
insertionIndex = this.tilesLoaded.length;
if ( this.tilesLoaded.length >= QUOTA ) {
var cutoff = Math.ceil(Math.log(this.tileSize) / Math.log(2));
cutoff = Math.ceil( Math.log( this.tileSize ) / Math.log( 2 ) );
var worstTile = null;
var worstTileIndex = -1;
worstTile = null;
worstTileIndex = -1;
for (var i = this.tilesLoaded.length - 1; i >= 0; i--) {
var prevTile = this.tilesLoaded[i];
for ( i = this.tilesLoaded.length - 1; i >= 0; i-- ) {
prevTile = this.tilesLoaded[ i ];
if ( prevTile.level <= this.cutoff || prevTile.beingDrawn ) {
continue;
@ -3584,10 +3611,10 @@ $.Drawer.prototype = {
continue;
}
var prevTime = prevTile.lastTouchTime;
var worstTime = worstTile.lastTouchTime;
var prevLevel = prevTile.level;
var worstLevel = worstTile.level;
prevTime = prevTile.lastTouchTime;
worstTime = worstTile.lastTouchTime;
prevLevel = prevTile.level;
worstLevel = worstTile.level;
if ( prevTime < worstTime ||
( prevTime == worstTime && prevLevel > worstLevel ) ) {
@ -3623,16 +3650,20 @@ $.Drawer.prototype = {
* levels that are within the image bounds, however, do not.
*/
_providesCoverage: function( level, x, y ) {
var rows,
cols,
i, j;
if ( !this.coverage[ level ] ) {
return false;
}
if ( x === undefined || y === undefined ) {
var rows = this.coverage[level];
for (var i in rows) {
rows = this.coverage[ level ];
for ( i in rows ) {
if ( rows.hasOwnProperty( i ) ) {
var cols = rows[i];
for (var j in cols) {
cols = rows[ i ];
for ( j in cols ) {
if ( cols.hasOwnProperty( j ) && !cols[ j ] ) {
return false;
}
@ -3643,9 +3674,11 @@ $.Drawer.prototype = {
return true;
}
return (this.coverage[level][x] === undefined ||
return (
this.coverage[ level ][ x] === undefined ||
this.coverage[ level ][ x ][ y ] === undefined ||
this.coverage[level][x][y] === true);
this.coverage[ level ][ x ][ y ] === true
);
},
/**
@ -3657,10 +3690,12 @@ $.Drawer.prototype = {
if ( x === undefined || y === undefined ) {
return this._providesCoverage( level + 1 );
} else {
return (this._providesCoverage(level + 1, 2 * x, 2 * y) &&
return (
this._providesCoverage( level + 1, 2 * x, 2 * y ) &&
this._providesCoverage( level + 1, 2 * x, 2 * y + 1 ) &&
this._providesCoverage( level + 1, 2 * x + 1, 2 * y ) &&
this._providesCoverage(level + 1, 2 * x + 1, 2 * y + 1));
this._providesCoverage( level + 1, 2 * x + 1, 2 * y + 1 )
);
}
},
@ -3669,8 +3704,9 @@ $.Drawer.prototype = {
*/
_setCoverage: function( level, x, y, covers ) {
if ( !this.coverage[ level ] ) {
$.Debug.error("Setting coverage for a tile before its " +
"level's coverage has been reset: " + level);
$.Debug.error(
"Setting coverage for a tile before its level's coverage has been reset: " + level
);
return;
}
@ -3709,7 +3745,8 @@ $.Drawer.prototype = {
_getOverlayIndex: function( elmt ) {
for (var i = this.overlays.length - 1; i >= 0; i--) {
var i;
for ( i = this.overlays.length - 1; i >= 0; i-- ) {
if ( this.overlays[ i ].elmt == elmt ) {
return i;
}
@ -3722,30 +3759,68 @@ $.Drawer.prototype = {
_updateActual: function() {
this.updateAgain = false;
var _canvas = this.canvas;
var _context = this.context;
var _container = this.container;
var _lastDrawn = this.lastDrawn;
var i, x, y,
tile,
tileTL,
tileBR,
numTiles,
numTilesX,
numTilesY,
level,
drawLevel,
drawTile,
renderPixelRatioC,
renderPixelRatioT,
levelOpacity,
levelVisibility,
viewportSize = this.viewport.getContainerSize(),
viewportWidth = viewportSize.x,
viewportHeight = viewportSize.y,
viewportBounds = this.viewport.getBounds( true ),
viewportTL = viewportBounds.getTopLeft(),
viewportBR = viewportBounds.getBottomRight(),
viewportCenter = this.viewport.pixelFromPoint( this.viewport.getCenter() ),
best = null,
haveDrawn = false,
currentTime = new Date().getTime(),
zeroRatioT = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio( 0 ),
false
).x,
zeroRatioC = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio( 0 ),
true
).x,
optimalRatio = this.config.immediateRender ? 1 : zeroRatioT,
lowestLevel = Math.max(
this.minLevel,
Math.floor(
Math.log( this.config.minZoomImageRatio ) /
Math.log( 2 )
)
),
highestLevel = Math.min(
this.maxLevel,
Math.floor(
Math.log( zeroRatioC / MIN_PIXEL_RATIO ) /
Math.log( 2 )
)
);
while (_lastDrawn.length > 0) {
var tile = _lastDrawn.pop();
while ( this.lastDrawn.length > 0 ) {
tile = this.lastDrawn.pop();
tile.beingDrawn = false;
}
var viewportSize = this.viewport.getContainerSize();
var viewportWidth = viewportSize.x;
var viewportHeight = viewportSize.y;
_canvas.innerHTML = "";
this.canvas.innerHTML = "";
if ( USE_CANVAS ) {
_canvas.width = viewportWidth;
_canvas.height = viewportHeight;
_context.clearRect(0, 0, viewportWidth, viewportHeight);
this.canvas.width = viewportWidth;
this.canvas.height = viewportHeight;
this.context.clearRect( 0, 0, viewportWidth, viewportHeight );
}
var viewportBounds = this.viewport.getBounds(true);
var viewportTL = viewportBounds.getTopLeft();
var viewportBR = viewportBounds.getBottomRight();
if ( !this.config.wrapHorizontal &&
( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
return;
@ -3755,51 +3830,31 @@ $.Drawer.prototype = {
}
var _abs = Math.abs;
var _ceil = Math.ceil;
var _floor = Math.floor;
var _log = Math.log;
var _max = Math.max;
var _min = Math.min;
var alwaysBlend = this.config.alwaysBlend;
var blendTimeMillis = 1000 * this.config.blendTime;
var immediateRender = this.config.immediateRender;
var wrapHorizontal = this.config.wrapHorizontal;
var wrapVertical = this.config.wrapVertical;
if (!wrapHorizontal) {
viewportTL.x = _max(viewportTL.x, 0);
viewportBR.x = _min(viewportBR.x, 1);
if ( !this.config.wrapHorizontal ) {
viewportTL.x = Math.max( viewportTL.x, 0 );
viewportBR.x = Math.min( viewportBR.x, 1 );
}
if (!wrapVertical) {
viewportTL.y = _max(viewportTL.y, 0);
viewportBR.y = _min(viewportBR.y, this.normHeight);
if ( !this.config.wrapVertical ) {
viewportTL.y = Math.max( viewportTL.y, 0 );
viewportBR.y = Math.min( viewportBR.y, this.normHeight );
}
var best = null;
var haveDrawn = false;
var currentTime = new Date().getTime();
lowestLevel = Math.min( lowestLevel, highestLevel );
var viewportCenter = this.viewport.pixelFromPoint(this.viewport.getCenter());
var zeroRatioT = this.viewport.deltaPixelsFromPoints(this.source.getPixelRatio(0), false).x;
var optimalPixelRatio = immediateRender ? 1 : zeroRatioT;
var lowestLevel = _max(this.minLevel, _floor(_log(this.config.minZoomImageRatio) / _log(2)));
var zeroRatioC = this.viewport.deltaPixelsFromPoints(this.source.getPixelRatio(0), true).x;
var highestLevel = _min(this.maxLevel,
_floor(_log(zeroRatioC / MIN_PIXEL_RATIO) / _log(2)));
lowestLevel = _min(lowestLevel, highestLevel);
for (var level = highestLevel; level >= lowestLevel; level--) {
var drawLevel = false;
var renderPixelRatioC = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio(level), true).x; // note the .x!
for ( level = highestLevel; level >= lowestLevel; level-- ) {
drawLevel = false;
// note the .x!
renderPixelRatioC = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio( level ),
true
).x;
renderPixelRatioT = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio( level ),
false
).x;
if ( ( !haveDrawn && renderPixelRatioC >= MIN_PIXEL_RATIO ) ||
level == lowestLevel) {
( level == lowestLevel ) ) {
drawLevel = true;
haveDrawn = true;
} else if ( !haveDrawn ) {
@ -3808,28 +3863,34 @@ $.Drawer.prototype = {
this._resetCoverage( level );
var levelOpacity = _min(1, (renderPixelRatioC - 0.5) / 0.5);
var renderPixelRatioT = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio(level), false).x;
var levelVisibility = optimalPixelRatio /
_abs(optimalPixelRatio - renderPixelRatioT);
levelOpacity = Math.min( 1, ( renderPixelRatioC - 0.5 ) / 0.5 );
levelVisibility = optimalRatio / Math.abs(
optimalRatio - renderPixelRatioT
);
var tileTL = this.source.getTileAtPoint(level, viewportTL);
var tileBR = this.source.getTileAtPoint(level, viewportBR);
var numTiles = numberOfTiles( this, level );
var numTilesX = numTiles.x;
var numTilesY = numTiles.y;
if (!wrapHorizontal) {
tileBR.x = _min(tileBR.x, numTilesX - 1);
tileTL = this.source.getTileAtPoint( level, viewportTL );
tileBR = this.source.getTileAtPoint( level, viewportBR );
numTiles = numberOfTiles( this, level );
numTilesX = numTiles.x;
numTilesY = numTiles.y;
if ( !this.config.wrapHorizontal ) {
tileBR.x = Math.min( tileBR.x, numTilesX - 1 );
}
if (!wrapVertical) {
tileBR.y = _min(tileBR.y, numTilesY - 1);
if ( !this.config.wrapVertical ) {
tileBR.y = Math.min( tileBR.y, numTilesY - 1 );
}
for (var x = tileTL.x; x <= tileBR.x; x++) {
for (var y = tileTL.y; y <= tileBR.y; y++) {
var tile = this._getTile(level, x, y, currentTime, numTilesX, numTilesY);
var drawTile = drawLevel;
for ( x = tileTL.x; x <= tileBR.x; x++ ) {
for ( y = tileTL.y; y <= tileBR.y; y++ ) {
drawTile = drawLevel;
tile = this._getTile(
level,
x, y,
currentTime,
numTilesX,
numTilesY
);
this._setCoverage( level, x, y, false );
@ -3849,47 +3910,24 @@ $.Drawer.prototype = {
continue;
}
var boundsTL = tile.bounds.getTopLeft();
var boundsSize = tile.bounds.getSize();
var positionC = this.viewport.pixelFromPoint(boundsTL, true);
var sizeC = this.viewport.deltaPixelsFromPoints(boundsSize, true);
if (!this.tileOverlap) {
sizeC = sizeC.plus(new $.Point(1, 1));
}
var positionT = this.viewport.pixelFromPoint(boundsTL, false);
var sizeT = this.viewport.deltaPixelsFromPoints(boundsSize, false);
var tileCenter = positionT.plus(sizeT.divide(2));
var tileDistance = viewportCenter.distanceTo(tileCenter);
tile.position = positionC;
tile.size = sizeC;
tile.distance = tileDistance;
tile.visibility = levelVisibility;
this._positionTile(
tile,
viewportCenter,
levelVisibility
);
if ( tile.loaded ) {
if (!tile.blendStart) {
tile.blendStart = currentTime;
}
var deltaTime = currentTime - tile.blendStart;
var opacity = _min(1, deltaTime / blendTimeMillis);
updateAgain = this._blendTile(
tile,
x, y,
level,
levelOpacity,
currentTime
);
if (alwaysBlend) {
opacity *= levelOpacity;
}
tile.opacity = opacity;
_lastDrawn.push(tile);
if (opacity == 1) {
this._setCoverage(level, x, y, true);
} else if (deltaTime < blendTimeMillis) {
updateAgain = true;
}
} else if ( tile.Loading ) {
//do nothing
} else {
best = this._compareTiles( best, tile );
}
@ -3901,59 +3939,138 @@ $.Drawer.prototype = {
}
}
for (var i = _lastDrawn.length - 1; i >= 0; i--) {
var tile = _lastDrawn[i];
this._drawTiles();
this._drawOverlays();
if ( best ) {
this._loadTile( best, currentTime );
// because we haven't finished drawing, so
this.updateAgain = true;
}
},
_drawLevel: function( ){
},
_positionTile: function( tile, viewportCenter, levelVisibility ){
var boundsTL = tile.bounds.getTopLeft(),
boundsSize = tile.bounds.getSize(),
positionC = this.viewport.pixelFromPoint( boundsTL, true ),
sizeC = this.viewport.deltaPixelsFromPoints( boundsSize, true ),
positionT = this.viewport.pixelFromPoint( boundsTL, false ),
sizeT = this.viewport.deltaPixelsFromPoints( boundsSize, false ),
tileCenter = positionT.plus( sizeT.divide( 2 ) ),
tileDistance = viewportCenter.distanceTo( tileCenter );
if ( !this.tileOverlap ) {
sizeC = sizeC.plus( new $.Point( 1, 1 ) );
}
tile.position = positionC;
tile.size = sizeC;
tile.distance = tileDistance;
tile.visibility = levelVisibility;
},
_blendTile: function( tile, x, y, level, levelOpacity, currentTime ){
var blendTimeMillis = 1000 * this.config.blendTime,
deltaTime,
opacity;
if ( !tile.blendStart ) {
tile.blendStart = currentTime;
}
deltaTime = currentTime - tile.blendStart;
opacity = Math.min( 1, deltaTime / blendTimeMillis );
if ( this.config.alwaysBlend ) {
opacity *= levelOpacity;
}
tile.opacity = opacity;
this.lastDrawn.push( tile );
if ( opacity == 1 ) {
this._setCoverage( level, x, y, true );
} else if ( deltaTime < blendTimeMillis ) {
return true;
}
return false;
},
_drawTiles: function(){
var i,
tile;
for ( i = this.lastDrawn.length - 1; i >= 0; i-- ) {
tile = this.lastDrawn[ i ];
if ( USE_CANVAS ) {
tile.drawCanvas(_context);
tile.drawCanvas( this.context );
} else {
tile.drawHTML(_canvas);
tile.drawHTML( this.canvas );
}
tile.beingDrawn = true;
}
},
_drawOverlays: function(){
var i,
length = this.overlays.length;
for ( i = 0; i < length; i++ ) {
this._drawOverlay( this.overlays[ i ] );
}
},
_drawOverlay: function( overlay ){
var numOverlays = this.overlays.length;
for (var i = 0; i < numOverlays; i++) {
var overlay = this.overlays[i];
var bounds = overlay.bounds;
overlay.position = this.viewport.pixelFromPoint(bounds.getTopLeft(), true);
overlay.size = this.viewport.deltaPixelsFromPoints(bounds.getSize(), true);
overlay.drawHTML(_container);
}
if (best) {
this._loadTile(best, currentTime);
this.updateAgain = true; // because we haven't finished drawing, so
}
overlay.position = this.viewport.pixelFromPoint(
bounds.getTopLeft(),
true
);
overlay.size = this.viewport.deltaPixelsFromPoints(
bounds.getSize(),
true
);
overlay.drawHTML( this.container );
},
addOverlay: function( element, location, placement ) {
element = $.getElement( element );
addOverlay: function(elmt, loc, placement) {
var elmt = $.getElement(elmt);
if (this._getOverlayIndex(elmt) >= 0) {
return; // they're trying to add a duplicate overlay
if ( this._getOverlayIndex( element ) >= 0 ) {
// they're trying to add a duplicate overlay
return;
}
this.overlays.push(new $.Overlay(elmt, loc, placement));
this.overlays.push( new $.Overlay( element, location, placement ) );
this.updateAgain = true;
},
updateOverlay: function(elmt, loc, placement) {
var elmt = $.getElement(elmt);
var i = this._getOverlayIndex(elmt);
updateOverlay: function( element, location, placement ) {
var i;
element = $.getElement( element );
i = this._getOverlayIndex( element );
if ( i >= 0 ) {
this.overlays[i].update(loc, placement);
this.overlays[ i ].update( location, placement );
this.updateAgain = true;
}
},
removeOverlay: function(elmt) {
var elmt = $.getElement(elmt);
var i = this._getOverlayIndex(elmt);
removeOverlay: function( element ) {
var i;
element = $.getElement( element );
i = this._getOverlayIndex( element );
if ( i >= 0 ) {
this.overlays[ i ].destroy();

View File

@ -84,6 +84,13 @@ $.Drawer.prototype = {
_getTile: function( level, x, y, time, numTilesX, numTilesY ) {
var xMod,
yMod,
bounds,
exists,
url,
tile;
if ( !this.tilesMatrix[ level ] ) {
this.tilesMatrix[ level ] = {};
}
@ -92,20 +99,26 @@ $.Drawer.prototype = {
}
if ( !this.tilesMatrix[ level ][ x ][ y ] ) {
var xMod = (numTilesX + (x % numTilesX)) % numTilesX;
var yMod = (numTilesY + (y % numTilesY)) % numTilesY;
var bounds = this.source.getTileBounds(level, xMod, yMod);
var exists = this.source.tileExists(level, xMod, yMod);
var url = this.source.getTileUrl(level, xMod, yMod);
xMod = ( numTilesX + ( x % numTilesX ) ) % numTilesX;
yMod = ( numTilesY + ( y % numTilesY ) ) % numTilesY;
bounds = this.source.getTileBounds( level, xMod, yMod );
exists = this.source.tileExists( level, xMod, yMod );
url = this.source.getTileUrl( level, xMod, yMod );
bounds.x += 1.0 * ( x - xMod ) / numTilesX;
bounds.y += this.normHeight * ( y - yMod ) / numTilesY;
this.tilesMatrix[level][x][y] = new $.Tile(level, x, y, bounds, exists, url);
this.tilesMatrix[ level ][ x ][ y ] = new $.Tile(
level,
x,
y,
bounds,
exists,
url
);
}
var tile = this.tilesMatrix[level][x][y];
tile = this.tilesMatrix[ level ][ x ][ y ];
tile.lastTouchTime = time;
return tile;
@ -124,6 +137,17 @@ $.Drawer.prototype = {
},
_onTileLoad: function(tile, time, image) {
var insertionIndex,
cutoff,
worstTile,
worstTime,
worstLevel,
worstTileIndex,
prevTile,
prevTime,
prevLevel,
i;
tile.loading = false;
if ( this.midUpdate ) {
@ -141,16 +165,16 @@ $.Drawer.prototype = {
tile.loaded = true;
tile.image = image;
var insertionIndex = this.tilesLoaded.length;
insertionIndex = this.tilesLoaded.length;
if ( this.tilesLoaded.length >= QUOTA ) {
var cutoff = Math.ceil(Math.log(this.tileSize) / Math.log(2));
cutoff = Math.ceil( Math.log( this.tileSize ) / Math.log( 2 ) );
var worstTile = null;
var worstTileIndex = -1;
worstTile = null;
worstTileIndex = -1;
for (var i = this.tilesLoaded.length - 1; i >= 0; i--) {
var prevTile = this.tilesLoaded[i];
for ( i = this.tilesLoaded.length - 1; i >= 0; i-- ) {
prevTile = this.tilesLoaded[ i ];
if ( prevTile.level <= this.cutoff || prevTile.beingDrawn ) {
continue;
@ -160,10 +184,10 @@ $.Drawer.prototype = {
continue;
}
var prevTime = prevTile.lastTouchTime;
var worstTime = worstTile.lastTouchTime;
var prevLevel = prevTile.level;
var worstLevel = worstTile.level;
prevTime = prevTile.lastTouchTime;
worstTime = worstTile.lastTouchTime;
prevLevel = prevTile.level;
worstLevel = worstTile.level;
if ( prevTime < worstTime ||
( prevTime == worstTime && prevLevel > worstLevel ) ) {
@ -199,16 +223,20 @@ $.Drawer.prototype = {
* levels that are within the image bounds, however, do not.
*/
_providesCoverage: function( level, x, y ) {
var rows,
cols,
i, j;
if ( !this.coverage[ level ] ) {
return false;
}
if ( x === undefined || y === undefined ) {
var rows = this.coverage[level];
for (var i in rows) {
rows = this.coverage[ level ];
for ( i in rows ) {
if ( rows.hasOwnProperty( i ) ) {
var cols = rows[i];
for (var j in cols) {
cols = rows[ i ];
for ( j in cols ) {
if ( cols.hasOwnProperty( j ) && !cols[ j ] ) {
return false;
}
@ -219,9 +247,11 @@ $.Drawer.prototype = {
return true;
}
return (this.coverage[level][x] === undefined ||
return (
this.coverage[ level ][ x] === undefined ||
this.coverage[ level ][ x ][ y ] === undefined ||
this.coverage[level][x][y] === true);
this.coverage[ level ][ x ][ y ] === true
);
},
/**
@ -233,10 +263,12 @@ $.Drawer.prototype = {
if ( x === undefined || y === undefined ) {
return this._providesCoverage( level + 1 );
} else {
return (this._providesCoverage(level + 1, 2 * x, 2 * y) &&
return (
this._providesCoverage( level + 1, 2 * x, 2 * y ) &&
this._providesCoverage( level + 1, 2 * x, 2 * y + 1 ) &&
this._providesCoverage( level + 1, 2 * x + 1, 2 * y ) &&
this._providesCoverage(level + 1, 2 * x + 1, 2 * y + 1));
this._providesCoverage( level + 1, 2 * x + 1, 2 * y + 1 )
);
}
},
@ -245,8 +277,9 @@ $.Drawer.prototype = {
*/
_setCoverage: function( level, x, y, covers ) {
if ( !this.coverage[ level ] ) {
$.Debug.error("Setting coverage for a tile before its " +
"level's coverage has been reset: " + level);
$.Debug.error(
"Setting coverage for a tile before its level's coverage has been reset: " + level
);
return;
}
@ -285,7 +318,8 @@ $.Drawer.prototype = {
_getOverlayIndex: function( elmt ) {
for (var i = this.overlays.length - 1; i >= 0; i--) {
var i;
for ( i = this.overlays.length - 1; i >= 0; i-- ) {
if ( this.overlays[ i ].elmt == elmt ) {
return i;
}
@ -298,30 +332,68 @@ $.Drawer.prototype = {
_updateActual: function() {
this.updateAgain = false;
var _canvas = this.canvas;
var _context = this.context;
var _container = this.container;
var _lastDrawn = this.lastDrawn;
var i, x, y,
tile,
tileTL,
tileBR,
numTiles,
numTilesX,
numTilesY,
level,
drawLevel,
drawTile,
renderPixelRatioC,
renderPixelRatioT,
levelOpacity,
levelVisibility,
viewportSize = this.viewport.getContainerSize(),
viewportWidth = viewportSize.x,
viewportHeight = viewportSize.y,
viewportBounds = this.viewport.getBounds( true ),
viewportTL = viewportBounds.getTopLeft(),
viewportBR = viewportBounds.getBottomRight(),
viewportCenter = this.viewport.pixelFromPoint( this.viewport.getCenter() ),
best = null,
haveDrawn = false,
currentTime = new Date().getTime(),
zeroRatioT = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio( 0 ),
false
).x,
zeroRatioC = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio( 0 ),
true
).x,
optimalRatio = this.config.immediateRender ? 1 : zeroRatioT,
lowestLevel = Math.max(
this.minLevel,
Math.floor(
Math.log( this.config.minZoomImageRatio ) /
Math.log( 2 )
)
),
highestLevel = Math.min(
this.maxLevel,
Math.floor(
Math.log( zeroRatioC / MIN_PIXEL_RATIO ) /
Math.log( 2 )
)
);
while (_lastDrawn.length > 0) {
var tile = _lastDrawn.pop();
while ( this.lastDrawn.length > 0 ) {
tile = this.lastDrawn.pop();
tile.beingDrawn = false;
}
var viewportSize = this.viewport.getContainerSize();
var viewportWidth = viewportSize.x;
var viewportHeight = viewportSize.y;
_canvas.innerHTML = "";
this.canvas.innerHTML = "";
if ( USE_CANVAS ) {
_canvas.width = viewportWidth;
_canvas.height = viewportHeight;
_context.clearRect(0, 0, viewportWidth, viewportHeight);
this.canvas.width = viewportWidth;
this.canvas.height = viewportHeight;
this.context.clearRect( 0, 0, viewportWidth, viewportHeight );
}
var viewportBounds = this.viewport.getBounds(true);
var viewportTL = viewportBounds.getTopLeft();
var viewportBR = viewportBounds.getBottomRight();
if ( !this.config.wrapHorizontal &&
( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
return;
@ -331,51 +403,31 @@ $.Drawer.prototype = {
}
var _abs = Math.abs;
var _ceil = Math.ceil;
var _floor = Math.floor;
var _log = Math.log;
var _max = Math.max;
var _min = Math.min;
var alwaysBlend = this.config.alwaysBlend;
var blendTimeMillis = 1000 * this.config.blendTime;
var immediateRender = this.config.immediateRender;
var wrapHorizontal = this.config.wrapHorizontal;
var wrapVertical = this.config.wrapVertical;
if (!wrapHorizontal) {
viewportTL.x = _max(viewportTL.x, 0);
viewportBR.x = _min(viewportBR.x, 1);
if ( !this.config.wrapHorizontal ) {
viewportTL.x = Math.max( viewportTL.x, 0 );
viewportBR.x = Math.min( viewportBR.x, 1 );
}
if (!wrapVertical) {
viewportTL.y = _max(viewportTL.y, 0);
viewportBR.y = _min(viewportBR.y, this.normHeight);
if ( !this.config.wrapVertical ) {
viewportTL.y = Math.max( viewportTL.y, 0 );
viewportBR.y = Math.min( viewportBR.y, this.normHeight );
}
var best = null;
var haveDrawn = false;
var currentTime = new Date().getTime();
lowestLevel = Math.min( lowestLevel, highestLevel );
var viewportCenter = this.viewport.pixelFromPoint(this.viewport.getCenter());
var zeroRatioT = this.viewport.deltaPixelsFromPoints(this.source.getPixelRatio(0), false).x;
var optimalPixelRatio = immediateRender ? 1 : zeroRatioT;
var lowestLevel = _max(this.minLevel, _floor(_log(this.config.minZoomImageRatio) / _log(2)));
var zeroRatioC = this.viewport.deltaPixelsFromPoints(this.source.getPixelRatio(0), true).x;
var highestLevel = _min(this.maxLevel,
_floor(_log(zeroRatioC / MIN_PIXEL_RATIO) / _log(2)));
lowestLevel = _min(lowestLevel, highestLevel);
for (var level = highestLevel; level >= lowestLevel; level--) {
var drawLevel = false;
var renderPixelRatioC = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio(level), true).x; // note the .x!
for ( level = highestLevel; level >= lowestLevel; level-- ) {
drawLevel = false;
// note the .x!
renderPixelRatioC = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio( level ),
true
).x;
renderPixelRatioT = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio( level ),
false
).x;
if ( ( !haveDrawn && renderPixelRatioC >= MIN_PIXEL_RATIO ) ||
level == lowestLevel) {
( level == lowestLevel ) ) {
drawLevel = true;
haveDrawn = true;
} else if ( !haveDrawn ) {
@ -384,28 +436,34 @@ $.Drawer.prototype = {
this._resetCoverage( level );
var levelOpacity = _min(1, (renderPixelRatioC - 0.5) / 0.5);
var renderPixelRatioT = this.viewport.deltaPixelsFromPoints(
this.source.getPixelRatio(level), false).x;
var levelVisibility = optimalPixelRatio /
_abs(optimalPixelRatio - renderPixelRatioT);
levelOpacity = Math.min( 1, ( renderPixelRatioC - 0.5 ) / 0.5 );
levelVisibility = optimalRatio / Math.abs(
optimalRatio - renderPixelRatioT
);
var tileTL = this.source.getTileAtPoint(level, viewportTL);
var tileBR = this.source.getTileAtPoint(level, viewportBR);
var numTiles = numberOfTiles( this, level );
var numTilesX = numTiles.x;
var numTilesY = numTiles.y;
if (!wrapHorizontal) {
tileBR.x = _min(tileBR.x, numTilesX - 1);
tileTL = this.source.getTileAtPoint( level, viewportTL );
tileBR = this.source.getTileAtPoint( level, viewportBR );
numTiles = numberOfTiles( this, level );
numTilesX = numTiles.x;
numTilesY = numTiles.y;
if ( !this.config.wrapHorizontal ) {
tileBR.x = Math.min( tileBR.x, numTilesX - 1 );
}
if (!wrapVertical) {
tileBR.y = _min(tileBR.y, numTilesY - 1);
if ( !this.config.wrapVertical ) {
tileBR.y = Math.min( tileBR.y, numTilesY - 1 );
}
for (var x = tileTL.x; x <= tileBR.x; x++) {
for (var y = tileTL.y; y <= tileBR.y; y++) {
var tile = this._getTile(level, x, y, currentTime, numTilesX, numTilesY);
var drawTile = drawLevel;
for ( x = tileTL.x; x <= tileBR.x; x++ ) {
for ( y = tileTL.y; y <= tileBR.y; y++ ) {
drawTile = drawLevel;
tile = this._getTile(
level,
x, y,
currentTime,
numTilesX,
numTilesY
);
this._setCoverage( level, x, y, false );
@ -425,47 +483,24 @@ $.Drawer.prototype = {
continue;
}
var boundsTL = tile.bounds.getTopLeft();
var boundsSize = tile.bounds.getSize();
var positionC = this.viewport.pixelFromPoint(boundsTL, true);
var sizeC = this.viewport.deltaPixelsFromPoints(boundsSize, true);
if (!this.tileOverlap) {
sizeC = sizeC.plus(new $.Point(1, 1));
}
var positionT = this.viewport.pixelFromPoint(boundsTL, false);
var sizeT = this.viewport.deltaPixelsFromPoints(boundsSize, false);
var tileCenter = positionT.plus(sizeT.divide(2));
var tileDistance = viewportCenter.distanceTo(tileCenter);
tile.position = positionC;
tile.size = sizeC;
tile.distance = tileDistance;
tile.visibility = levelVisibility;
this._positionTile(
tile,
viewportCenter,
levelVisibility
);
if ( tile.loaded ) {
if (!tile.blendStart) {
tile.blendStart = currentTime;
}
var deltaTime = currentTime - tile.blendStart;
var opacity = _min(1, deltaTime / blendTimeMillis);
updateAgain = this._blendTile(
tile,
x, y,
level,
levelOpacity,
currentTime
);
if (alwaysBlend) {
opacity *= levelOpacity;
}
tile.opacity = opacity;
_lastDrawn.push(tile);
if (opacity == 1) {
this._setCoverage(level, x, y, true);
} else if (deltaTime < blendTimeMillis) {
updateAgain = true;
}
} else if ( tile.Loading ) {
//do nothing
} else {
best = this._compareTiles( best, tile );
}
@ -477,59 +512,138 @@ $.Drawer.prototype = {
}
}
for (var i = _lastDrawn.length - 1; i >= 0; i--) {
var tile = _lastDrawn[i];
this._drawTiles();
this._drawOverlays();
if ( best ) {
this._loadTile( best, currentTime );
// because we haven't finished drawing, so
this.updateAgain = true;
}
},
_drawLevel: function( ){
},
_positionTile: function( tile, viewportCenter, levelVisibility ){
var boundsTL = tile.bounds.getTopLeft(),
boundsSize = tile.bounds.getSize(),
positionC = this.viewport.pixelFromPoint( boundsTL, true ),
sizeC = this.viewport.deltaPixelsFromPoints( boundsSize, true ),
positionT = this.viewport.pixelFromPoint( boundsTL, false ),
sizeT = this.viewport.deltaPixelsFromPoints( boundsSize, false ),
tileCenter = positionT.plus( sizeT.divide( 2 ) ),
tileDistance = viewportCenter.distanceTo( tileCenter );
if ( !this.tileOverlap ) {
sizeC = sizeC.plus( new $.Point( 1, 1 ) );
}
tile.position = positionC;
tile.size = sizeC;
tile.distance = tileDistance;
tile.visibility = levelVisibility;
},
_blendTile: function( tile, x, y, level, levelOpacity, currentTime ){
var blendTimeMillis = 1000 * this.config.blendTime,
deltaTime,
opacity;
if ( !tile.blendStart ) {
tile.blendStart = currentTime;
}
deltaTime = currentTime - tile.blendStart;
opacity = Math.min( 1, deltaTime / blendTimeMillis );
if ( this.config.alwaysBlend ) {
opacity *= levelOpacity;
}
tile.opacity = opacity;
this.lastDrawn.push( tile );
if ( opacity == 1 ) {
this._setCoverage( level, x, y, true );
} else if ( deltaTime < blendTimeMillis ) {
return true;
}
return false;
},
_drawTiles: function(){
var i,
tile;
for ( i = this.lastDrawn.length - 1; i >= 0; i-- ) {
tile = this.lastDrawn[ i ];
if ( USE_CANVAS ) {
tile.drawCanvas(_context);
tile.drawCanvas( this.context );
} else {
tile.drawHTML(_canvas);
tile.drawHTML( this.canvas );
}
tile.beingDrawn = true;
}
},
_drawOverlays: function(){
var i,
length = this.overlays.length;
for ( i = 0; i < length; i++ ) {
this._drawOverlay( this.overlays[ i ] );
}
},
_drawOverlay: function( overlay ){
var numOverlays = this.overlays.length;
for (var i = 0; i < numOverlays; i++) {
var overlay = this.overlays[i];
var bounds = overlay.bounds;
overlay.position = this.viewport.pixelFromPoint(bounds.getTopLeft(), true);
overlay.size = this.viewport.deltaPixelsFromPoints(bounds.getSize(), true);
overlay.drawHTML(_container);
}
if (best) {
this._loadTile(best, currentTime);
this.updateAgain = true; // because we haven't finished drawing, so
}
overlay.position = this.viewport.pixelFromPoint(
bounds.getTopLeft(),
true
);
overlay.size = this.viewport.deltaPixelsFromPoints(
bounds.getSize(),
true
);
overlay.drawHTML( this.container );
},
addOverlay: function( element, location, placement ) {
element = $.getElement( element );
addOverlay: function(elmt, loc, placement) {
var elmt = $.getElement(elmt);
if (this._getOverlayIndex(elmt) >= 0) {
return; // they're trying to add a duplicate overlay
if ( this._getOverlayIndex( element ) >= 0 ) {
// they're trying to add a duplicate overlay
return;
}
this.overlays.push(new $.Overlay(elmt, loc, placement));
this.overlays.push( new $.Overlay( element, location, placement ) );
this.updateAgain = true;
},
updateOverlay: function(elmt, loc, placement) {
var elmt = $.getElement(elmt);
var i = this._getOverlayIndex(elmt);
updateOverlay: function( element, location, placement ) {
var i;
element = $.getElement( element );
i = this._getOverlayIndex( element );
if ( i >= 0 ) {
this.overlays[i].update(loc, placement);
this.overlays[ i ].update( location, placement );
this.updateAgain = true;
}
},
removeOverlay: function(elmt) {
var elmt = $.getElement(elmt);
var i = this._getOverlayIndex(elmt);
removeOverlay: function( element ) {
var i;
element = $.getElement( element );
i = this._getOverlayIndex( element );
if ( i >= 0 ) {
this.overlays[ i ].destroy();

View File

@ -330,11 +330,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
getElementPosition: function( element ) {
var element = $.getElement( element );
var result = new $.Point(),
isFixed,
offsetParent;
var isFixed = $.getElementStyle( element ).position == "fixed",
offsetParent = $.getOffsetParent( element, isFixed ),
result = new $.Point();
element = $.getElement( element );
isFixed = $.getElementStyle( element ).position == "fixed";
offsetParent = $.getOffsetParent( element, isFixed );
while ( offsetParent ) {
@ -354,7 +356,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
getElementSize: function( element ) {
var element = $.getElement( element );
element = $.getElement( element );
return new $.Point(
element.clientWidth,
@ -363,7 +365,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
getElementStyle: function( element ) {
var element = $.getElement( element );
element = $.getElement( element );
if ( element.currentStyle ) {
return element.currentStyle;
@ -379,15 +381,14 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
getMousePosition: function( event ) {
var event = $.getEvent( event );
var result = new $.Point();
event = $.getEvent( event );
if ( typeof( event.pageX ) == "number" ) {
result.x = event.pageX;
result.y = event.pageY;
} else if ( typeof( event.clientX ) == "number" ) {
result.x =
event.clientX +
document.body.scrollLeft +
@ -446,18 +447,19 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
imageFormatSupported: function( extension ) {
var extension = extension ? extension : "";
extension = extension ? extension : "";
return !!FILEFORMATS[ extension.toLowerCase() ];
},
makeCenteredNode: function( element ) {
var element = $.getElement( element );
var div = $.makeNeutralElement( "div" ),
html = [],
innerDiv,
innerDivs;
element = $.getElement( element );
//TODO: I dont understand the use of # inside the style attributes
// below. Invetigate the results of the constructed html in
// the browser and clean up the mark-up to make this clearer.
@ -534,12 +536,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
setElementOpacity: function( element, opacity, usesAlpha ) {
var element = $.getElement( element );
var previousFilter,
ieOpacity,
ieFilter;
element = $.getElement( element );
if ( usesAlpha && !$.Browser.alpha ) {
opacity = Math.round( opacity );
}
@ -573,7 +576,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
addEvent: function( element, eventName, handler, useCapture ) {
var element = $.getElement( element );
element = $.getElement( element );
//TODO: Why do this if/else on every method call instead of just
// defining this function once based on the same logic
@ -592,7 +595,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
removeEvent: function( element, eventName, handler, useCapture ) {
var element = $.getElement( element );
element = $.getElement( element );
//TODO: Why do this if/else on every method call instead of just
// defining this function once based on the same logic
@ -611,7 +614,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
cancelEvent: function( event ) {
var event = $.getEvent( event );
event = $.getEvent( event );
if ( event.preventDefault ) {
event.preventDefault(); // W3C for preventing default
@ -622,7 +625,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
},
stopEvent: function( event ) {
var event = $.getEvent( event );
event = $.getEvent( event );
if ( event.stopPropagation ) {
event.stopPropagation(); // W3C for stopping propagation