docs: function(bounds) {
          this.events.triggerEvent("retile");
  
          // work out mininum number of rows and columns; this is the number of
          // tiles required to cover the viewport plus at least one for panning
  
          var viewSize = this.map.getSize();
          
          var origin = this.getTileOrigin();
          var resolution = this.map.getResolution(),
              serverResolution = this.getServerResolution(),
              ratio = resolution / serverResolution,
              tileSize = {
                  w: this.tileSize.w / ratio,
                  h: this.tileSize.h / ratio
              };
  
          var minRows = Math.ceil(viewSize.h/tileSize.h) + 
                        2 * this.buffer + 1;
          var minCols = Math.ceil(viewSize.w/tileSize.w) +
                        2 * this.buffer + 1;
  
          var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution);
          this.gridLayout = tileLayout;
          
          var tilelon = tileLayout.tilelon;
          var tilelat = tileLayout.tilelat;
          
          var layerContainerDivLeft = this.map.layerContainerOriginPx.x;
          var layerContainerDivTop = this.map.layerContainerOriginPx.y;
  
          var tileBounds = this.getTileBoundsForGridIndex(0, 0);
          var startPx = this.map.getViewPortPxFromLonLat(
              new OpenLayers.LonLat(tileBounds.left, tileBounds.top)
          );
          startPx.x = Math.round(startPx.x) - layerContainerDivLeft;
          startPx.y = Math.round(startPx.y) - layerContainerDivTop;
  
          var tileData = [], center = this.map.getCenter();
  
          var rowidx = 0;
          do {
              var row = this.grid[rowidx];
              if (!row) {
                  row = [];
                  this.grid.push(row);
              }
              
              var colidx = 0;
              do {
                  tileBounds = this.getTileBoundsForGridIndex(rowidx, colidx);
                  var px = startPx.clone();
                  px.x = px.x + colidx * Math.round(tileSize.w);
                  px.y = px.y + rowidx * Math.round(tileSize.h);
                  var tile = row[colidx];
                  if (!tile) {
                      tile = this.addTile(tileBounds, px);
                      this.addTileMonitoringHooks(tile);
                      row.push(tile);
                  } else {
                      tile.moveTo(tileBounds, px, false);
                  }
                  var tileCenter = tileBounds.getCenterLonLat();
                  tileData.push({
                      tile: tile,
                      distance: Math.pow(tileCenter.lon - center.lon, 2) +
                          Math.pow(tileCenter.lat - center.lat, 2)
                  });
       
                  colidx += 1;
              } while ((tileBounds.right <= bounds.right + tilelon * this.buffer)
                       || colidx < minCols);
               
              rowidx += 1;
          } while((tileBounds.bottom >= bounds.bottom - tilelat * this.buffer)
                  || rowidx < minRows);
          
          //shave off exceess rows and colums
          this.removeExcessTiles(rowidx, colidx);
  
          var resolution = this.getServerResolution();
          // store the resolution of the grid
          this.gridResolution = resolution;
  
          //now actually draw the tiles
          tileData.sort(function(a, b) {
              return a.distance - b.distance; 
          });
          for (var i=0, ii=tileData.length; i<ii; ++i) {
              tileData[i].tile.draw();
          }
      }