Tile layers and basemap switching
Quick answer
This tutorial explains the Web Mercator tile pyramid behind L.tileLayer and the meaning of the z, x, y, s and r placeholders. It reviews options including subdomains, tileSize, zoomOffset, detectRetina, noWrap, bounds, keepBuffer and updateWhenIdle, and builds a basemap switcher with L.control.layers. It also diagnoses failed tiles with tileerror and the baselayerchange event. Readers can swap basemaps without stale layers or broken attribution.
Key points
- Provide subdomains whenever the URL template contains {s}, and set maxZoom to the real limit.
- Pass all basemaps to L.control.layers so only one is visible and attribution stays in sync.
- Use tms: true when the service counts rows from south to north.
Example
var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors'
});
var cartoLight = L.tileLayer(
'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
subdomains: 'abcd',
maxZoom: 20,
attribution: '© OpenStreetMap contributors © CARTO'
}
);
var map = L.map('map', {
center: [39.907359, 116.391263],
zoom: 11,
layers: [osm]
});
L.control.layers({
'OpenStreetMap': osm,
'Carto 浅色': cartoLight
}, null, { position: 'topright' }).addTo(map);var failed = 0;
tiles.on('tileerror', function (e) {
failed++;
if (failed === 3) {
console.warn('瓦片连续失败,检查网络或服务地址', e.tile.src);
}
});
map.on('baselayerchange', function (e) {
failed = 0;
console.log('当前底图', e.name);
});
Notes
- A hand-written switcher that only adds layers leaves the old basemap requesting tiles underneath.
- WGS84 points over GCJ-02 tiles from Gaode or Tencent stay offset no matter the URL.
English edition written for Atlaslog. Code is taken from the original Chinese page and runs unchanged.
Atlaslog (2026). Tile layers and basemap switching. https://www.jingweizhi.com/en/leaflet/tutorials/tile-layer.html (accessed 2026-11-03).