Анимационные переходы в Leaflet реализованы как сочетание CSS-трансформаций, внутренних интерполяций координат и управления состояниями карты через события. Базовый принцип заключается в плавном изменении центра, масштаба и трансформации тайловой подложки, а также синхронизации всех векторных и DOM-слоёв с текущим состоянием карты.
Leaflet оперирует географическими координатами (LatLng), которые в процессе анимации преобразуются в пиксельные координаты через проекцию. Во время переходов изменяется не сами данные, а матрица преобразования отображения карты. Это позволяет одновременно анимировать:
Внутри движка используется интерполяция между начальным и конечным состоянием с фиксированным временным шагом.
Основной механизм панорамирования реализуется через методы
panTo, flyTo и setView с
включённой анимацией.
Метод выполняет линейное смещение центра карты:
map.panTo([55.751244, 37.618423], {
animate: true,
duration: 1.2,
easeLinearity: 0.25,
noMoveStart: false
});
Параметры анимации управляют скоростью и характером движения:
duration — длительность перехода в секундахeaseLinearity — коэффициент сглаживания траекторииnoMoveStart — отключение события начала движенияИнтерполяция происходит в экранных координатах, что обеспечивает равномерную скорость визуального перемещения независимо от проекции.
Метод реализует более сложную траекторию с эффектом «приближения по дуге»:
map.flyTo([55.751244, 37.618423], 10, {
duration: 2,
easeLinearity: 0.3
});
Особенность заключается в комбинированной анимации:
При больших дистанциях используется логарифмическая интерполяция масштаба, что создаёт эффект «полёта» над картой.
Изменение уровня масштаба выполняется через zoomIn,
zoomOut, setZoom и setView.
map.setZoom(12, {
animate: true,
duration: 1
});
Zoom-анимация основана на изменении коэффициента масштабирования тайлового слоя с синхронным пересчётом позиции всех векторных объектов.
Масштабирование происходит по экспоненциальной шкале:
Метод fitBounds обеспечивает автоматическое
масштабирование и позиционирование карты под заданный прямоугольник:
map.fitBounds([
[55.5, 37.3],
[55.9, 37.9]
], {
animate: true,
duration: 1.5,
padding: [20, 20]
});
Алгоритм включает:
При этом сохраняется пропорциональность отображения области.
Единый набор параметров используется в большинстве методов:
animate — включение анимацииduration — длительность переходаeaseLinearity — степень сглаживания движенияinertia — инерция после drag-событийmaxZoom / minZoom — ограничения
масштабаИнерция применяется при перетаскивании карты и создаёт эффект продолжения движения после отпускания:
map.dragging.enable();
map.options.inertia = true;
map.options.inertiaDeceleration = 3000;
Все слои Leaflet синхронизируются с состоянием карты через систему событий:
movestartmovemoveendzoomstartzoomzoomendКаждое изменение трансформации карты вызывает перерасчёт позиции элементов DOM или Canvas.
Векторные слои (SVG) пересчитывают координаты точек в реальном времени, тогда как тайлы используют CSS transform:
.leaflet-tile {
transition: transform 0.25s ease-out, opacity 0.25s ease;
}
TileLayer поддерживает плавное появление и масштабирование изображений:
L.tileLayer(url, {
fadeAnimation: true,
zoomAnimation: true,
updateWhenZooming: false
});
Обеспечивает постепенное появление новых тайлов через изменение opacity.
Применяет масштабирование через CSS transform вместо мгновенной подмены тайлов.
При включённой анимации используется двойной буфер тайлов для предотвращения «мигания» при смене масштаба.
Маркерные объекты используют CSS-трансформации при изменении позиции карты:
L.marker([55.75, 37.61], {
riseOnHover: true
}).addTo(map);
При движении карты маркер не пересоздаётся, а только получает новые координаты в пикселях, что позволяет сохранять плавность.
Popup-окна анимируются через изменение класса состояния:
moveВекторный слой SVG использует прямую привязку к DOM:
zoom и
moveCanvas-рендеринг работает иначе:
Canvas предпочтителен при большом количестве объектов, так как снижает нагрузку на DOM.
Анимации синхронизируются через requestAnimationFrame.
Основной цикл выполняет:
Псевдологика:
function animateZoom(t) {
const progress = ease(t);
currentZoom = startZoom + (endZoom - startZoom) * progress;
updateMapTransform(currentZoom);
requestAnimationFrame(animateZoom);
}
Каждый переход сопровождается цепочкой событий:
zoomstart или
movestartzoom и movezoomend или
moveendЭти события позволяют синхронизировать внешние компоненты интерфейса с состоянием карты без прямого вмешательства в механизм рендеринга.
Одновременное изменение центра и масштаба используется в
setView:
map.setView([55.751244, 37.618423], 11, {
animate: true,
duration: 1.5
});
В этом режиме Leaflet выполняет двухмерную интерполяцию:
Траектория формируется в экранном пространстве, что исключает визуальные скачки при резком изменении масштаба.
Ключевым фактором производительности является количество DOM-элементов и тип слоя:
Дополнительные оптимизации:
zoomAnimation при слабых устройствахupdateWhenIdleПлавность определяется функцией easing. Leaflet использует линейную и нелинейную интерполяцию:
Коэффициент easeLinearity регулирует кривизну траектории
и влияет на восприятие скорости при pan и flyTo операциях.
Кастомные оверлеи подключаются к системе через подписку на события карты:
map.on('zoom', callback)map.on('move', callback)Внутри callback пересчитываются координаты объектов с использованием
latLngToLayerPoint, что обеспечивает согласованность с
анимацией карты.
map.on('zoom', () => {
const point = map.latLngToLayerPoint([55.75, 37.61]);
customElement.style.transform = `translate(${point.x}px, ${point.y}px)`;
});
Все анимации сводятся к изменению единой матрицы трансформации:
Leaflet применяет CSS transform к контейнеру карты,
минимизируя количество перерисовок и обеспечивая согласованность всех
слоёв в пределах одного кадра.