Тайловые слои в Leaflet построены вокруг асинхронной загрузки
изображений, разбитых на сетку в соответствии с текущим масштабом и
координатами карты. Каждый тайл представляет собой отдельный
HTTP-запрос, а весь процесс управляется внутренним менеджером слоя
L.TileLayer, который координирует создание, загрузку,
кэширование и удаление DOM-элементов <img>.
При изменении состояния карты (панорамирование, масштабирование, изменение CRS или границ отображения) происходит пересчёт набора необходимых тайлов. На основе этого пересчёта инициируется серия событий, отражающих жизненный цикл загрузки данных.
Ключевой момент архитектуры заключается в том, что тайлы не загружаются «пакетом» — каждый элемент проходит свой путь от создания до полной загрузки, а слой агрегирует их состояние для формирования событий более высокого уровня.
Тайловый слой генерирует события, отражающие общее состояние загрузки
всех тайлов. Эти события привязаны к экземпляру L.TileLayer
и позволяют отслеживать глобальный прогресс.
loading
Срабатывает в момент, когда начинается загрузка хотя бы одного нового тайла. Это сигнал о том, что слой перешёл в активное состояние.
Типичный сценарий: пользователь переместил карту, и появились новые области, требующие подгрузки.
tileLayer.on('loading', function () {
console.log('Началась загрузка тайлов');
});
load
Срабатывает, когда все тайлы, необходимые для текущего состояния карты, полностью загружены (или завершились ошибкой). Это состояние означает, что слой стабилизировался.
tileLayer.on('load', function () {
console.log('Все тайлы загружены');
});
Эти два события формируют базовый цикл состояния слоя: переход в загрузку и завершение загрузки.
Помимо глобальных событий, каждый тайл генерирует собственные уведомления в рамках слоя. Эти события позволяют детально контролировать процесс отрисовки и диагностику проблем с конкретными изображениями.
tileloadstart
Срабатывает при создании тайла и начале загрузки изображения.
tileLayer.on('tileloadstart', function (event) {
console.log('Начата загрузка тайла', event.tile);
});
Событие полезно для реализации индикаторов прогресса на уровне отдельных плиток.
tileload
Срабатывает, когда изображение тайла успешно загружено и готово к отображению.
tileLayer.on('tileload', function (event) {
console.log('Тайл загружен', event.tile);
});
На этом этапе элемент <img> уже содержит
корректный src и полностью декодирован браузером.
tileerror
Срабатывает при ошибке загрузки тайла. Причины могут включать:
tileLayer.on('tileerror', function (event) {
console.warn('Ошибка загрузки тайла', event.tile, event.error);
});
Внутри Leaflet может быть задействован механизм повторных попыток или подмена тайла заглушкой, если это предусмотрено опциями слоя.
Жизненный цикл тайлового слоя можно представить как упорядоченную цепочку событий:
Пользователь изменяет состояние карты
Слой вычисляет необходимые тайлы
Генерируется loading
Для каждого тайла:
tileloadstarttileload или tileerrorПосле завершения всех тайлов:
loadВажно учитывать, что события отдельных тайлов могут приходить в произвольном порядке, так как загрузка выполняется асинхронно и параллельно.
Событие tileerror играет ключевую роль в обеспечении
устойчивости отображения карты. При отсутствии корректного ответа
серверa можно:
Пример замены источника при ошибке:
tileLayer.on('tileerror', function (e) {
e.tile.src = '/images/placeholder-tile.png';
});
Дополнительно можно анализировать количество ошибок для адаптации поведения слоя, например, отключать подгрузку при массовых сбоях.
Leaflet не предоставляет встроенного прогресс-бара, однако события тайлов позволяют вычислять состояние загрузки вручную.
Общая схема:
tileload и tileerrorlet total = 0;
let loaded = 0;
tileLayer.on('loading', function () {
total = 0;
loaded = 0;
});
tileLayer.on('tileloadstart', function () {
total++;
});
tileLayer.on('tileload', function () {
loaded++;
console.log((loaded / total) * 100 + '%');
});
tileLayer.on('tileerror', function () {
loaded++;
});
Такой подход даёт возможность построения кастомных индикаторов загрузки без модификации ядра библиотеки.
При каждом zoom или move происходит
пересчёт видимых тайлов, что приводит к повторной генерации событий:
Особенность заключается в том, что tileload может не
вызываться повторно для кэшированных ресурсов, но
tileloadstart всё равно фиксирует момент обращения к
DOM-элементу.
Leaflet полагается на браузерный кэш HTTP-запросов. При корректных заголовках сервера повторная загрузка одного и того же тайла может не приводить к реальному сетевому запросу.
С точки зрения событий это создаёт важный эффект:
tileloadstart и tileload может
быть минимальнымЭто следует учитывать при измерении производительности, так как события не всегда отражают реальную сетевую активность.
При быстром перемещении карты некоторые тайлы могут быть отозваны до завершения загрузки. В таких случаях:
tileload или tileerror могут не
повлиять на текущее состояние слояЭто поведение важно для оптимизации: Leaflet стремится не блокировать интерфейс устаревшими запросами.
События тайловых слоёв позволяют строить сложные механизмы управления визуализацией:
Пример плавного отображения:
tileLayer.on('tileload', function (e) {
e.tile.style.opacity = 0;
requestAnimationFrame(() => {
e.tile.style.transition = 'opacity 0.3s';
e.tile.style.opacity = 1;
});
});
Помимо тайловых событий, слой также реагирует на включение и выключение с карты:
add — слой добавлен на картуremove — слой удалёнЭти события влияют на запуск и остановку процесса загрузки тайлов.
tileLayer.on('add', function () {
console.log('Слой активирован');
});
tileLayer.on('remove', function () {
console.log('Слой отключён');
});
Поведение событий тесно связано с настройками
L.TileLayer:
updateWhenIdle — определяет, когда происходит пересчёт
тайловkeepBuffer — влияет на количество заранее загруженных
тайловmaxZoom / minZoom — ограничивают генерацию событий на
разных масштабахupdateInterval — регулирует частоту обновленийИзменение этих параметров влияет не только на производительность, но
и на частоту срабатывания событий, особенно loading и
tileloadstart.
События тайловых слоёв часто используются для отладки:
Логирование всех событий в разработке позволяет восстановить полную картину поведения слоя:
tileLayer.on('tileloadstart tileload tileerror loading load', function (e) {
console.log(e.type, e.tile || '');
});
Такой подход позволяет наблюдать внутреннюю механику работы слоя без модификации исходного кода библиотеки.