Туром в контексте интерактивных карт называется последовательность автоматизированных переходов между различными географическими точками, сопровождаемая изменением положения камеры, масштаба, наклона и поворота карты. Подобный механизм используется для создания презентаций данных, интерактивных экскурсий, демонстрации маршрутов, визуализации путешествий и навигационных сценариев.
В 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: 8000
8 секунд.
Скорость перемещения.
speed: 0.4
Медленное движение.
Кривизна траектории.
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);
В результате карта превращается в интерактивную экскурсию.
Современный подход предполагает использование асинхронного кода.
Создание вспомогательной функции:
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.
const geojson = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
title: 'Москва'
},
geometry: {
type: 'Point',
coordinates: [37.6176, 55.7558]
}
}
]
};
Получение координат:
const point =
geojson.features[0].geometry.coordinates;
Преимущества:
При использовании стиля, поддерживающего 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();
Подобная архитектура позволяет добавлять:
Демонстрация стран, регионов и городов.
Последовательный показ достопримечательностей.
Автоматический обзор ключевых объектов мониторинга.
Показ маршрута доставки или перемещения транспорта.
Визуальное изучение географии, истории и природных объектов.
Навигация между районами и объектами городской инфраструктуры.
Грамотно реализованный тур превращает статичную карту в динамическую систему повествования, где камера последовательно раскрывает информацию через плавные перелёты, изменение ракурса, масштабирование и синхронное отображение связанных данных.