Создание туров

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

В Mapbox GL JS создание туров основывается на управлении камерой карты через встроенные методы:

  • flyTo()
  • easeTo()
  • jumpTo()
  • fitBounds()

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


Основы управления камерой

После создания карты объект map предоставляет доступ к камере.

const map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v12',
    center: [37.6176, 55.7558],
    zoom: 5
});

Для изменения положения карты используется метод flyTo().

map.flyTo({
    center: [30.3158, 59.9398],
    zoom: 10
});

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


Структура простой экскурсии

Тур обычно состоит из набора остановок.

const stops = [
    {
        center: [37.6176, 55.7558],
        zoom: 10
    },
    {
        center: [30.3158, 59.9398],
        zoom: 11
    },
    {
        center: [39.7015, 47.2357],
        zoom: 12
    }
];

Каждая остановка содержит параметры отображения карты:

Свойство Описание
center Координаты точки
zoom Масштаб
bearing Поворот карты
pitch Наклон
duration Время анимации

Последовательный переход между остановками

Наиболее распространённый способ создания тура — последовательный запуск анимаций.

const stops = [
    {
        center: [37.6176, 55.7558],
        zoom: 10
    },
    {
        center: [30.3158, 59.9398],
        zoom: 11
    },
    {
        center: [24.7536, 59.4370],
        zoom: 12
    }
];

let currentIndex = 0;

function startTour() {

    if (currentIndex >= stops.length) {
        return;
    }

    map.flyTo({
        ...stops[currentIndex],
        duration: 5000
    });

    map.once('moveend', () => {
        currentIndex++;
        startTour();
    });
}

startTour();

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


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

В крупных проектах удобнее хранить параметры тура в виде набора сцен.

const scenes = [
    {
        name: 'Москва',
        center: [37.6176, 55.7558],
        zoom: 11,
        pitch: 40,
        bearing: 20
    },
    {
        name: 'Санкт-Петербург',
        center: [30.3158, 59.9398],
        zoom: 12,
        pitch: 50,
        bearing: 120
    }
];

Такой подход облегчает:

  • добавление новых точек;
  • изменение маршрута;
  • загрузку данных с сервера;
  • создание редакторов туров.

Изменение наклона камеры

Для создания кинематографического эффекта используется параметр pitch.

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 14,
    pitch: 70
});

Значения:

0   — вид сверху
30  — умеренный наклон
60  — объёмное отображение
85  — почти горизонтальный взгляд

Большие значения особенно эффектно работают с трёхмерными зданиями.


Управление поворотом карты

Параметр bearing отвечает за ориентацию карты.

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 15,
    bearing: 180
});

Примеры:

Значение Направление
0 Север сверху
90 Восток сверху
180 Юг сверху
270 Запад сверху

Комбинация pitch и bearing позволяет создавать профессиональные презентационные сцены.


Создание кинематографических перелётов

Часто требуется не просто переместить карту, а создать эффект полёта.

map.flyTo({
    center: [13.4050, 52.5200],
    zoom: 14,
    pitch: 60,
    bearing: 140,
    duration: 8000,
    curve: 1.8,
    speed: 0.5
});

Ключевые параметры:

duration

Продолжительность анимации.

duration: 8000

8 секунд.

speed

Скорость перемещения.

speed: 0.4

Медленное движение.

curve

Кривизна траектории.

curve: 2

Чем выше значение, тем заметнее дуга перелёта.


Автоматическая демонстрация маршрута

Если имеется набор координат маршрута, тур может проходить вдоль линии.

const route = [
    [37.6176, 55.7558],
    [36.2304, 49.9935],
    [30.3158, 59.9398]
];

Перемещение между точками:

let index = 0;

function nextPoint() {

    if (index >= route.length) {
        return;
    }

    map.flyTo({
        center: route[index],
        zoom: 10,
        duration: 4000
    });

    map.once('moveend', () => {
        index++;
        nextPoint();
    });
}

nextPoint();

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


Синхронизация с информационными окнами

Во время тура часто отображается дополнительная информация.

const locations = [
    {
        title: 'Москва',
        center: [37.6176, 55.7558]
    },
    {
        title: 'Санкт-Петербург',
        center: [30.3158, 59.9398]
    }
];

При переходе можно создавать всплывающие окна.

new mapboxgl.Popup()
    .setLngLat(location.center)
    .setHTML(`<h3>${location.title}</h3>`)
    .addTo(map);

В результате карта превращается в интерактивную экскурсию.


Использование async/await

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

