Commit tile-reuse branch back to trunk. This branch offers numerous performance

improvements in the form of reduced memory use and lower element creating costs,
hopefully making the OpenLayers code more usable in internet explorer as well
as less of a memory hog in Firefox and other browsers. Additionally, a buffer
is available around the main map grid which allows tiles to be loaded outside
of the viewing area for faster dragging.


git-svn-id: http://svn.openlayers.org/trunk/openlayers@1137 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
crschmidt
2006-08-09 03:47:33 +00:00
parent 51ac2b4acf
commit 0ba7961df4
9 changed files with 194 additions and 105 deletions

View File

@@ -26,6 +26,10 @@ OpenLayers.Control.LayerSwitcher.prototype =
/** @type Array */
baseLayerInputs: null,
/** @type DOMElement */
dataLbl: null,
/** @type DOMElement */
dataLayersDiv: null,
@@ -223,8 +227,6 @@ OpenLayers.Control.LayerSwitcher.prototype =
this.div.style.width = "0px";
this.div.style.height = "0px";
// this.div.style.backgroundColor = "transparent";
this.showControls(true);
if (e != null) {
@@ -331,7 +333,7 @@ OpenLayers.Control.LayerSwitcher.prototype =
// maximize button div
var img = imgLocation + 'layer-switcher-maximize.png';
this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
"OpenLayers_Control_ResizeDiv",
"OpenLayers_Control_MaximizeDiv",
null,
sz,
img,
@@ -350,7 +352,7 @@ OpenLayers.Control.LayerSwitcher.prototype =
var img = imgLocation + 'layer-switcher-minimize.png';
var sz = new OpenLayers.Size(18,18);
this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
"OpenLayers_Control_ResizeDiv",
"OpenLayers_Control_MinimizeDiv",
null,
sz,
img,

View File

@@ -30,6 +30,11 @@ OpenLayers.Layer.prototype = {
*/
isBaseLayer: false,
/** asserts whether or not the layer's images have an alpha channel
*
* @type boolean */
alpha: false,
// OPTIONS
/** @type Array */

View File

@@ -20,11 +20,8 @@ OpenLayers.Layer.Grid.prototype =
* @type Array(Array) */
grid: null,
/** asserts whether or not the layer's images have an alpha channel
*
* @type boolean */
alpha: false,
/** @type Integer */
buffer: 2,
/**
* @constructor
@@ -37,6 +34,7 @@ OpenLayers.Layer.Grid.prototype =
initialize: function(name, url, params, options) {
OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
arguments);
this.grid = new Array();
},
/** on destroy, clear the grid.
@@ -132,37 +130,33 @@ OpenLayers.Layer.Grid.prototype =
*
* @param {OpenLayers.Bounds} bounds
* @param {Boolean} zoomChanged
* @param {Boolean} minor
* @param {Boolean} dragging
*/
moveTo:function(bounds, zoomChanged, minor) {
moveTo:function(bounds, zoomChanged, dragging) {
if (bounds == null) {
bounds = this.map.getExtent();
}
if (bounds != null) {
if (!this.getVisibility()) {
if (zoomChanged) {
//now clear out the old grid and start a new one
this.clearGrid();
this.grid = null;
// FIX ME FIX ME FIX ME -- should be this.hideGrid() basically
}
} else {
if (!this.grid || zoomChanged) {
this._initTiles();
} else if (this.getGridBounds().containsBounds(bounds, true) == false) {
} else if (!this.grid.length || zoomChanged
|| !this.getGridBounds().containsBounds(bounds, true)) {
this._initTiles();
} else {
var i = 0;
while (this.getGridBounds().bottom > bounds.bottom) {
this.insertRow(false);
}
while (this.getGridBounds().left > bounds.left) {
this.insertColumn(true);
}
while (this.getGridBounds().top < bounds.top) {
this.insertRow(true);
}
while (this.getGridBounds().right < bounds.right) {
this.insertColumn(false);
while (true) {
var topLeft = this.map.getViewPortPxFromLayerPx( this.grid[0][0].position );
if (topLeft.x > -this.tileSize.w * (this.buffer - 1)) {
this.shiftColumn(true);
} else if (topLeft.x < -this.tileSize.w * this.buffer) {
this.shiftColumn(false);
} else if (topLeft.y > -this.tileSize.w * (this.buffer - 1)) {
this.shiftRow(true);
} else if (topLeft.y < -this.tileSize.h * this.buffer) {
this.shiftRow(false);
} else {
break;
}
}
}
@@ -193,14 +187,6 @@ OpenLayers.Layer.Grid.prototype =
*
*/
_initTiles:function() {
//first of all, clear out the main div
this.div.innerHTML = "";
//now clear out the old grid and start a new one
this.clearGrid();
this.grid = new Array();
var viewSize = this.map.getSize();
var bounds = this.map.getExtent();
var extent = this.map.getMaxExtent();
@@ -209,13 +195,13 @@ OpenLayers.Layer.Grid.prototype =
var tilelat = resolution * this.tileSize.h;
var offsetlon = bounds.left - extent.left;
var tilecol = Math.floor(offsetlon/tilelon);
var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
var tilecolremain = offsetlon/tilelon - tilecol;
var tileoffsetx = -tilecolremain * this.tileSize.w;
var tileoffsetlon = extent.left + tilecol * tilelon;
var offsetlat = bounds.top - (extent.bottom + tilelat);
var tilerow = Math.ceil(offsetlat/tilelat);
var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
var tilerowremain = tilerow - offsetlat/tilelat;
var tileoffsety = -tilerowremain * this.tileSize.h;
var tileoffsetlat = extent.bottom + tilerow * tilelat;
@@ -228,12 +214,24 @@ OpenLayers.Layer.Grid.prototype =
var startX = tileoffsetx;
var startLon = tileoffsetlon;
var newGrid = (this.grid.length == 0);
var rowidx = 0;
do {
var row = new Array();
var row;
if (newGrid) {
row = new Array();
this.grid.push(row);
} else {
row = this.grid[rowidx++];
}
tileoffsetlon = startLon;
tileoffsetx = startX;
var colidx = 0;
do {
var tileBounds = new OpenLayers.Bounds(tileoffsetlon,
tileoffsetlat,
@@ -247,19 +245,24 @@ OpenLayers.Layer.Grid.prototype =
y -= parseInt(this.map.layerContainerDiv.style.top);
var px = new OpenLayers.Pixel(x, y);
var tile;
var tile = this.addTile(tileBounds, px);
tile.draw(this.alpha);
if (newGrid) {
tile = this.addTile(tileBounds, px);
tile.draw();
row.push(tile);
} else {
tile = row[colidx++];
tile.moveTo(tileBounds, px);
}
tileoffsetlon += tilelon;
tileoffsetx += this.tileSize.w;
} while (tileoffsetlon < bounds.right)
} while (tileoffsetlon <= bounds.right + tilelon * this.buffer)
tileoffsetlat -= tilelat;
tileoffsety += this.tileSize.h;
} while(tileoffsetlat > bounds.bottom - tilelat)
} while(tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
},
@@ -376,16 +379,16 @@ OpenLayers.Layer.Grid.prototype =
* @param {Boolean} prepend if true, prepend to beginning.
* if false, then append to end
*/
insertRow:function(prepend) {
shiftRow:function(prepend) {
var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
var modelRow = this.grid[modelRowIndex];
var newRow = new Array();
var resolution = this.map.getResolution();
var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
var deltaLat = resolution * -deltaY;
var row = (prepend) ? this.grid.pop() : this.grid.shift();
for (var i=0; i < modelRow.length; i++) {
var modelTile = modelRow[i];
var bounds = modelTile.bounds.clone();
@@ -393,17 +396,13 @@ OpenLayers.Layer.Grid.prototype =
bounds.bottom = bounds.bottom + deltaLat;
bounds.top = bounds.top + deltaLat;
position.y = position.y + deltaY;
var newTile = this.addTile(bounds, position);
newTile.draw(this.alpha);
newRow.push(newTile);
row[i].moveTo(bounds, position);
}
if (newRow.length>0){
if (prepend) {
this.grid.unshift(newRow);
this.grid.unshift(row);
} else {
this.grid.push(newRow);
}
this.grid.push(row);
}
},
@@ -413,15 +412,14 @@ OpenLayers.Layer.Grid.prototype =
* @param {Boolean} prepend if true, prepend to beginning.
* if false, then append to end
*/
insertColumn:function(prepend) {
var modelCellIndex;
shiftColumn: function(prepend) {
var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
var resolution = this.map.getResolution();
var deltaLon = resolution * deltaX;
for (var i=0; i<this.grid.length; i++) {
var row = this.grid[i];
modelTileIndex = (prepend) ? 0 : (row.length - 1);
var modelTileIndex = (prepend) ? 0 : (row.length - 1);
var modelTile = row[modelTileIndex];
var bounds = modelTile.bounds.clone();
@@ -429,13 +427,13 @@ OpenLayers.Layer.Grid.prototype =
bounds.left = bounds.left + deltaLon;
bounds.right = bounds.right + deltaLon;
position.x = position.x + deltaX;
var newTile = this.addTile(bounds, position);
newTile.draw(this.alpha);
var tile = prepend ? this.grid[i].pop() : this.grid[i].shift()
tile.moveTo(bounds, position);
if (prepend) {
row = row.unshift(newTile);
this.grid[i].unshift(tile);
} else {
row = row.push(newTile);
this.grid[i].push(tile);
}
}
},

View File

@@ -44,7 +44,8 @@ OpenLayers.Layer.KaMap.prototype =
);
}
},
addTile:function(bounds,position) {
getURL:function(bounds) {
var zoom = this.map.getZoom();
var maxRes = this.map.maxResolution;
var mapRes = this.map.getResolution();
@@ -53,14 +54,19 @@ OpenLayers.Layer.KaMap.prototype =
var cellSize = new OpenLayers.Size(mapRes*this.tileSize.w, mapRes*this.tileSize.h);
var pX = Math.round(((bounds.left) / cellSize.w) * this.tileSize.w);
var pY = -Math.round(((bounds.top) / cellSize.h) * this.tileSize.h);
var url = this.getFullRequestString(
return this.getFullRequestString(
{ t: pY,
l: pX,
s: scale
});
},
addTile:function(bounds,position) {
var url = this.getURL(bounds);
return new OpenLayers.Tile.Image(this, position, bounds,
url, this.tileSize);
},
_initTiles:function() {
//first of all, clear out the main div
@@ -112,7 +118,7 @@ OpenLayers.Layer.KaMap.prototype =
new OpenLayers.Pixel(tileoffsetx - parseInt(this.map.layerContainerDiv.style.left),
tileoffsety - parseInt(this.map.layerContainerDiv.style.top))
);
tile.draw((this.alpha));
tile.draw();
row.push(tile);
tileoffsetlon += tilelon;

View File

@@ -83,6 +83,13 @@ OpenLayers.Layer.WMS.prototype =
return obj;
},
getURL: function (bounds) {
return this.getFullRequestString(
{BBOX:bounds.toBBOX(),
WIDTH:this.tileSize.w,
HEIGHT:this.tileSize.h});
},
/**
* addTile creates a tile, initializes it, and
* adds it to the layer div.
@@ -93,16 +100,11 @@ OpenLayers.Layer.WMS.prototype =
* @type OpenLayers.Tile.Image
*/
addTile:function(bounds,position) {
url = this.getFullRequestString(
{BBOX:bounds.toBBOX(),
WIDTH:this.tileSize.w,
HEIGHT:this.tileSize.h});
url = this.getURL(bounds);
return new OpenLayers.Tile.Image(this, position, bounds,
url, this.tileSize);
},
/**
* Catch changeParams and uppercase the new params to be merged in
* before calling changeParams on the super class.

View File

@@ -38,18 +38,9 @@ OpenLayers.Layer.WorldWind.prototype =
}
},
addTile:function(bounds,position) {
var zoom = this.map.getZoom();
var extent = this.map.getMaxExtent();
zoom = zoom - Math.log(this.map.maxResolution / (this.lzd/512))/Math.log(2);
if (this.map.getResolution() <= (this.lzd/512) && zoom <= this.zoomLevels) {
var deg = this.lzd/Math.pow(2,zoom);
var x = Math.floor((bounds.left - extent.left)/deg);
var y = Math.floor((bounds.bottom - extent.bottom)/deg);
var url = this.getFullRequestString(
{ L: zoom,
X: x,
Y: y
});
if (this.map.getResolution() <= (this.lzd/512)
&& this.getZoom() <= this.zoomLevels) {
return new OpenLayers.Tile.Image(this, position, bounds,
url, this.tileSize);
} else {
@@ -62,6 +53,25 @@ OpenLayers.Layer.WorldWind.prototype =
}
},
getZoom: function () {
var zoom = this.map.getZoom();
var extent = this.map.getMaxExtent();
zoom = zoom - Math.log(this.map.maxResolution / (this.lzd/512))/Math.log(2);
return zoom;
},
getURL: function (bounds) {
var deg = this.lzd/Math.pow(2,this.getZoom());
var x = Math.floor((bounds.left - extent.left)/deg);
var y = Math.floor((bounds.bottom - extent.bottom)/deg);
return this.getFullRequestString(
{ L: zoom,
X: x,
Y: y
});
},
/** @final @type String */
CLASS_NAME: "OpenLayers.Layer.WorldWind"
});

View File

@@ -73,6 +73,17 @@ OpenLayers.Tile.prototype = {
},
redraw: function () {
this.draw();
},
moveTo: function (bounds, position) {
this.bounds = bounds.clone();
this.position = position.clone();
this.redraw();
},
/** remove this tile from the ds
*/
remove:function() {

View File

@@ -10,7 +10,7 @@ OpenLayers.Tile.Image.prototype =
Object.extend( new OpenLayers.Tile(), {
/** @type DOMElement img */
imgDiv:null,
imgDiv: null,
/**
* @constructor
@@ -35,23 +35,45 @@ OpenLayers.Tile.Image.prototype =
/**
*/
draw:function(transparent) {
if (transparent) {
draw:function() {
if (this.layer.alpha) {
this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
this.position,
this.size,
this.url,
"absolute");
"absolute",
null,
null,
true);
} else {
this.imgDiv = OpenLayers.Util.createImage(null,
this.position,
this.size,
this.url,
"absolute");
"absolute",
null,
true);
}
this.layer.div.appendChild(this.imgDiv);
},
moveTo: function (bounds, position) {
this.url = this.layer.getURL(bounds);
OpenLayers.Tile.prototype.moveTo.apply(this, arguments);
},
redraw: function () {
this.imgDiv.style.display = "none";
if (this.layer.alpha) {
OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
null, this.position, this.size, this.url);
} else {
this.imgDiv.src = this.url;
OpenLayers.Util.modifyDOMElement(this.imgDiv,
null, this.position, this.size) ;
}
},
/** @final @type String */
CLASS_NAME: "OpenLayers.Tile.Image"
}

View File

@@ -773,14 +773,25 @@ OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position,
* @param {String} imgURL
* @param {String} position
* @param {String} border
* @param {Boolean} delayDisplay
*
* @returns A DOM Image created with the specified attributes.
* @type DOMElement
*/
OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border) {
OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
delayDisplay) {
image = document.createElement("img");
if(delayDisplay) {
image.style.display = "none";
Event.observe(image, "load",
OpenLayers.Util.onImageLoad.bindAsEventListener(image));
Event.observe(image, "error",
OpenLayers.Util.onImageLoadError.bindAsEventListener(image));
}
//set special properties
image.style.alt = id;
image.galleryImg = "no";
@@ -797,9 +808,21 @@ OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border) {
}
OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, border);
return image;
};
OpenLayers.Util.onImageLoad = function() {
this.style.backgroundColor = null;
this.style.display = "";
};
OpenLayers.Util.onImageLoadError = function() {
this.style.backgroundColor = "pink";
};
OpenLayers.Util.alphaHack = function() {
var arVersion = navigator.appVersion.split("MSIE");
var version = parseFloat(arVersion[1]);
@@ -852,18 +875,28 @@ OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL,
* @param {String} position
* @param {String} border
* @param {String} sizing 'crop', 'scale', or 'image'. Default is "scale"
* @param {Boolean} delayDisplay
*
* @returns A DOM Div created with a DOM Image inside it. If the hack is
* needed for transparency in IE, it is added.
* @type DOMElement
*/
OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL,
position, border, sizing) {
position, border, sizing, delayDisplay) {
var div = OpenLayers.Util.createDiv();
var img = OpenLayers.Util.createImage();
var img = OpenLayers.Util.createImage(null, null, null, null, null, null,
false);
div.appendChild(img);
if (delayDisplay) {
img.style.display = "none";
Event.observe(img, "load",
OpenLayers.Util.onImageLoad.bindAsEventListener(div));
Event.observe(img, "error",
OpenLayers.Util.onImageLoadError.bindAsEventListener(div));
}
OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL,
position, border, sizing);