patch for #831 - simplify the notion of untiled (now an option on grid layers called 'singleTile') and implementing loading events for gridded/untiled layers. thanks tim and chris for reviewing this beast.
git-svn-id: http://svn.openlayers.org/trunk/openlayers@3725 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -29,12 +29,26 @@ OpenLayers.Layer.Grid.prototype =
|
||||
*/
|
||||
grid: null,
|
||||
|
||||
/** APIProperty: ratio
|
||||
* {Float} Used only when in single-tile mode, this specifies the
|
||||
* ratio of the size of the single tile to the size of the map.
|
||||
*/
|
||||
ratio: 1.5,
|
||||
|
||||
/**
|
||||
* APIProperty: buffer
|
||||
* {Integer}
|
||||
* {Integer} Used only when in gridded mode, this specifies the number of
|
||||
* extra rows and colums of tiles which will surround the minimum
|
||||
* grid tiles to cover the map.
|
||||
*/
|
||||
buffer: 2,
|
||||
|
||||
/**
|
||||
* APIProperty: numLoadingTiles
|
||||
* {Integer} How many tiles are still loading?
|
||||
*/
|
||||
numLoadingTiles: 0,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Layer.Grid
|
||||
* Create a new grid layer
|
||||
@@ -44,10 +58,18 @@ OpenLayers.Layer.Grid.prototype =
|
||||
* url - {String}
|
||||
* params - {Object}
|
||||
* options - {Object} Hashtable of extra options to tag onto the layer
|
||||
*/
|
||||
*/
|
||||
initialize: function(name, url, params, options) {
|
||||
OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
|
||||
arguments);
|
||||
|
||||
//grid layers will trigger 'tileloaded' when each new tile is
|
||||
// loaded, as a means of progress update to listeners.
|
||||
// listeners can access 'numLoadingTiles' if they wish to keep track
|
||||
// of the loading progress
|
||||
//
|
||||
this.events.addEventType("tileloaded");
|
||||
|
||||
this.grid = new Array();
|
||||
},
|
||||
|
||||
@@ -72,7 +94,9 @@ OpenLayers.Layer.Grid.prototype =
|
||||
for(var iRow=0; iRow < this.grid.length; iRow++) {
|
||||
var row = this.grid[iRow];
|
||||
for(var iCol=0; iCol < row.length; iCol++) {
|
||||
row[iCol].destroy();
|
||||
var tile = row[iCol];
|
||||
this.removeTileMonitoringHooks(tile);
|
||||
tile.destroy();
|
||||
}
|
||||
}
|
||||
this.grid = [];
|
||||
@@ -112,21 +136,6 @@ OpenLayers.Layer.Grid.prototype =
|
||||
return obj;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: setMap
|
||||
* When the layer is added to a map, then we can ask the map for
|
||||
* its default tile size
|
||||
*
|
||||
* Parameters:
|
||||
* map - {<OpenLayers.Map>}
|
||||
*/
|
||||
setMap: function(map) {
|
||||
OpenLayers.Layer.HTTPRequest.prototype.setMap.apply(this, arguments);
|
||||
if (this.tileSize == null) {
|
||||
this.tileSize = this.map.getTileSize();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: moveTo
|
||||
* This function is called whenever the map is moved. All the moving
|
||||
@@ -141,48 +150,78 @@ OpenLayers.Layer.Grid.prototype =
|
||||
moveTo:function(bounds, zoomChanged, dragging) {
|
||||
OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
|
||||
|
||||
if (bounds == null) {
|
||||
bounds = this.map.getExtent();
|
||||
}
|
||||
bounds = bounds || this.map.getExtent();
|
||||
|
||||
if (bounds != null) {
|
||||
if (!this.grid.length || zoomChanged
|
||||
|| !this.getGridBounds().containsBounds(bounds, true)) {
|
||||
this._initTiles();
|
||||
|
||||
// if grid is empty or zoom has changed, we *must* re-tile
|
||||
var forceReTile = !this.grid.length || zoomChanged;
|
||||
|
||||
// total bounds of the tiles
|
||||
var tilesBounds = this.getTilesBounds();
|
||||
|
||||
if (this.singleTile) {
|
||||
|
||||
// We want to redraw whenever even the slightest part of the
|
||||
// current bounds is not contained by our tile.
|
||||
// (thus, we do not specify partial -- its default is false)
|
||||
if ( forceReTile ||
|
||||
(!dragging && !tilesBounds.containsBounds(bounds))) {
|
||||
this.initSingleTile(bounds);
|
||||
}
|
||||
} else {
|
||||
var buffer = (this.buffer) ? this.buffer*1.5 : 1;
|
||||
while (true) {
|
||||
var tlLayer = this.grid[0][0].position;
|
||||
var tlViewPort =
|
||||
this.map.getViewPortPxFromLayerPx(tlLayer);
|
||||
if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
|
||||
this.shiftColumn(true);
|
||||
} else if (tlViewPort.x < -this.tileSize.w * buffer) {
|
||||
this.shiftColumn(false);
|
||||
} else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
|
||||
this.shiftRow(true);
|
||||
} else if (tlViewPort.y < -this.tileSize.h * buffer) {
|
||||
this.shiftRow(false);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
if (this.buffer == 0) {
|
||||
for (var r=0, rl=this.grid.length; r<rl; r++) {
|
||||
var row = this.grid[r];
|
||||
for (var c=0, cl=row.length; c<cl; c++) {
|
||||
var tile = row[c];
|
||||
if (!tile.drawn && tile.bounds.intersectsBounds(bounds, false)) {
|
||||
tile.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the bounds have changed such that they are not even
|
||||
// *partially* contained by our tiles (IE user has
|
||||
// programmatically panned to the other side of the earth)
|
||||
// then we want to reTile (thus, partial true).
|
||||
//
|
||||
if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
|
||||
this.initGriddedTiles(bounds);
|
||||
} else {
|
||||
//we might have to shift our buffer tiles
|
||||
this.moveGriddedTiles(bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: setTileSize
|
||||
* Check if we are in singleTile mode and if so, set the size as a ratio
|
||||
* of the map size (as specified by the layer's 'ratio' property).
|
||||
*
|
||||
* Parameters:
|
||||
* size - {<OpenLayers.Size>}
|
||||
*/
|
||||
setTileSize: function(size) {
|
||||
if (this.singleTile) {
|
||||
var size = this.map.getSize().clone();
|
||||
size.h = size.h * this.ratio;
|
||||
size.w = size.w * this.ratio;
|
||||
}
|
||||
OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: getGridBounds
|
||||
* Deprecated. This function will be removed in 3.0. Please use
|
||||
* getTilesBounds() instead.
|
||||
*
|
||||
* Return:
|
||||
* {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
|
||||
* currently loaded tiles (including those partially or not at all seen
|
||||
* onscreen)
|
||||
*/
|
||||
getGridBounds: function() {
|
||||
var msg = "The getGridBounds() function is deprecated. It will be " +
|
||||
"removed in 3.0. Please use getTilesBounds() instead.";
|
||||
OpenLayers.Console.warn(msg);
|
||||
return getTilesBounds();
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: getTilesBounds
|
||||
* Get the bounds of the grid
|
||||
*
|
||||
* Return:
|
||||
@@ -190,33 +229,80 @@ OpenLayers.Layer.Grid.prototype =
|
||||
* currently loaded tiles (including those partially or not at all seen
|
||||
* onscreen)
|
||||
*/
|
||||
getGridBounds:function() {
|
||||
getTilesBounds: function() {
|
||||
var bounds = null;
|
||||
|
||||
var bottom = this.grid.length - 1;
|
||||
var bottomLeftTile = this.grid[bottom][0];
|
||||
|
||||
var right = this.grid[0].length - 1;
|
||||
var topRightTile = this.grid[0][right];
|
||||
|
||||
return new OpenLayers.Bounds(bottomLeftTile.bounds.left,
|
||||
bottomLeftTile.bounds.bottom,
|
||||
topRightTile.bounds.right,
|
||||
topRightTile.bounds.top);
|
||||
if (this.grid.length) {
|
||||
var bottom = this.grid.length - 1;
|
||||
var bottomLeftTile = this.grid[bottom][0];
|
||||
|
||||
var right = this.grid[0].length - 1;
|
||||
var topRightTile = this.grid[0][right];
|
||||
|
||||
bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left,
|
||||
bottomLeftTile.bounds.bottom,
|
||||
topRightTile.bounds.right,
|
||||
topRightTile.bounds.top);
|
||||
|
||||
}
|
||||
return bounds;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: _initTiles
|
||||
* Initialize the tiles
|
||||
* Method: initSingleTile
|
||||
*
|
||||
* Parameters:
|
||||
* bounds - {<OpenLayers.Bounds>}
|
||||
*/
|
||||
_initTiles:function() {
|
||||
initSingleTile: function(bounds) {
|
||||
|
||||
//determine new tile bounds
|
||||
var center = bounds.getCenterLonLat();
|
||||
var tileWidth = bounds.getWidth() * this.ratio;
|
||||
var tileHeight = bounds.getHeight() * this.ratio;
|
||||
|
||||
var tileBounds =
|
||||
new OpenLayers.Bounds(center.lon - (tileWidth/2),
|
||||
center.lat - (tileHeight/2),
|
||||
center.lon + (tileWidth/2),
|
||||
center.lat + (tileHeight/2));
|
||||
|
||||
var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
|
||||
var px = this.map.getLayerPxFromLonLat(ul);
|
||||
|
||||
if (!this.grid.length) {
|
||||
this.grid[0] = new Array();
|
||||
}
|
||||
|
||||
var tile = this.grid[0][0];
|
||||
if (!tile) {
|
||||
tile = this.addTile(tileBounds, px);
|
||||
|
||||
this.addTileMonitoringHooks(tile);
|
||||
tile.draw();
|
||||
this.grid[0][0] = tile;
|
||||
} else {
|
||||
tile.moveTo(tileBounds, px);
|
||||
}
|
||||
|
||||
//remove all but our single tile
|
||||
this.removeExcessTiles(1,1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: initGriddedTiles
|
||||
*
|
||||
* Parameters:
|
||||
* bounds - {<OpenLayers.Bounds>}
|
||||
*/
|
||||
initGriddedTiles:function(bounds) {
|
||||
|
||||
// work out mininum number of rows and columns; this is the number of
|
||||
// tiles required to cover the viewport plus one for panning
|
||||
var viewSize = this.map.getSize();
|
||||
var minRows = Math.ceil(viewSize.h/this.tileSize.h) + 1;
|
||||
var minCols = Math.ceil(viewSize.w/this.tileSize.w) + 1;
|
||||
|
||||
var bounds = this.map.getExtent();
|
||||
var extent = this.map.getMaxExtent();
|
||||
var resolution = this.map.getResolution();
|
||||
var tilelon = resolution * this.tileSize.w;
|
||||
@@ -256,10 +342,11 @@ OpenLayers.Layer.Grid.prototype =
|
||||
var colidx = 0;
|
||||
|
||||
do {
|
||||
var tileBounds = new OpenLayers.Bounds(tileoffsetlon,
|
||||
tileoffsetlat,
|
||||
tileoffsetlon + tilelon,
|
||||
tileoffsetlat + tilelat);
|
||||
var tileBounds =
|
||||
new OpenLayers.Bounds(tileoffsetlon,
|
||||
tileoffsetlat,
|
||||
tileoffsetlon + tilelon,
|
||||
tileoffsetlat + tilelat);
|
||||
|
||||
var x = tileoffsetx;
|
||||
x -= parseInt(this.map.layerContainerDiv.style.left);
|
||||
@@ -271,6 +358,7 @@ OpenLayers.Layer.Grid.prototype =
|
||||
var tile = row[colidx++];
|
||||
if (!tile) {
|
||||
tile = this.addTile(tileBounds, px);
|
||||
this.addTileMonitoringHooks(tile);
|
||||
row.push(tile);
|
||||
} else {
|
||||
tile.moveTo(tileBounds, px, false);
|
||||
@@ -286,23 +374,9 @@ OpenLayers.Layer.Grid.prototype =
|
||||
} while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
|
||||
|| rowidx < minRows)
|
||||
|
||||
// remove extra rows
|
||||
while (this.grid.length > rowidx) {
|
||||
var row = this.grid.pop();
|
||||
for (var i=0, l=row.length; i<l; i++) {
|
||||
row[i].destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// remove extra columns
|
||||
while (this.grid[0].length > colidx) {
|
||||
for (var i=0, l=this.grid.length; i<l; i++) {
|
||||
var row = this.grid[i];
|
||||
var tile = row.pop();
|
||||
tile.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
//shave off exceess rows and colums
|
||||
this.removeExcessTiles(rowidx, colidx);
|
||||
|
||||
//now actually draw the tiles
|
||||
this.spiralTileLoad();
|
||||
},
|
||||
@@ -396,6 +470,87 @@ OpenLayers.Layer.Grid.prototype =
|
||||
// Should be implemented by subclasses
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: addTileMonitoringHooks
|
||||
* This function takes a tile as input and adds the appropriate hooks to
|
||||
* the tile so that the layer can keep track of the loading tiles.
|
||||
*
|
||||
* Parameters:
|
||||
* tile - {<OpenLayers.Tile>}
|
||||
*/
|
||||
addTileMonitoringHooks: function(tile) {
|
||||
|
||||
tile.onLoadStart = function() {
|
||||
//if that was first tile then trigger a 'loadstart' on the layer
|
||||
if (this.numLoadingTiles == 0) {
|
||||
this.events.triggerEvent("loadstart");
|
||||
}
|
||||
this.numLoadingTiles++;
|
||||
};
|
||||
tile.events.register("loadstart", this, tile.onLoadStart);
|
||||
|
||||
tile.onLoadEnd = function() {
|
||||
this.numLoadingTiles--;
|
||||
this.events.triggerEvent("tileloaded");
|
||||
//if that was the last tile, then trigger a 'loadend' on the layer
|
||||
if (this.numLoadingTiles == 0) {
|
||||
this.events.triggerEvent("loadend");
|
||||
}
|
||||
};
|
||||
tile.events.register("loadend", this, tile.onLoadEnd);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: removeTileMonitoringHooks
|
||||
* This function takes a tile as input and removes the tile hooks
|
||||
* that were added in addTileMonitoringHooks()
|
||||
*
|
||||
* Parameters:
|
||||
* tile - {<OpenLayers.Tile>}
|
||||
*/
|
||||
removeTileMonitoringHooks: function(tile) {
|
||||
tile.events.unregister("loadstart", this, tile.onLoadStart);
|
||||
tile.events.unregister("loadend", this, tile.onLoadEnd);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: moveGriddedTiles
|
||||
*
|
||||
* Parameters:
|
||||
* bounds - {<OpenLayers.Bounds>}
|
||||
*/
|
||||
moveGriddedTiles: function(bounds) {
|
||||
var buffer = (this.buffer) ? this.buffer*1.5 : 1;
|
||||
while (true) {
|
||||
var tlLayer = this.grid[0][0].position;
|
||||
var tlViewPort =
|
||||
this.map.getViewPortPxFromLayerPx(tlLayer);
|
||||
if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
|
||||
this.shiftColumn(true);
|
||||
} else if (tlViewPort.x < -this.tileSize.w * buffer) {
|
||||
this.shiftColumn(false);
|
||||
} else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
|
||||
this.shiftRow(true);
|
||||
} else if (tlViewPort.y < -this.tileSize.h * buffer) {
|
||||
this.shiftRow(false);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
if (this.buffer == 0) {
|
||||
for (var r=0, rl=this.grid.length; r<rl; r++) {
|
||||
var row = this.grid[r];
|
||||
for (var c=0, cl=row.length; c<cl; c++) {
|
||||
var tile = row[c];
|
||||
if (!tile.drawn &&
|
||||
tile.bounds.intersectsBounds(bounds, false)) {
|
||||
tile.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: shiftRow
|
||||
* Shifty grid work
|
||||
@@ -465,6 +620,38 @@ OpenLayers.Layer.Grid.prototype =
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: removeExcessTiles
|
||||
* When the size of the map or the buffer changes, we may need to
|
||||
* remove some excess rows and columns.
|
||||
*
|
||||
* Parameters:
|
||||
* rows - {Integer} Maximum number of rows we want our grid to have.
|
||||
* colums - {Integer} Maximum number of columns we want our grid to have.
|
||||
*/
|
||||
removeExcessTiles: function(rows, columns) {
|
||||
|
||||
// remove extra rows
|
||||
while (this.grid.length > rows) {
|
||||
var row = this.grid.pop();
|
||||
for (var i=0, l=row.length; i<l; i++) {
|
||||
var tile = row[i];
|
||||
this.removeTileMonitoringHooks(tile)
|
||||
tile.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// remove extra columns
|
||||
while (this.grid[0].length > columns) {
|
||||
for (var i=0, l=this.grid.length; i<l; i++) {
|
||||
var row = this.grid[i];
|
||||
var tile = row.pop();
|
||||
this.removeTileMonitoringHooks(tile);
|
||||
tile.destroy();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** @final @type String */
|
||||
CLASS_NAME: "OpenLayers.Layer.Grid"
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user