Пошаговая навигация (Turn-by-Turn Navigation) представляет собой процесс построения маршрута между точками и последовательного отображения инструкций движения: поворотов, съездов, разворотов, изменения полос движения и других манёвров. В веб-приложениях на базе Mapbox GL JS такая функциональность строится за счёт совместного использования картографического движка и сервисов маршрутизации.
Mapbox GL JS отвечает за:
Сервис маршрутизации предоставляет:
Схема работы выглядит следующим образом:
Типичная структура состоит из нескольких компонентов.
Создаётся экземпляр Mapbox GL JS:
mapboxgl.accessToken = 'YOUR_TOKEN';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [37.6176, 55.7558],
zoom: 12
});
Необходимо хранить:
const start = [37.6176, 55.7558];
const destination = [37.6810, 55.7600];
Отвечает за получение маршрута:
async function getRoute(start, destination) {
const url =
`https://api.mapbox.com/directions/v5/mapbox/driving/` +
`${start[0]},${start[1]};${destination[0]},${destination[1]}` +
`?steps=true&geometries=geojson&access_token=${mapboxgl.accessToken}`;
const response = await fetch(url);
return response.json();
}
Может содержать:
Для работы пошаговой навигации необходимо получать детализированные инструкции движения.
Запрос должен содержать параметр:
steps=true
Полный пример:
const response = await fetch(
`https://api.mapbox.com/directions/v5/mapbox/driving/
37.6176,55.7558;
37.6810,55.7600
?steps=true
&geometries=geojson
&overview=full
&access_token=${mapboxgl.accessToken}`
);
const data = await response.json();
Из ответа извлекается маршрут:
const route = data.routes[0];
Информация о маршруте:
console.log(route.distance);
console.log(route.duration);
Маршрут содержит массив участков:
route.legs
Каждый участок содержит шаги:
route.legs[0].steps
Пример шага:
{
distance: 120,
duration: 15,
geometry: {...},
maneuver: {
instruction: "Поверните направо",
location: [37.620, 55.756]
}
}
Наиболее важные поля:
| Поле | Описание |
|---|---|
| distance | расстояние шага |
| duration | время выполнения |
| geometry | геометрия участка |
| maneuver | информация о манёвре |
| instruction | текст инструкции |
| location | координаты манёвра |
После получения геометрии её необходимо вывести как слой.
Создание источника:
map.addSource('route', {
type: 'geojson',
data: {
type: 'Feature',
geometry: route.geometry
}
});
Создание линии маршрута:
map.addLayer({
id: 'route-line',
type: 'line',
source: 'route',
paint: {
'line-color': '#3b82f6',
'line-width': 6
}
});
В результате появляется визуальное представление пути.
Для улучшения восприятия маршрута обычно добавляются маркеры.
Начальная точка:
new mapboxgl.Marker({
color: 'green'
})
.setLngLat(start)
.addTo(map);
Конечная точка:
new mapboxgl.Marker({
color: 'red'
})
.setLngLat(destination)
.addTo(map);
Навигационные шаги можно преобразовать в удобный массив.
const steps = route.legs[0].steps;
Получение инструкций:
const instructions = steps.map(step => ({
text: step.maneuver.instruction,
distance: step.distance
}));
Результат:
[
{
text: "Двигайтесь прямо",
distance: 200
},
{
text: "Поверните направо",
distance: 150
}
]
Создание списка:
const container =
document.getElementById('instructions');
Заполнение:
steps.forEach(step => {
const item = document.createElement('div');
item.textContent =
`${step.maneuver.instruction}
(${Math.round(step.distance)} м)`;
container.appendChild(item);
});
HTML:
<div id="instructions"></div>
Для пошаговой навигации необходимо понимать, возле какого манёвра находится пользователь.
Положение пользователя:
const userPosition =
[37.6200, 55.7560];
Координаты следующего манёвра:
const maneuverLocation =
currentStep.maneuver.location;
Необходимо вычислить расстояние между двумя точками.
Для этого часто используется библиотека Turf.js.
Подключение Turf:
<script src="https://unpkg.com/@turf/turf"></script>
Расстояние:
const from =
turf.point(userPosition);
const to =
turf.point(maneuverLocation);
const distance =
turf.distance(from, to, {
units: 'meters'
});
Проверка:
if (distance < 20) {
moveToNextStep();
}
Когда пользователь оказывается рядом с манёвром, система переключается на следующий шаг.
Текущий индекс шага:
let currentStepIndex = 0;
Получение инструкции:
function getCurrentStep() {
return steps[currentStepIndex];
}
Переход:
function moveToNextStep() {
currentStepIndex++;
updateInstruction();
}
Обновление интерфейса:
function updateInstruction() {
const step = getCurrentStep();
instructionElement.textContent =
step.maneuver.instruction;
}
Расстояние до манёвра может обновляться в режиме реального времени.
distanceElement.textContent =
`${Math.round(distance)} м`;
Типичный интерфейс:
Через 150 м поверните налево
или
Через 40 м поверните направо
Для реальной навигации необходимо отслеживать местоположение устройства.
Запуск отслеживания:
navigator.geolocation.watchPosition(
position => {
const lng =
position.coords.longitude;
const lat =
position.coords.latitude;
updateNavigation([lng, lat]);
},
error => {
console.error(error);
},
{
enableHighAccuracy: true
}
);
Каждое обновление координат запускает пересчёт навигации.
Создание маркера:
const userMarker =
new mapboxgl.Marker({
color: 'blue'
})
.setLngLat(start)
.addTo(map);
Обновление положения:
userMarker.setLngLat([
lng,
lat
]);
Пользователь визуально перемещается по маршруту.
При движении карта может следовать за объектом.
map.easeTo({
center: [lng, lat],
zoom: 17,
duration: 500
});
Такой подход создаёт эффект автомобильного навигатора.
Для повышения удобства карта может автоматически вращаться.
Пример:
map.easeTo({
bearing: heading,
duration: 300
});
Где:
heading =
position.coords.heading;
Если устройство поддерживает определение направления движения, карта всегда будет ориентирована вперёд по маршруту.
Пользователь может отклониться от рассчитанного пути.
Для обнаружения используется расстояние до линии маршрута.
Создание точки:
const point =
turf.point(userPosition);
Создание линии:
const line =
turf.lineString(
route.geometry.coordinates
);
Расстояние до маршрута:
const distance =
turf.pointToLineDistance(
point,
line,
{
units: 'meters'
}
);
Проверка:
if (distance > 50) {
recalculateRoute();
}
Функция может использовать текущее положение как новую стартовую точку.
async function recalculateRoute() {
const routeData =
await getRoute(
currentPosition,
destination
);
drawRoute(routeData);
}
Подобное поведение характерно для автомобильных навигаторов.
Для демонстрационных проектов полезно анимировать объект вдоль линии маршрута.
Получение координат:
const coordinates =
route.geometry.coordinates;
Перемещение:
let index = 0;
function animate() {
if (index >= coordinates.length) {
return;
}
userMarker.setLngLat(
coordinates[index]
);
index++;
requestAnimationFrame(
animate
);
}
Запуск:
animate();
Пошаговая навигация часто дополняется озвучиванием манёвров.
Использование Web Speech API:
function speak(text) {
const utterance =
new SpeechSynthesisUtterance(
text
);
speechSynthesis.speak(
utterance
);
}
Пример:
speak(
"Через сто метров поверните направо"
);
Озвучивание может запускаться при достижении определённого расстояния до манёвра.
Дополнительная статистика обычно выводится в отдельном блоке.
Расстояние:
const km =
(route.distance / 1000)
.toFixed(1);
Время:
const minutes =
Math.round(
route.duration / 60
);
Отображение:
tripInfo.innerHTML = `
<strong>${km} км</strong>
<br>
${minutes} мин
`;
Маршрут может содержать несколько остановок.
Пример координат:
const points = [
[37.6176, 55.7558],
[37.6400, 55.7600],
[37.6600, 55.7700],
[37.6810, 55.7600]
];
Формирование строки координат:
const coordinates =
points
.map(p => p.join(','))
.join(';');
Запрос:
const url =
`https://api.mapbox.com/directions/v5/
mapbox/driving/${coordinates}
?steps=true
&geometries=geojson
&access_token=${mapboxgl.accessToken}`;
В результате формируется сложный маршрут с несколькими участками и собственными наборами инструкций для каждого сегмента.
При реализации пошаговой навигации рекомендуется:
setData() для обновления GeoJSON;Грамотно реализованная пошаговая навигация в Mapbox GL JS позволяет создавать полноценные навигационные веб-приложения с отображением маршрутов, автоматическим сопровождением движения, голосовыми подсказками, отслеживанием положения пользователя и динамическим перестроением пути в режиме реального времени.