diff --git a/debug/map/grid.html b/debug/map/grid.html index 06e71d7f..fb733830 100644 --- a/debug/map/grid.html +++ b/debug/map/grid.html @@ -31,7 +31,7 @@ // test async setTimeout(function () { - done(tile); + done(null, tile); }, Math.random() * 500); return tile; diff --git a/src/geo/crs/CRS.EPSG3857.js b/src/geo/crs/CRS.EPSG3857.js index 670ca49a..6d668b79 100644 --- a/src/geo/crs/CRS.EPSG3857.js +++ b/src/geo/crs/CRS.EPSG3857.js @@ -14,6 +14,8 @@ L.CRS.EPSG3857 = L.extend({}, L.CRS, { return new L.Transformation(scale, 0.5, -scale, 0.5); }()) + + wrapLng: true }); L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, { diff --git a/src/layer/tile/GridLayer.js b/src/layer/tile/GridLayer.js index 1bae8154..66bce929 100644 --- a/src/layer/tile/GridLayer.js +++ b/src/layer/tile/GridLayer.js @@ -108,15 +108,6 @@ L.GridLayer = L.Class.extend({ return this; }, - isValidTile: function (coords) { - if (!this.options.bounds) { return true; } - - var tileBounds = this._tileCoordsToBounds(coords), - bounds = L.latLngBounds(this.options.bounds); - - return bounds.contains(tileBounds); - }, - _getPane: function () { // TODO pane in options? return this._map._panes.tilePane; @@ -274,7 +265,7 @@ L.GridLayer = L.Class.extend({ coords = new L.Point(i, j); coords.z = zoom; - if (!this._tileIsAdded(coords) && this.isValidTile(coords)) { + if (!this._tileIsAdded(coords) && this._isValidTile(coords)) { queue.push(coords); } } @@ -305,6 +296,21 @@ L.GridLayer = L.Class.extend({ this._tileContainer.appendChild(fragment); }, + _isValidTile: function (coords) { + var crs = this._map.options.crs, + limit = this._getWrapTileNum(); + + if (!crs.wrapLng && (coords.x < 0 || coords.x >= limit.x)) { return; } + if (!crs.wrapLat && (coords.y < 0 || coords.y >= limit.y)) { return; } + + if (!this.options.bounds) { return true; } + + var tileBounds = this._tileCoordsToBounds(coords), + bounds = L.latLngBounds(this.options.bounds); + + return bounds.contains(tileBounds); + }, + _tileIsAdded: function (coords) { return this._tileCoordsToKey(coords) in this._tiles; }, @@ -319,8 +325,6 @@ L.GridLayer = L.Class.extend({ nw = this._map.unproject(nwPoint), se = this._map.unproject(sePoint); - // TODO rectangular - return new L.LatLngBounds(nw, se); }, @@ -379,19 +383,23 @@ L.GridLayer = L.Class.extend({ }, _addTile: function (coords, container) { + var tilePos = this._getTilePos(coords); + + this._wrapCoords(coords); + var tile = this.createTile(coords, this._tileReady); - // TODO wrapping happens here? + this.fire('tileloadstart', {tile: tile}); this._initTile(tile); + // if createTile is defined with a second argument ("done" callback), + // we know that tile is async and will be ready later; otherwise if (this.createTile.length < 2) { - // if tiles are sync, delay one frame for opacity anim to happen - setTimeout(L.bind(this._tileReady, this, tile), 0); + // mark tile as ready, but delay one frame for opacity anim to happen + setTimeout(L.bind(this._tileReady, this, null, tile), 0); } - var tilePos = this._getTilePos(coords); - /* Chrome 20 layouts much faster with top/left (verify with timeline, frames) Android 4 browser has display issues with top/left and requires transform instead @@ -406,7 +414,11 @@ L.GridLayer = L.Class.extend({ container.appendChild(tile); }, - _tileReady: function (tile) { + _tileReady: function (err, tile) { + if (err) { + this.fire('tileerror', {error: err}); + } + L.DomUtil.addClass(tile, 'leaflet-tile-loaded'); this.fire('tileload', {tile: tile}); @@ -435,6 +447,23 @@ L.GridLayer = L.Class.extend({ return tilePoint.multiplyBy(tileSize).subtract(origin); }, + _wrapCoords: function (coords) { + var crs = this._map.options.crs, + limit = this._getWrapTileNum(); + + if (crs.wrapLng) { + coords.x = ((coords.x % limit.x) + limit.x) % limit.x; + } + if (crs.wrapLat) { + coords.y = ((coords.y % limit.y) + limit.y) % limit.y; + } + }, + + _getWrapTileNum: function () { + var size = this._map.options.crs.getSize(this._map.getZoom()); + return size.divideBy(this.options.tileSize); + }, + _animateZoom: function (e) { if (!this._animating) { this._animating = true;