Интеграция маршрутизации в веб-карту строится вокруг разделения ответственности между картографическим движком и внешними сервисами вычисления маршрутов. OpenLayers обеспечивает отображение геометрии, управление слоями и взаимодействие с пользовательскими событиями, тогда как routing-сервисы отвечают за вычисление оптимального пути между точками с учётом дорожной сети, ограничений и транспортного профиля.
В типичной архитектуре присутствуют следующие компоненты:
Основной поток данных выглядит следующим образом: координаты точек → HTTP запрос → получение геометрии маршрута → декодирование → построение feature → рендеринг на карте.
Routing-сервисы можно разделить на несколько категорий по принципу предоставления данных и алгоритмов расчёта.
OSRM (Open Source Routing Machine) — высокопроизводительный движок, основанный на данных OpenStreetMap. Используется для быстрых расчётов маршрутов по предобработанному графу дорог.
GraphHopper — гибкий routing-движок, поддерживающий различные профили транспорта (автомобиль, велосипед, пешком), а также кастомные ограничения.
Mapbox Directions API от Mapbox предоставляет маршрутизацию как сервис с поддержкой пробок, профилей движения и альтернативных маршрутов.
OpenRouteService — сервис на основе OpenStreetMap данных с расширенными функциями изохрон, матриц расстояний и многоцелевой оптимизации.
OpenLayers не содержит встроенного routing-движка, поэтому интеграция выполняется через HTTP запросы и последующую обработку результата.
Типовая схема включает:
ol.FeatureVectorLayerconst url = `https://router.project-osrm.org/route/v1/driving/
${start[0]},${start[1]};${end[0]},${end[1]}
?overview=full&geometries=geojson`;
Ответ содержит структуру:
const url = `https://api.mapbox.com/directions/v5/mapbox/driving/
${start[0]},${start[1]};${end[0]},${end[1]}
?geometries=geojson&access_token=TOKEN`;
Сервис от Mapbox возвращает несколько альтернативных маршрутов, включая метаданные о трафике и манёврах.
const url = "https://api.openrouteservice.org/v2/directions/driving-car/geojson";
fetch(url, {
method: "POST",
headers: {
"Authorization": "API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
coordinates: [start, end]
})
});
После получения GeoJSON необходимо преобразовать данные в объект слоя.
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import Feature from 'ol/Feature';
import LineString from 'ol/geom/LineString';
const routeSource = new VectorSource();
const routeLayer = new VectorLayer({
source: routeSource,
style: new Style({
stroke: new Stroke({
color: '#2a7fff',
width: 4
})
})
});
function addRoute(geojson) {
const coords = geojson.features[0].geometry.coordinates;
const routeFeature = new Feature({
geometry: new LineString(coords)
});
routeSource.clear();
routeSource.addFeature(routeFeature);
}
Некоторые сервисы возвращают маршрут в сжатом виде (encoded polyline). В этом случае требуется декодирование.
import {decode} from '@mapbox/polyline';
const coords = decode(encodedPolyline)
.map(c => [c[1], c[0]]);
После декодирования данные приводятся к формату
[lon, lat], используемому в OpenLayers.
Routing-сервисы поддерживают multi-stop маршруты (waypoints). Формирование запроса усложняется:
const coordinates = [
start,
waypoint1,
waypoint2,
end
];
В зависимости от API:
; разделительДля динамических сценариев (перетаскивание точек, GPS трекинг) используется частое обновление маршрута.
function debounce(fn, delay) {
let t;
return (...args) => {
clearTimeout(t);
t = setTimeout(() => fn(...args), delay);
};
}
Использование:
const updateRoute = debounce(fetchRoute, 300);
OpenLayers предоставляет событийную модель для взаимодействия с объектами карты.
map.on('click', function (event) {
const coords = event.coordinate;
addPoint(coords);
updateRoute(currentPoints);
});
Визуальное представление маршрута зависит от слоя стилей.
const routeStyle = new Style({
stroke: new Stroke({
color: 'rgba(0, 120, 255, 0.8)',
width: 5
})
});
Дополнительно применяются:
Некоторые сервисы (например, Mapbox от Mapbox) возвращают несколько вариантов маршрута.
Структура обработки:
routes.forEach(route => {
const feature = new Feature({
geometry: new LineString(route.geometry.coordinates)
});
routeSource.addFeature(feature);
});
Повторяющиеся запросы между одинаковыми точками можно кешировать:
const cache = new Map();
function getCacheKey(a, b) {
return `${a.join(',')}-${b.join(',')}`;
}
Routing-сервисы поддерживают различные профили:
Пример для OSRM:
/route/v1/driving/
/route/v1/walking/
/route/v1/cycling/
Для GraphHopper профиль задаётся в параметрах запроса и влияет на граф дорог.
Все координаты должны соответствовать системе EPSG:4326 до передачи в API, а затем трансформироваться в проекцию карты OpenLayers (обычно EPSG:3857).
import {fromLonLat} from 'ol/proj';
const point = fromLonLat([lon, lat]);
Некоторые routing API возвращают пошаговые инструкции:
Эти данные могут быть связаны с координатами и отображаться как маркеры:
instructions.forEach(step => {
const marker = new Feature({
geometry: new Point(step.location)
});
routeSource.addFeature(marker);
});
Типовые сценарии:
Обработка:
try {
const res = await fetch(url);
if (!res.ok) throw new Error('Routing error');
} catch (e) {
routeSource.clear();
}
В сложных системах применяется fallback стратегия:
Это обеспечивает устойчивость системы при отказах API или ограничениях квоты.