Reputation: 6338
I am using Leaflet with two tile layers. The first one, I will call it basement tile layer, provides tiles for whole world. The second one overlays the basement tile layer in a specific region defined by bounce option. I will call this one overlaying tile layer. In code this looks like the following:
var map = L.map('map');
// OpenstreetMap tile layer as basement
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
// overlaying tile layer for specific region defined by bounds
L.tileLayer('http://{s}.examples.com/overlay/{z}/{x}/{y}.png', {
bounds: L.latLngBounds(L.latLng(59.321966, 18.05943), L.latLng(59.328469, 18.076167));
}).addTo(map);
The overlaying tile layer are not transparent. So for the bounds region only the tiles of overlaying tile layer are visible. Tiles provided by basement tile layer are not needed. But I didn't find a way to prevent Leaflet from loading these unnecessary tiles yet. I would be glad for any hint.
I thought about using tile events to interrupt loading of tiles which aren't needed. But as far as documented tile events can not manipulate tile loading.
Here is a JSFiddle demonstrating the behavior. As you see e.g. tile 14/4825/6155.png is loaded from openstreetmap.org even so it's invisible.
In my use case another think makes it more complicated: Overlaying map has strict borders cause it's generated by historic map sheet. So tiles are transparent at the borders of overlaying map. In these regions tiles of basement map has to be loaded.
Upvotes: 7
Views: 2450
Reputation: 6338
Thanks to @FrankPhillips hints in comment I figured out that I could overwrite _isValidTile
method from L.GridLayer to achieve the functionality. I could add a hole option as a opposite to bounce option.
L.ExtendedTileLayer = L.TileLayer.extend({
_isValidTile: function (coords) {
var crs = this._map.options.crs;
if (!crs.infinite) {
// don't load tile if it's out of bounds and not wrapped
/*
* this._globalTileRange is not defined
* not quite sure why
*/
var globalTileRange = this._map.getPixelWorldBounds( coords.z );
var bounds = globalTileRange;
if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||
(!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }
}
var tileBounds = this._tileCoordsToBounds(coords);
// don't load tile if it doesn't intersect the bounds in options
if (this.options.bounds &&
! L.latLngBounds(this.options.bounds).intersects(tileBounds)) {
return false;
}
// don't load tile if it does intersect the hole in options
if (this.options.hole &&
L.latLngBounds(this.options.hole).intersects(tileBounds)) {
return false;
}
return true;
},
});
var map = L.map('map', {
center: [40.777838, -73.968654],
zoom: 14
});
new L.ExtendedTileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
hole: L.latLngBounds(
L.latLng(40.791853, -73.967128),
L.latLng(40.781455, -73.955713)
)
}).addTo(map);
L.tileLayer('http://tile.stamen.com/toner/{z}/{x}/{y}.png', {
attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.',
bounds: L.latLngBounds(
L.latLng(40.791853, -73.967128),
L.latLng(40.781455, -73.955713)
)
}).addTo(map);
I updated JSFiddle to show it working.
_isValidTile
is mostly just copyed from Leaflet original. I had to reimplement this._globalTileRange
since is was undefined. Code is only working for leaflet-src.js, since _isValidTime
is uglifyed in production build.
Upvotes: 4