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

@ -314,8 +314,8 @@ OpenSeadragon = window.OpenSeadragon || (function(){
$.extend( $, {
getElement: function( element ) {
if (typeof ( element ) == "string") {
getElement: function( element ) {
if ( typeof ( element ) == "string") {
element = document.getElementById( element );
}
return element;
@ -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
@ -3498,49 +3501,62 @@ $.Drawer = function(source, viewport, elmt) {
$.Drawer.prototype = {
getPixelRatio: function(level) {
if (!this.cachePixelRatios[level]) {
this.cachePixelRatios[level] = this.source.getPixelRatio(level);
getPixelRatio: function( level ) {
if ( !this.cachePixelRatios[ level ] ) {
this.cachePixelRatios[ level ] = this.source.getPixelRatio( level );
}
return this.cachePixelRatios[level];
return this.cachePixelRatios[ level ];
},
_getTile: function(level, x, y, time, numTilesX, numTilesY) {
if (!this.tilesMatrix[level]) {
this.tilesMatrix[level] = {};
_getTile: function( level, x, y, time, numTilesX, numTilesY ) {
var xMod,
yMod,
bounds,
exists,
url,
tile;
if ( !this.tilesMatrix[ level ] ) {
this.tilesMatrix[ level ] = {};
}
if (!this.tilesMatrix[level][x]) {
this.tilesMatrix[level][x] = {};
if ( !this.tilesMatrix[ level ][ x ] ) {
this.tilesMatrix[ level ][ x ] = {};
}
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);
if ( !this.tilesMatrix[ level ][ x ][ y ] ) {
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;
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;
},
_loadTile: function(tile, time) {
_loadTile: function( tile, time ) {
tile.loading = this.loadImage(
tile.url,
$.createCallback(
null,
$.delegate(this, this._onTileLoad),
$.delegate( this, this._onTileLoad ),
tile,
time
)
@ -3548,61 +3564,72 @@ $.Drawer.prototype = {
},
_onTileLoad: function(tile, time, image) {
var insertionIndex,
cutoff,
worstTile,
worstTime,
worstLevel,
worstTileIndex,
prevTile,
prevTime,
prevLevel,
i;
tile.loading = false;
if (this.midUpdate) {
$.Debug.error("Tile load callback in middle of drawing routine.");
if ( this.midUpdate ) {
$.Debug.error( "Tile load callback in middle of drawing routine." );
return;
} else if (!image) {
$.Debug.log("Tile " + tile + " failed to load: " + tile.url);
} else if ( !image ) {
$.Debug.log( "Tile " + tile + " failed to load: " + tile.url );
tile.exists = false;
return;
} else if (time < this.lastResetTime) {
$.Debug.log("Ignoring tile " + tile + " loaded before reset: " + tile.url);
} else if ( time < this.lastResetTime ) {
$.Debug.log( "Ignoring tile " + tile + " loaded before reset: " + tile.url );
return;
}
tile.loaded = true;
tile.image = image;
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));
if ( this.tilesLoaded.length >= QUOTA ) {
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) {
if ( prevTile.level <= this.cutoff || prevTile.beingDrawn ) {
continue;
} else if (!worstTile) {
worstTile = prevTile;
worstTileIndex = i;
} else if ( !worstTile ) {
worstTile = prevTile;
worstTileIndex = i;
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)) {
worstTile = prevTile;
worstTileIndex = i;
if ( prevTime < worstTime ||
( prevTime == worstTime && prevLevel > worstLevel ) ) {
worstTile = prevTile;
worstTileIndex = i;
}
}
if (worstTile && worstTileIndex >= 0) {
if ( worstTile && worstTileIndex >= 0 ) {
worstTile.unload();
insertionIndex = worstTileIndex;
}
}
this.tilesLoaded[insertionIndex] = tile;
this.tilesLoaded[ insertionIndex ] = tile;
this.updateAgain = true;
},
@ -3622,18 +3649,22 @@ $.Drawer.prototype = {
* there's no content that they would need to cover. Tiles at non-existent
* levels that are within the image bounds, however, do not.
*/
_providesCoverage: function(level, x, y) {
if (!this.coverage[level]) {
_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) {
if (rows.hasOwnProperty(i)) {
var cols = rows[i];
for (var j in cols) {
if (cols.hasOwnProperty(j) && !cols[j]) {
if ( x === undefined || y === undefined ) {
rows = this.coverage[ level ];
for ( i in rows ) {
if ( rows.hasOwnProperty( i ) ) {
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 ||
this.coverage[level][x][y] === undefined ||
this.coverage[level][x][y] === true);
return (
this.coverage[ level ][ x] === undefined ||
this.coverage[ level ][ x ][ y ] === undefined ||
this.coverage[ level ][ x ][ y ] === true
);
},
/**
@ -3653,32 +3686,35 @@ $.Drawer.prototype = {
* tiles of higher resolution representing the same content. If neither x
* nor y is given, returns true if the entire visible level is covered.
*/
_isCovered: function(level, x, y) {
if (x === undefined || y === undefined) {
return this._providesCoverage(level + 1);
_isCovered: function( level, x, y ) {
if ( x === undefined || y === undefined ) {
return this._providesCoverage( level + 1 );
} else {
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));
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 )
);
}
},
/**
* Sets whether the given tile provides coverage or not.
*/
_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);
_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
);
return;
}
if (!this.coverage[level][x]) {
this.coverage[level][x] = {};
if ( !this.coverage[ level ][ x ] ) {
this.coverage[ level ][ x ] = {};
}
this.coverage[level][x][y] = covers;
this.coverage[ level ][ x ][ y ] = covers;
},
/**
@ -3686,20 +3722,20 @@ $.Drawer.prototype = {
* after every draw routine. Note that at the beginning of the next draw
* routine, coverage for every visible tile should be explicitly set.
*/
_resetCoverage: function(level) {
this.coverage[level] = {};
_resetCoverage: function( level ) {
this.coverage[ level ] = {};
},
_compareTiles: function(prevBest, tile) {
if (!prevBest) {
_compareTiles: function( prevBest, tile ) {
if ( !prevBest ) {
return tile;
}
if (tile.visibility > prevBest.visibility) {
if ( tile.visibility > prevBest.visibility ) {
return tile;
} else if (tile.visibility == prevBest.visibility) {
if (tile.distance < prevBest.distance) {
} else if ( tile.visibility == prevBest.visibility ) {
if ( tile.distance < prevBest.distance ) {
return tile;
}
}
@ -3708,9 +3744,10 @@ $.Drawer.prototype = {
},
_getOverlayIndex: function(elmt) {
for (var i = this.overlays.length - 1; i >= 0; i--) {
if (this.overlays[i].elmt == elmt) {
_getOverlayIndex: function( elmt ) {
var i;
for ( i = this.overlays.length - 1; i >= 0; i-- ) {
if ( this.overlays[ i ].elmt == elmt ) {
return i;
}
}
@ -3722,248 +3759,328 @@ $.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)) {
if ( !this.config.wrapHorizontal &&
( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
return;
} else if (!this.config.wrapVertical &&
(viewportBR.y < 0 || viewportTL.y > this.normHeight)) {
} else if ( !this.config.wrapVertical &&
( viewportBR.y < 0 || viewportTL.y > this.normHeight ) ) {
return;
}
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;
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;
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!
if ((!haveDrawn && renderPixelRatioC >= MIN_PIXEL_RATIO) ||
level == lowestLevel) {
if ( ( !haveDrawn && renderPixelRatioC >= MIN_PIXEL_RATIO ) ||
( level == lowestLevel ) ) {
drawLevel = true;
haveDrawn = true;
} else if (!haveDrawn) {
} else if ( !haveDrawn ) {
continue;
}
this._resetCoverage(level);
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);
this._setCoverage( level, x, y, false );
if (!tile.exists) {
if ( !tile.exists ) {
continue;
}
if (haveDrawn && !drawTile) {
if (this._isCovered(level, x, y)) {
this._setCoverage(level, x, y, true);
if ( haveDrawn && !drawTile ) {
if ( this._isCovered( level, x, y ) ) {
this._setCoverage( level, x, y, true );
} else {
drawTile = true;
}
}
if (!drawTile) {
if ( !drawTile ) {
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);
this._positionTile(
tile,
viewportCenter,
levelVisibility
);
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;
if (tile.loaded) {
if (!tile.blendStart) {
tile.blendStart = currentTime;
}
var deltaTime = currentTime - tile.blendStart;
var opacity = _min(1, deltaTime / blendTimeMillis);
if ( tile.loaded ) {
if (alwaysBlend) {
opacity *= levelOpacity;
}
updateAgain = this._blendTile(
tile,
x, y,
level,
levelOpacity,
currentTime
);
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) {
} else if ( tile.Loading ) {
//do nothing
} else {
best = this._compareTiles(best, tile);
best = this._compareTiles( best, tile );
}
}
}
if (this._providesCoverage(level)) {
if ( this._providesCoverage( level ) ) {
break;
}
}
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;
}
},
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
_drawOverlays: function(){
var i,
length = this.overlays.length;
for ( i = 0; i < length; i++ ) {
this._drawOverlay( this.overlays[ i ] );
}
},
_drawOverlay: function( overlay ){
var bounds = overlay.bounds;
addOverlay: function(elmt, loc, placement) {
var elmt = $.getElement(elmt);
overlay.position = this.viewport.pixelFromPoint(
bounds.getTopLeft(),
true
);
overlay.size = this.viewport.deltaPixelsFromPoints(
bounds.getSize(),
true
);
overlay.drawHTML( this.container );
},
if (this._getOverlayIndex(elmt) >= 0) {
return; // they're trying to add a duplicate overlay
addOverlay: function( element, location, placement ) {
element = $.getElement( element );
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;
if (i >= 0) {
this.overlays[i].update(loc, placement);
element = $.getElement( element );
i = this._getOverlayIndex( element );
if ( i >= 0 ) {
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;
if (i >= 0) {
this.overlays[i].destroy();
this.overlays.splice(i, 1);
element = $.getElement( element );
i = this._getOverlayIndex( element );
if ( i >= 0 ) {
this.overlays[ i ].destroy();
this.overlays.splice( i, 1 );
this.updateAgain = true;
}
},
clearOverlays: function() {
while (this.overlays.length > 0) {
while ( this.overlays.length > 0 ) {
this.overlays.pop().destroy();
this.updateAgain = true;
}

View File

@ -74,49 +74,62 @@ $.Drawer = function(source, viewport, elmt) {
$.Drawer.prototype = {
getPixelRatio: function(level) {
if (!this.cachePixelRatios[level]) {
this.cachePixelRatios[level] = this.source.getPixelRatio(level);
getPixelRatio: function( level ) {
if ( !this.cachePixelRatios[ level ] ) {
this.cachePixelRatios[ level ] = this.source.getPixelRatio( level );
}
return this.cachePixelRatios[level];
return this.cachePixelRatios[ level ];
},
_getTile: function(level, x, y, time, numTilesX, numTilesY) {
if (!this.tilesMatrix[level]) {
this.tilesMatrix[level] = {};
_getTile: function( level, x, y, time, numTilesX, numTilesY ) {
var xMod,
yMod,
bounds,
exists,
url,
tile;
if ( !this.tilesMatrix[ level ] ) {
this.tilesMatrix[ level ] = {};
}
if (!this.tilesMatrix[level][x]) {
this.tilesMatrix[level][x] = {};
if ( !this.tilesMatrix[ level ][ x ] ) {
this.tilesMatrix[ level ][ x ] = {};
}
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);
if ( !this.tilesMatrix[ level ][ x ][ y ] ) {
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;
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;
},
_loadTile: function(tile, time) {
_loadTile: function( tile, time ) {
tile.loading = this.loadImage(
tile.url,
$.createCallback(
null,
$.delegate(this, this._onTileLoad),
$.delegate( this, this._onTileLoad ),
tile,
time
)
@ -124,61 +137,72 @@ $.Drawer.prototype = {
},
_onTileLoad: function(tile, time, image) {
var insertionIndex,
cutoff,
worstTile,
worstTime,
worstLevel,
worstTileIndex,
prevTile,
prevTime,
prevLevel,
i;
tile.loading = false;
if (this.midUpdate) {
$.Debug.error("Tile load callback in middle of drawing routine.");
if ( this.midUpdate ) {
$.Debug.error( "Tile load callback in middle of drawing routine." );
return;
} else if (!image) {
$.Debug.log("Tile " + tile + " failed to load: " + tile.url);
} else if ( !image ) {
$.Debug.log( "Tile " + tile + " failed to load: " + tile.url );
tile.exists = false;
return;
} else if (time < this.lastResetTime) {
$.Debug.log("Ignoring tile " + tile + " loaded before reset: " + tile.url);
} else if ( time < this.lastResetTime ) {
$.Debug.log( "Ignoring tile " + tile + " loaded before reset: " + tile.url );
return;
}
tile.loaded = true;
tile.image = image;
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));
if ( this.tilesLoaded.length >= QUOTA ) {
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) {
if ( prevTile.level <= this.cutoff || prevTile.beingDrawn ) {
continue;
} else if (!worstTile) {
worstTile = prevTile;
worstTileIndex = i;
} else if ( !worstTile ) {
worstTile = prevTile;
worstTileIndex = i;
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)) {
worstTile = prevTile;
worstTileIndex = i;
if ( prevTime < worstTime ||
( prevTime == worstTime && prevLevel > worstLevel ) ) {
worstTile = prevTile;
worstTileIndex = i;
}
}
if (worstTile && worstTileIndex >= 0) {
if ( worstTile && worstTileIndex >= 0 ) {
worstTile.unload();
insertionIndex = worstTileIndex;
}
}
this.tilesLoaded[insertionIndex] = tile;
this.tilesLoaded[ insertionIndex ] = tile;
this.updateAgain = true;
},
@ -198,18 +222,22 @@ $.Drawer.prototype = {
* there's no content that they would need to cover. Tiles at non-existent
* levels that are within the image bounds, however, do not.
*/
_providesCoverage: function(level, x, y) {
if (!this.coverage[level]) {
_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) {
if (rows.hasOwnProperty(i)) {
var cols = rows[i];
for (var j in cols) {
if (cols.hasOwnProperty(j) && !cols[j]) {
if ( x === undefined || y === undefined ) {
rows = this.coverage[ level ];
for ( i in rows ) {
if ( rows.hasOwnProperty( i ) ) {
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 ||
this.coverage[level][x][y] === undefined ||
this.coverage[level][x][y] === true);
return (
this.coverage[ level ][ x] === undefined ||
this.coverage[ level ][ x ][ y ] === undefined ||
this.coverage[ level ][ x ][ y ] === true
);
},
/**
@ -229,32 +259,35 @@ $.Drawer.prototype = {
* tiles of higher resolution representing the same content. If neither x
* nor y is given, returns true if the entire visible level is covered.
*/
_isCovered: function(level, x, y) {
if (x === undefined || y === undefined) {
return this._providesCoverage(level + 1);
_isCovered: function( level, x, y ) {
if ( x === undefined || y === undefined ) {
return this._providesCoverage( level + 1 );
} else {
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));
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 )
);
}
},
/**
* Sets whether the given tile provides coverage or not.
*/
_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);
_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
);
return;
}
if (!this.coverage[level][x]) {
this.coverage[level][x] = {};
if ( !this.coverage[ level ][ x ] ) {
this.coverage[ level ][ x ] = {};
}
this.coverage[level][x][y] = covers;
this.coverage[ level ][ x ][ y ] = covers;
},
/**
@ -262,20 +295,20 @@ $.Drawer.prototype = {
* after every draw routine. Note that at the beginning of the next draw
* routine, coverage for every visible tile should be explicitly set.
*/
_resetCoverage: function(level) {
this.coverage[level] = {};
_resetCoverage: function( level ) {
this.coverage[ level ] = {};
},
_compareTiles: function(prevBest, tile) {
if (!prevBest) {
_compareTiles: function( prevBest, tile ) {
if ( !prevBest ) {
return tile;
}
if (tile.visibility > prevBest.visibility) {
if ( tile.visibility > prevBest.visibility ) {
return tile;
} else if (tile.visibility == prevBest.visibility) {
if (tile.distance < prevBest.distance) {
} else if ( tile.visibility == prevBest.visibility ) {
if ( tile.distance < prevBest.distance ) {
return tile;
}
}
@ -284,9 +317,10 @@ $.Drawer.prototype = {
},
_getOverlayIndex: function(elmt) {
for (var i = this.overlays.length - 1; i >= 0; i--) {
if (this.overlays[i].elmt == elmt) {
_getOverlayIndex: function( elmt ) {
var i;
for ( i = this.overlays.length - 1; i >= 0; i-- ) {
if ( this.overlays[ i ].elmt == elmt ) {
return i;
}
}
@ -298,248 +332,328 @@ $.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)) {
if ( !this.config.wrapHorizontal &&
( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
return;
} else if (!this.config.wrapVertical &&
(viewportBR.y < 0 || viewportTL.y > this.normHeight)) {
} else if ( !this.config.wrapVertical &&
( viewportBR.y < 0 || viewportTL.y > this.normHeight ) ) {
return;
}
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;
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;
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!
if ((!haveDrawn && renderPixelRatioC >= MIN_PIXEL_RATIO) ||
level == lowestLevel) {
if ( ( !haveDrawn && renderPixelRatioC >= MIN_PIXEL_RATIO ) ||
( level == lowestLevel ) ) {
drawLevel = true;
haveDrawn = true;
} else if (!haveDrawn) {
} else if ( !haveDrawn ) {
continue;
}
this._resetCoverage(level);
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);
this._setCoverage( level, x, y, false );
if (!tile.exists) {
if ( !tile.exists ) {
continue;
}
if (haveDrawn && !drawTile) {
if (this._isCovered(level, x, y)) {
this._setCoverage(level, x, y, true);
if ( haveDrawn && !drawTile ) {
if ( this._isCovered( level, x, y ) ) {
this._setCoverage( level, x, y, true );
} else {
drawTile = true;
}
}
if (!drawTile) {
if ( !drawTile ) {
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);
this._positionTile(
tile,
viewportCenter,
levelVisibility
);
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;
if (tile.loaded) {
if (!tile.blendStart) {
tile.blendStart = currentTime;
}
var deltaTime = currentTime - tile.blendStart;
var opacity = _min(1, deltaTime / blendTimeMillis);
if ( tile.loaded ) {
if (alwaysBlend) {
opacity *= levelOpacity;
}
updateAgain = this._blendTile(
tile,
x, y,
level,
levelOpacity,
currentTime
);
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) {
} else if ( tile.Loading ) {
//do nothing
} else {
best = this._compareTiles(best, tile);
best = this._compareTiles( best, tile );
}
}
}
if (this._providesCoverage(level)) {
if ( this._providesCoverage( level ) ) {
break;
}
}
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;
}
},
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
_drawOverlays: function(){
var i,
length = this.overlays.length;
for ( i = 0; i < length; i++ ) {
this._drawOverlay( this.overlays[ i ] );
}
},
_drawOverlay: function( overlay ){
var bounds = overlay.bounds;
addOverlay: function(elmt, loc, placement) {
var elmt = $.getElement(elmt);
overlay.position = this.viewport.pixelFromPoint(
bounds.getTopLeft(),
true
);
overlay.size = this.viewport.deltaPixelsFromPoints(
bounds.getSize(),
true
);
overlay.drawHTML( this.container );
},
if (this._getOverlayIndex(elmt) >= 0) {
return; // they're trying to add a duplicate overlay
addOverlay: function( element, location, placement ) {
element = $.getElement( element );
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;
if (i >= 0) {
this.overlays[i].update(loc, placement);
element = $.getElement( element );
i = this._getOverlayIndex( element );
if ( i >= 0 ) {
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;
if (i >= 0) {
this.overlays[i].destroy();
this.overlays.splice(i, 1);
element = $.getElement( element );
i = this._getOverlayIndex( element );
if ( i >= 0 ) {
this.overlays[ i ].destroy();
this.overlays.splice( i, 1 );
this.updateAgain = true;
}
},
clearOverlays: function() {
while (this.overlays.length > 0) {
while ( this.overlays.length > 0 ) {
this.overlays.pop().destroy();
this.updateAgain = true;
}

View File

@ -314,8 +314,8 @@ OpenSeadragon = window.OpenSeadragon || (function(){
$.extend( $, {
getElement: function( element ) {
if (typeof ( element ) == "string") {
getElement: function( element ) {
if ( typeof ( element ) == "string") {
element = document.getElementById( element );
}
return element;
@ -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