Плавная анимация камеры

Камера в MapLibre GL JS определяет положение виртуального наблюдателя относительно карты. Через параметры камеры управляются центр карты, масштаб, наклон и поворот. Плавная анимация камеры позволяет создавать естественные переходы между состояниями карты без резких скачков интерфейса.

Анимация применяется в различных сценариях:

  • переход к выбранному объекту;
  • навигация между городами и регионами;
  • демонстрация маршрутов;
  • последовательное отображение точек интереса;
  • создание интерактивных презентаций;
  • визуализация перемещения транспорта и объектов.

Основные параметры камеры

Состояние камеры определяется несколькими ключевыми характеристиками:

Параметр Описание
center Географический центр карты
zoom Уровень масштабирования
bearing Поворот карты относительно севера
pitch Угол наклона карты

Пример начальной конфигурации:

const map = new maplibregl.Map({
    container: 'map',
    style: 'https://demotiles.maplibre.org/style.json',
    center: [37.6176, 55.7558],
    zoom: 10,
    bearing: 0,
    pitch: 0
});

Метод flyTo

Наиболее популярный способ плавного перемещения камеры — использование метода flyTo().

Пример перелёта к новой точке:

map.flyTo({
    center: [30.3351, 59.9343],
    zoom: 12
});

Камера выполнит анимированный переход от текущего положения к указанным координатам.

Особенности flyTo

Метод моделирует эффект полёта над картой:

  • автоматически изменяет масштаб;
  • рассчитывает красивую траекторию движения;
  • обеспечивает естественное ускорение и замедление;
  • подходит для больших расстояний.

Пример:

map.flyTo({
    center: [2.3522, 48.8566],
    zoom: 13
});

Если текущий центр находится в Москве, пользователь увидит плавный перелёт к Парижу.


Настройка продолжительности анимации

Параметр duration задаёт длительность анимации в миллисекундах.

map.flyTo({
    center: [2.3522, 48.8566],
    zoom: 13,
    duration: 5000
});

В данном случае анимация займёт пять секунд.

Часто используемые значения:

Значение Эффект
500 Очень быстро
1000 Быстро
2000 Стандартный переход
5000+ Демонстрационный режим

Управление скоростью полёта

Параметр speed влияет на скорость движения камеры.

map.flyTo({
    center: [13.4050, 52.5200],
    zoom: 12,
    speed: 0.5
});

По умолчанию используется значение около 1.2.

Чем больше значение:

map.flyTo({
    center: [13.4050, 52.5200],
    zoom: 12,
    speed: 3
});

тем быстрее камера достигнет цели.


Параметр curve

curve определяет форму траектории полёта.

map.flyTo({
    center: [13.4050, 52.5200],
    zoom: 12,
    curve: 2
});

Большие значения создают более выраженную дугу движения.

Небольшие значения дают более прямолинейный переход.


Метод easeTo

Для более контролируемых перемещений используется easeTo().

map.easeTo({
    center: [37.64, 55.76],
    zoom: 14
});

Отличия от flyTo:

flyTo easeTo
Эффект полёта Простое плавное движение
Подходит для больших расстояний Подходит для локальных перемещений
Может менять масштаб автоматически Обычно выполняет прямой переход

Анимация изменения масштаба

Изменение масштаба без перемещения:

map.easeTo({
    zoom: 15
});

Уменьшение масштаба:

map.easeTo({
    zoom: 5
});

Подобные переходы часто используются при выборе объектов из списка.


Одновременное изменение нескольких параметров

Камера может изменять несколько характеристик одновременно.

map.easeTo({
    center: [37.6176, 55.7558],
    zoom: 16,
    bearing: 90,
    pitch: 60,
    duration: 3000
});

В результате карта:

  • переместится в новую точку;
  • приблизится;
  • повернётся на 90 градусов;
  • получит наклон 60 градусов.

Поворот камеры

Для анимации поворота используется свойство bearing.

map.easeTo({
    bearing: 180,
    duration: 2000
});

Карта плавно развернётся в противоположную сторону.

Сброс поворота:

map.easeTo({
    bearing: 0
});

Наклон камеры

Наклон создаёт эффект перспективы.

map.easeTo({
    pitch: 60
});

Максимально допустимый угол зависит от версии движка и настроек карты.

Возврат к виду сверху:

map.easeTo({
    pitch: 0
});

Анимация к маркеру

Часто требуется переместить камеру к выбранному маркеру.

