Расчёт времени в пути в веб-картографии опирается на построение маршрута по дорожному графу и оценку стоимости каждого ребра графа. В контексте веб-карт и интерактивной визуализации ключевую роль играет сочетание геометрии маршрута и весов рёбер, где весом выступает время прохождения сегмента дороги.
В Mapbox GL JS отображение маршрутов и работа с данными маршрутизации обычно разделяются на два уровня:
Время в пути не вычисляется непосредственно библиотекой отображения карты, а поступает из внешнего сервиса маршрутизации, который учитывает дорожную сеть, ограничения скорости, повороты и при наличии данных — трафик.
Основной источник данных о времени в пути — сервис маршрутизации
Mapbox. Он возвращает маршрут в виде GeoJSON-подобной структуры с
набором метаданных, где ключевым параметром является
duration.
Запрос к API маршрута формируется через HTTP:
const accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';
const url = `https://api.mapbox.com/directions/v5/mapbox/driving/30.3351,59.9343;30.3609,59.9227
?alternatives=false
&geometries=geojson
&steps=true
&access_token=${accessToken}`;
fetch(url)
.then(res => res.json())
.then(data => {
const route = data.routes[0];
console.log(route.duration);
});
Поле duration возвращается в секундах и отражает
оценочное время прохождения всего маршрута.
Каждый маршрут содержит несколько ключевых метрик:
distance — длина маршрута в метрахduration — время в секундахlegs — сегменты маршрута между точкамиПример структуры:
{
"routes": [
{
"distance": 5230.4,
"duration": 812.6,
"legs": [
{
"distance": 5230.4,
"duration": 812.6
}
]
}
]
}
Перевод в удобный формат обычно выполняется на стороне клиента:
function formatDuration(seconds) {
const minutes = Math.round(seconds / 60);
return `${minutes} мин`;
}
После получения геометрии маршрута данные добавляются как источник (source) и слой (layer):
map.on('load', () => {
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': 5
}
});
});
Время в пути обычно связывается с UI-элементами:
document.getElementById('time').textContent =
formatDuration(route.duration);
Расчёт времени может учитывать трафик при использовании соответствующих профилей маршрутизации:
drivingdriving-trafficПри включении трафика значение duration становится
динамическим и зависит от времени суток.
const url = `https://api.mapbox.com/directions/v5/mapbox/driving-traffic/${coords}
?access_token=${accessToken}`;
Разница между режимами:
driving — статическая модель скоростиdriving-traffic — прогноз с учётом текущей и
исторической загруженности дорогДля расчёта времени между множеством точек используется Matrix API. Он возвращает таблицу попарных значений времени.
Пример запроса:
const url = `https://api.mapbox.com/directions-matrix/v1/mapbox/driving/30.3,59.9;30.4,59.92;30.5,59.91
?access_token=${accessToken}`;
fetch(url)
.then(res => res.json())
.then(data => {
console.log(data.durations);
});
Результат:
{
"durations": [
[0, 120, 240],
[110, 0, 180],
[230, 190, 0]
]
}
Каждое значение — время в секундах между точками.
Matrix API применяется для:
Пример поиска минимального времени:
function findNearest(durations) {
const origin = durations[0];
let min = Infinity;
let index = -1;
for (let i = 1; i < origin.length; i++) {
if (origin[i] < min) {
min = origin[i];
index = i;
}
}
return { index, time: min };
}
Хотя основной способ — использование API, иногда применяется приближённый расчёт на основе длины маршрута и средней скорости.
function estimateTime(distanceMeters, avgSpeedKmh) {
const distanceKm = distanceMeters / 1000;
return (distanceKm / avgSpeedKmh) * 3600;
}
Этот подход используется:
При движении объекта по маршруту время пересчитывается динамически. Логика основана на остаточном расстоянии.
function remainingTime(remainingDistance, avgSpeedKmh) {
return estimateTime(remainingDistance, avgSpeedKmh);
}
Визуализация часто включает:
Маршрут состоит из набора координат. Для более точного расчёта используется сегментация:
function segmentDistance(coords) {
let total = 0;
for (let i = 1; i < coords.length; i++) {
const [x1, y1] = coords[i - 1];
const [x2, y2] = coords[i];
total += Math.sqrt((x2 - x1)**2 + (y2 - y1)**2);
}
return total;
}
Хотя это упрощённая модель (без проекции на сферу), она используется в визуальных слоях для оценки прогресса.
Типичный сценарий объединяет маршрут и UI:
map.on('click', (e) => {
const coords = `${startLng},${startLat};${e.lngLat.lng},${e.lngLat.lat}`;
fetch(`https://api.mapbox.com/directions/v5/mapbox/driving/${coords}?access_token=${accessToken}`)
.then(res => res.json())
.then(data => {
const route = data.routes[0];
map.getSource('route').setData(route.geometry);
document.getElementById('eta').textContent =
Math.round(route.duration / 60) + ' мин';
});
});
Для уменьшения количества запросов применяются стратегии кэширования:
const cache = new Map();
function getCachedRoute(key) {
return cache.get(key);
}
function setCachedRoute(key, value) {
cache.set(key, value);
}
При работе с временем маршрута возникают специфические ситуации:
В таких случаях API возвращает несколько маршрутов:
data.routes.forEach(r => {
console.log(r.duration, r.distance);
});
Выбор маршрута обычно производится по минимальному
duration, если не задана иная стратегия оптимизации.