diff --git a/openseadragon.js b/openseadragon.js index 954d5914..3c21f698 100644 --- a/openseadragon.js +++ b/openseadragon.js @@ -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; } diff --git a/src/drawer.js b/src/drawer.js index 8e4da664..a0ff85b7 100644 --- a/src/drawer.js +++ b/src/drawer.js @@ -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; } diff --git a/src/openseadragon.js b/src/openseadragon.js index d375af86..d6fb911b 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -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