marker.getElement().addEventListener('click', () => {
    map.flyTo({
        center: marker.getLngLat(),
        zoom: 15
    });
});

После нажатия карта плавно переместится к объекту.


Использование fitBounds

Для анимации перехода к области применяется fitBounds().

const bounds = [
    [37.50, 55.70],
    [37.75, 55.85]
];

map.fitBounds(bounds, {
    padding: 50
});

Камера автоматически рассчитает оптимальный масштаб и центр.


Анимированный fitBounds

Метод поддерживает анимацию.

map.fitBounds(bounds, {
    padding: 50,
    duration: 3000
});

Переход будет выполнен плавно в течение трёх секунд.


Последовательность анимаций

После завершения одной анимации можно запускать следующую.

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 12,
    duration: 3000
});

map.once('moveend', () => {
    map.easeTo({
        pitch: 60,
        bearing: 120,
        duration: 2000
    });
});

Сначала выполняется перелёт, затем изменение угла обзора.


События анимации

movestart

Запускается при начале движения камеры.

map.on('movestart', () => {
    console.log('Начало движения');
});

move

Вызывается во время анимации.

map.on('move', () => {
    console.log('Камера движется');
});

moveend

Срабатывает после завершения движения.

map.on('moveend', () => {
    console.log('Движение завершено');
});

Прерывание анимации

Любое действие пользователя может остановить текущую анимацию.

Например:

  • перетаскивание карты;
  • изменение масштаба колесом мыши;
  • жесты на сенсорных устройствах.

Для программного прерывания используется:

map.stop();

Пример:

map.flyTo({
    center: [2.3522, 48.8566],
    duration: 10000
});

setTimeout(() => {
    map.stop();
}, 3000);

Анимация завершится через три секунды после запуска.


Автоматический тур по карте

Один из популярных сценариев — экскурсия по нескольким городам.

const locations = [
    [37.6176, 55.7558],
    [30.3351, 59.9343],
    [39.7015, 47.2357]
];

let index = 0;

function flyNext() {
    map.flyTo({
        center: locations[index],
        zoom: 12,
        duration: 4000
    });

    index++;

    if (index < locations.length) {
        map.once('moveend', flyNext);
    }
}

flyNext();

Камера будет последовательно перелетать между заданными координатами.


Кинематографический эффект обзора

Сочетание наклона, поворота и изменения масштаба позволяет создавать эффектные сцены.

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 17,
    pitch: 70,
    bearing: 120,
    duration: 6000
});

Подобный подход используется:

  • в презентациях проектов;
  • в туристических приложениях;
  • в системах мониторинга транспорта;
  • в геоинформационных панелях управления.

Анимация следования за движущимся объектом

Камера может постоянно перемещаться вслед за объектом.

function updateVehicle(position) {
    map.easeTo({
        center: position,
        duration: 500
    });
}

При регулярном обновлении координат создаётся эффект сопровождения объекта.


Ограничение частоты обновлений

При большом количестве перемещений важно избегать запуска новой анимации до завершения предыдущей.

Плохой вариант:

setInterval(() => {
    map.easeTo({
        center: getPosition()
    });
}, 100);

Лучше использовать более редкие обновления:

setInterval(() => {
    map.easeTo({
        center: getPosition(),
        duration: 1000
    });
}, 1000);

Либо проверять состояние приложения перед запуском очередной анимации.


Синхронизация с пользовательским интерфейсом

Анимации часто связываются с элементами управления.

Кнопка перехода:

button.addEventListener('click', () => {
    map.flyTo({
        center: [37.6176, 55.7558],
        zoom: 14
    });
});

Выбор элемента списка:

list.addEventListener('change', (event) => {
    map.flyTo({
        center: getCoordinates(event.target.value),
        zoom: 15
    });
});

Такой подход позволяет создавать интерактивную навигацию по данным карты.


Практические рекомендации

Для дальних перемещений предпочтителен flyTo().

Для локальных изменений камеры обычно используется easeTo().

Продолжительность анимации желательно удерживать в диапазоне от 1000 до 3000 миллисекунд для большинства интерфейсов.

Наклон и поворот следует применять умеренно, чтобы не ухудшать ориентацию пользователя на карте.

Длинные цепочки анимаций лучше строить через события moveend.

Принудительное сопровождение объектов не должно полностью лишать пользователя возможности самостоятельно управлять картой.

Анимации камеры должны подчёркивать структуру геоданных и облегчать навигацию, а не превращаться в декоративный элемент интерфейса.