Пользовательские источники тайлов в Leaflet опираются на универсальный механизм подстановки URL-шаблонов, позволяющий подключать практически любые растровые картографические серверы. Основная модель работы строится вокруг разбиения карты на сетку квадратных тайлов, которые запрашиваются по мере необходимости при изменении центра и масштаба.
В основе большинства слоёв тайлов используется класс
L.TileLayer, принимающий строку-шаблон:
L.tileLayer('https://{s}.tile.example.com/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© Example Maps'
}).addTo(map);
Ключевые плейсхолдеры:
Модель XYZ предполагает, что координата Y растёт вниз от северного полюса. Это стандарт де-факто для большинства веб-картографических сервисов.
При использовании собственного сервера тайлов важно соблюдать структуру каталогов или динамической генерации:
/tiles/{z}/{x}/{y}.png
Пример подключения:
const customTiles = L.tileLayer('https://tiles.myserver.com/tiles/{z}/{x}/{y}.png', {
maxZoom: 18,
minZoom: 2,
tileSize: 256,
keepBuffer: 4,
updateWhenIdle: false
});
Параметры minZoom и maxZoom ограничивают
диапазон доступных масштабов, предотвращая лишние запросы за пределами
покрытия источника данных.
Некоторые серверы используют тайлы размером 512×512 пикселей. В этом случае необходимо явно указать размер и, при необходимости, корректировать масштабирование:
L.tileLayer('https://server.com/tiles/{z}/{x}/{y}.png', {
tileSize: 512,
zoomOffset: -1
}).addTo(map);
zoomOffset компенсирует разницу между логикой сервера и Leaflet, обеспечивая корректное наложение тайлов.
Для экранов с высокой плотностью пикселей используется параметр
detectRetina:
L.tileLayer('https://server.com/tiles/{z}/{x}/{y}.png', {
detectRetina: true
});
При включении этого режима Leaflet автоматически увеличивает масштаб
запроса или добавляет суффикс @2x, если сервер поддерживает
такие тайлы.
Некоторые серверы используют систему TMS (Tile Map Service), где ось Y инвертирована относительно XYZ. Для корректной работы применяется опция:
L.tileLayer('https://server.com/tms/{z}/{x}/{y}.png', {
tms: true
});
В этом режиме Leaflet автоматически преобразует координату Y.
URL может формироваться функцией через L.TileLayer с
переопределением метода getTileUrl:
const DynamicLayer = L.TileLayer.extend({
getTileUrl: function(coords) {
const { z, x, y } = coords;
const server = (x + y) % 2 === 0 ? 'a' : 'b';
return `https://${server}.tiles.com/${z}/${x}/${y}.png`;
}
});
const layer = new DynamicLayer();
layer.addTo(map);
Такая схема используется для:
Многие API требуют токены доступа. Они передаются через query string:
L.tileLayer('https://api.tiles.com/{z}/{x}/{y}.png?key=YOUR_TOKEN', {
maxZoom: 18
}).addTo(map);
Для более сложной авторизации можно использовать динамическую генерацию URL:
getTileUrl: function(coords) {
return `https://api.tiles.com/${coords.z}/${coords.x}/${coords.y}.png?token=${this.options.token}`;
}
Каждый тайл генерирует события загрузки:
loadingloadtileloadstarttileloadtileerrorПример обработки ошибок:
const layer = L.tileLayer('https://server.com/{z}/{x}/{y}.png');
layer.on('tileerror', function(e) {
console.log('Ошибка загрузки тайла:', e.tile.src);
});
Можно задать запасной URL:
L.TileLayer.extend({
createTile: function(coords, done) {
const img = document.createElement('img');
img.oner ror = function() {
img.src = '/fallback.png';
};
img.src = this.getTileUrl(coords);
return img;
}
});
Для оптимизации запросов применяется ограничение по географическим границам:
L.tileLayer('https://server.com/{z}/{x}/{y}.png', {
bounds: [[40, -10], [60, 30]]
});
Это предотвращает загрузку тайлов вне заданной области покрытия.
Браузерное кэширование играет ключевую роль в производительности тайловых слоёв. Дополнительно используются:
keepBuffer — количество тайлов за пределами экранаupdateWhenIdle — обновление только после остановки
перемещенияupdateInterval — минимальный интервал обновленияL.tileLayer('https://server.com/{z}/{x}/{y}.png', {
keepBuffer: 8,
updateWhenIdle: true,
updateInterval: 200
});
Увеличение keepBuffer снижает вероятность пустых
областей при панорамировании, но увеличивает количество сетевых
запросов.
Стандартный TileLayer ограничен загрузкой через
<img>. Для передачи заголовков используется
переопределение с fetch:
const CustomFetchLayer = L.TileLayer.extend({
createTile: function(coords, done) {
const tile = document.createElement('img');
fetch(this.getTileUrl(coords), {
headers: {
'Authorization': 'Bearer TOKEN'
}
})
.then(res => res.blob())
.then(blob => {
tile.src = URL.createObjectURL(blob);
done(null, tile);
})
.catch(err => done(err, tile));
return tile;
}
});
Такой подход применяется при работе с закрытыми API или корпоративными картографическими системами.
Комбинация нескольких провайдеров позволяет переключать стили карты:
const osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
const satellite = L.tileLayer('https://sat.example.com/{z}/{x}/{y}.jpg');
const baseMaps = {
"OSM": osm,
"Satellite": satellite
};
L.control.layers(baseMaps).addTo(map);
Слои могут динамически заменяться без пересоздания карты, сохраняя состояние центра и масштаба.
Для нестандартных сценариев используется L.GridLayer,
предоставляющий полный контроль над созданием тайлов:
const MyGrid = L.GridLayer.extend({
createTile: function(coords) {
const tile = document.createElement('div');
tile.innerHTML = `${coords.z}/${coords.x}/${coords.y}`;
tile.style.border = '1px solid #ccc';
return tile;
}
});
map.addLayer(new MyGrid());
Этот уровень абстракции используется для:
При наложении нескольких источников важны параметры:
L.tileLayer('https://server.com/{z}/{x}/{y}.png', {
opacity: 0.7,
zIndex: 5
}).addTo(map);
Комбинация этих параметров позволяет создавать сложные многослойные карты с независимыми источниками данных.