Создание вспомогательной функции:

function flyToLocation(options) {

    return new Promise(resolve => {

        map.flyTo(options);

        map.once('moveend', resolve);
    });
}

Запуск тура:

async function startTour() {

    await flyToLocation({
        center: [37.6176, 55.7558],
        zoom: 11
    });

    await flyToLocation({
        center: [30.3158, 59.9398],
        zoom: 12
    });

    await flyToLocation({
        center: [24.7536, 59.4370],
        zoom: 13
    });
}

startTour();

Такой код проще поддерживать и расширять.


Паузы между сценами

Экскурсии обычно содержат задержки между переходами.

Функция ожидания:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

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

async function startTour() {

    await flyToLocation({
        center: [37.6176, 55.7558],
        zoom: 12
    });

    await delay(3000);

    await flyToLocation({
        center: [30.3158, 59.9398],
        zoom: 12
    });

    await delay(3000);
}

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


Воспроизведение тура по кнопке

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

HTML:

<button id="start-tour">
    Запустить тур
</button>

Jav * aScript:

document
    .getElementById('start-tour')
    .addEventListener('click', startTour);

Это позволяет пользователю самостоятельно инициировать демонстрацию.


Реализация кнопок управления

Для сложных сценариев добавляются элементы управления.

<button id="play">Play</button>
<button id="pause">Pause</button>
<button id="next">Next</button>
<button id="previous">Previous</button>

Типичные возможности:

  • запуск;
  • остановка;
  • переход вперёд;
  • возврат назад;
  • повтор тура.

Создание циклического тура

Некоторые презентации работают непрерывно.

async function loopTour() {

    while (true) {

        for (const stop of stops) {

            await flyToLocation({
                ...stop,
                duration: 5000
            });

            await delay(2000);
        }
    }
}

loopTour();

Подобный режим применяется на информационных стендах и панелях мониторинга.


Подсветка объектов во время тура

Тур становится значительно информативнее при синхронизации камеры и слоёв.

Пример выделения объекта:

map.setFilter(
    'cities-highlight',
    ['==', 'id', currentCityId]
);

После перехода к новой сцене фильтр обновляется.

В результате зритель всегда видит объект, о котором идёт речь.


Использование GeoJSON для хранения остановок

Точки тура могут храниться непосредственно в GeoJSON.

const geojson = {
    type: 'FeatureCollection',
    features: [
        {
            type: 'Feature',
            properties: {
                title: 'Москва'
            },
            geometry: {
                type: 'Point',
                coordinates: [37.6176, 55.7558]
            }
        }
    ]
};

Получение координат:

const point =
    geojson.features[0].geometry.coordinates;

Преимущества:

  • совместимость со стандартами GIS;
  • лёгкая интеграция с сервером;
  • возможность хранения описаний и изображений.

Тур с трёхмерными зданиями

При использовании стиля, поддерживающего 3D, можно создавать эффект виртуального полёта по городу.

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 16,
    pitch: 80,
    bearing: 45
});

Дополнительно подключается слой зданий:

map.addLayer({
    id: '3d-buildings',
    source: 'composite',
    'source-layer': 'building',
    type: 'fill-extrusion',
    minzoom: 15,
    paint: {
        'fill-extrusion-color': '#aaa',
        'fill-extrusion-height': [
            'get',
            'height'
        ]
    }
});

Комбинация наклона и трёхмерных объектов создаёт полноценную виртуальную экскурсию.


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

При разработке масштабных туров рекомендуется:

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

Архитектура менеджера туров

В крупных приложениях логика обычно выносится в отдельный класс.

class TourManager {

    constructor(map, scenes) {
        this.map = map;
        this.scenes = scenes;
        this.current = 0;
    }

    async start() {

        for (const scene of this.scenes) {

            await this.move(scene);
        }
    }

    move(scene) {

        return new Promise(resolve => {

            this.map.flyTo(scene);

            this.map.once(
                'moveend',
                resolve
            );
        });
    }
}

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

const tour = new TourManager(
    map,
    scenes
);

tour.start();

Подобная архитектура позволяет добавлять:

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

Типичные сценарии использования туров

Географические презентации

Демонстрация стран, регионов и городов.

Туристические экскурсии

Последовательный показ достопримечательностей.

Аналитические панели

Автоматический обзор ключевых объектов мониторинга.

Логистические системы

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

Образовательные проекты

Визуальное изучение географии, истории и природных объектов.

Городские цифровые двойники

Навигация между районами и объектами городской инфраструктуры.

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