1 /* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
2 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
3 * text of the license. */
4 // @require: OpenLayers/Layer.js
5 // @require: OpenLayers/Util.js
6 OpenLayers.Layer.Grid = Class.create();
7 OpenLayers.Layer.Grid.TILE_WIDTH = 256;
8 OpenLayers.Layer.Grid.TILE_HEIGHT = 256;
9 OpenLayers.Layer.Grid.prototype = Object.extend( new OpenLayers.Layer(), {
17 // tileSize: OpenLayers.Size
20 // grid: Array(Array())
21 // this is an array of rows, each row is an array of tiles
27 * @param {hash} params
29 initialize: function(name, url, params) {
30 var newArguments = arguments;
31 if (arguments.length > 0) {
32 newArguments = [name];
34 OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
37 this.tileSize = new OpenLayers.Size(OpenLayers.Layer.Grid.TILE_WIDTH,
38 OpenLayers.Layer.Grid.TILE_HEIGHT);
48 OpenLayers.Layer.prototype.destroy.apply(this, arguments);
51 setTileSize: function (size) {
52 this.tileSize = size.copyOf();
57 * moveTo is a function called whenever the map is moved. All the moving
58 * of actual 'tiles' is done by the map, but moveTo's role is to accept
59 * a bounds and make sure the data that that bounds requires is pre-loaded.
60 * @param {OpenLayers.Bounds}
62 moveTo:function(bounds,zoomChanged) {
63 if (!this.getVisibility()) {
69 if (!this.grid || zoomChanged) {
73 while (this.getGridBounds().bottom > bounds.bottom) {
74 this.insertRow(false);
76 while (this.getGridBounds().left > bounds.left) {
77 this.insertColumn(true);
79 while (this.getGridBounds().top < bounds.top) {
82 while (this.getGridBounds().right < bounds.right) {
83 this.insertColumn(false);
87 getGridBounds:function() {
88 var topLeftTile = this.grid[0][0];
89 var bottomRightTile = this.grid[this.grid.length-1][this.grid[0].length-1];
90 return new OpenLayers.Bounds(topLeftTile.bounds.left,
91 bottomRightTile.bounds.bottom,
92 bottomRightTile.bounds.right,
93 topLeftTile.bounds.top);
98 _initTiles:function() {
100 //first of all, clear out the main div
101 this.div.innerHTML = "";
103 //now clear out the old grid and start a new one
105 this.grid = new Array();
107 var viewSize = this.map.getSize();
108 var bounds = this.map.getExtent();
109 var extent = this.map.getFullExtent();
110 var resolution = this.map.getResolution();
111 var tilelon = resolution*this.tileSize.w;
112 var tilelat = resolution*this.tileSize.h;
114 var offsetlon = bounds.left - extent.left;
115 var tilecol = Math.floor(offsetlon/tilelon);
116 var tilecolremain = offsetlon/tilelon - tilecol;
117 var tileoffsetx = -tilecolremain * this.tileSize.w;
118 var tileoffsetlon = extent.left + tilecol * tilelon;
120 var offsetlat = bounds.top - (extent.bottom + tilelat);
121 var tilerow = Math.ceil(offsetlat/tilelat);
122 var tilerowremain = tilerow - offsetlat/tilelat;
123 var tileoffsety = -tilerowremain * this.tileSize.h;
124 var tileoffsetlat = extent.bottom + tilerow * tilelat;
126 tileoffsetx = Math.round(tileoffsetx); // heaven help us
127 tileoffsety = Math.round(tileoffsety);
129 this.origin = new OpenLayers.Pixel(tileoffsetx,tileoffsety);
131 var startX = tileoffsetx;
132 var startLon = tileoffsetlon;
135 var row = new Array();
136 this.grid.append(row);
137 tileoffsetlon = startLon;
138 tileoffsetx = startX;
140 var tileBounds = new OpenLayers.Bounds(tileoffsetlon,
142 tileoffsetlon+tilelon,
143 tileoffsetlat+tilelat);
145 var tile = this.addTile(tileBounds,
146 new OpenLayers.Pixel(tileoffsetx - parseInt(this.map.layerContainerDiv.style.left),
147 tileoffsety - parseInt(this.map.layerContainerDiv.style.top))
149 tile.draw((this.params.TRANSPARENT == 'true'));
152 tileoffsetlon += tilelon;
153 tileoffsetx += this.tileSize.w;
154 } while (tileoffsetlon < bounds.right)
156 tileoffsetlat -= tilelat;
157 tileoffsety += this.tileSize.h;
158 } while(tileoffsetlat > bounds.bottom - tilelat)
163 * @param {bool} prepend - if true, prepend to beginning.
164 * if false, then append to end
166 insertRow:function(prepend) {
167 var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
168 var modelRow = this.grid[modelRowIndex];
170 var newRow = new Array();
172 var resolution = this.map.getResolution();
173 var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
174 var deltaLat = resolution * -deltaY;
176 for (var i=0; i < modelRow.length; i++) {
177 var modelTile = modelRow[i];
178 var bounds = modelTile.bounds.copyOf();
179 var position = modelTile.position.copyOf();
180 bounds.bottom = bounds.bottom + deltaLat;
181 bounds.top = bounds.top + deltaLat;
182 position.y = position.y + deltaY;
183 var newTile = this.addTile(bounds, position);
184 newTile.draw((this.params.TRANSPARENT == 'true'));
185 newRow.append(newTile);
188 if (newRow.length>0){
190 this.grid.prepend(newRow);
192 this.grid.append(newRow);
198 * @param {bool} prepend - if true, prepend to beginning.
199 * if false, then append to end
201 insertColumn:function(prepend) {
203 var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
204 var resolution = this.map.getResolution();
205 var deltaLon = resolution * deltaX;
207 for (var i=0; i<this.grid.length; i++) {
208 var row = this.grid[i];
209 modelTileIndex = (prepend) ? 0 : (row.length - 1);
210 var modelTile = row[modelTileIndex];
212 var bounds = modelTile.bounds.copyOf();
213 var position = modelTile.position.copyOf();
214 bounds.left = bounds.left + deltaLon;
215 bounds.right = bounds.right + deltaLon;
216 position.x = position.x + deltaX;
217 var newTile = this.addTile(bounds, position);
218 newTile.draw((this.params.TRANSPARENT == 'true'));
221 row = row.prepend(newTile);
223 row = row.append(newTile);
227 /** combine the ds's serverPath with its params and the tile's params.
229 * does checking on the serverPath variable, allowing for cases when it
230 * is supplied with trailing ? or &, as well as cases where not.
232 * return in formatted string like this:
233 * "server?key1=value1&key2=value2&key3=value3"
237 getFullRequestString:function(params) {
238 var requestString = "";
239 this.params.SRS = this.map.projection;
240 // concat tile params with layer params and convert to string
241 var allParams = Object.extend(this.params, params);
242 var paramsString = OpenLayers.Util.getParameterString(allParams);
244 var server = this.url;
245 var lastServerChar = server.charAt(server.length - 1);
247 if ((lastServerChar == "&") || (lastServerChar == "?")) {
248 requestString = server + paramsString;
250 if (server.indexOf('?') == -1) {
251 //serverPath has no ? -- add one
252 requestString = server + '?' + paramsString;
254 //serverPath contains ?, so must already have paramsString at the end
255 requestString = server + '&' + paramsString;
258 return requestString;
261 /** go through and remove all tiles from the grid, calling
262 * destroy() on each of them to kill circular references
266 clearGrid:function() {
268 while(this.grid.length > 0) {
269 var row = this.grid[0];
270 while(row.length > 0) {
275 this.grid.remove(row);
281 * addTile gives subclasses of Grid the opportunity to create an
282 * OpenLayer.Tile of their choosing. The implementer should initialize
283 * the new tile and take whatever steps necessary to display it.
285 * @param {OpenLayers.Bounds} bounds
287 * @returns The added OpenLayers.Tile
288 * @type OpenLayers.Tile
290 addTile:function(bounds,position) {
291 // Should be implemented by subclasses
294 /** @final @type String */
295 CLASS_NAME: "OpenLayers.Grid"