Маршрутизация в экосистеме Leaflet реализуется через плагин Leaflet Routing Machine, который добавляет слой построения маршрутов, управление точками и интеграцию с внешними routing-сервисами.
Подключение через CDN:
<link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine/dist/leaflet-routing-machine.css" />
<script src="https://unpkg.com/leaflet-routing-machine/dist/leaflet-routing-machine.js"></script>
Также требуется базовый Leaflet:
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
При использовании npm:
npm install leaflet leaflet-routing-machine
import L from "leaflet";
import "leaflet-routing-machine";
Основная сущность плагина — L.Routing.control, которая
создаёт маршрут между точками.
const map = L.map("map").setView([51.505, -0.09], 13);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© OpenStreetMap contributors"
}).addTo(map);
L.Routing.control({
waypoints: [
L.latLng(51.505, -0.09),
L.latLng(51.515, -0.1)
]
}).addTo(map);
После выполнения создаётся маршрут с интерактивной линией и маркерами точек.
Маршрут строится на основе массива waypoints.
waypoints: [
L.latLng(lat1, lng1),
L.latLng(lat2, lng2)
]
Особенности:
Программное обновление:
routingControl.setWaypoints([
L.latLng(51.5, -0.1),
L.latLng(51.52, -0.12),
L.latLng(51.53, -0.13)
]);
Очистка маршрута:
routingControl.setWaypoints([]);
По умолчанию используется сервис OSRM (Open Source Routing Machine).
Явная настройка:
L.Routing.control({
router: L.Routing.osrmv1({
serviceUrl: "https://router.project-osrm.org/route/v1"
}),
waypoints: [
L.latLng(51.505, -0.09),
L.latLng(51.515, -0.1)
]
}).addTo(map);
OSRM обеспечивает:
L.Routing.control({
router: L.Routing.mapbox("TOKEN_API"),
waypoints: [
L.latLng(51.505, -0.09),
L.latLng(51.515, -0.1)
]
}).addTo(map);
Поддерживает:
L.Routing.control({
router: L.Routing.graphHopper("API_KEY"),
waypoints: [
L.latLng(51.505, -0.09),
L.latLng(51.515, -0.1)
]
}).addTo(map);
Особенности:
lineOptions: {
styles: [
{ color: "blue", opacity: 0.7, weight: 5 }
]
}
showAlternatives: true
Система возвращает несколько вариантов пути, которые можно переключать.
По умолчанию добавляется панель управления. Её можно скрыть:
L.Routing.control({
show: false
})
Или полностью отключить создание UI:
createMarker: function() { return null; }
createMarker: function(i, waypoint, n) {
return L.marker(waypoint.latLng, {
draggable: true
}).bindPopup(`Точка ${i + 1}`);
}
Расширенные сценарии:
routingControl.on("routesfound", function(e) {
const routes = e.routes;
console.log(routes[0].summary);
});
routingControl.on("routingerror", function(e) {
console.error(e.error);
});
routingControl.on("waypointschanged", function(e) {
console.log("Waypoints updated");
});
Объект маршрута содержит:
distance — длина маршрутаtime — время в секундахcoordinates — массив точек линииinstructions — пошаговые инструкцииПример обработки:
routingControl.on("routesfound", function(e) {
const route = e.routes[0];
console.log("Distance:", route.summary.totalDistance);
console.log("Time:", route.summary.totalTime);
route.instructions.forEach(step => {
console.log(step.text);
});
});
Leaflet Routing Machine не включает встроенный геокодер, но поддерживает интеграцию:
geocoder: L.Control.Geocoder.nominatim()
Пример подключения:
L.Routing.control({
geocoder: L.Control.Geocoder.nominatim()
}).addTo(map);
Это позволяет:
Частый сценарий — обновление маршрута по клику:
map.on("click", function(e) {
const waypoints = routingControl.getWaypoints();
waypoints.push(e.latlng);
routingControl.setWaypoints(waypoints);
});
При большом количестве запросов маршрутизации учитываются ограничения:
Пример debounce:
let timeout;
map.on("click", function(e) {
clearTimeout(timeout);
timeout = setTimeout(() => {
routingControl.spliceWaypoints(
routingControl.getWaypoints().length,
0,
e.latlng
);
}, 300);
});
altLineOptions: {
styles: [
{ color: "gray", opacity: 0.5, weight: 4 }
]
}
Переключение маршрутов выполняется автоматически через UI или программно:
routingControl.setAlternatives([
route1,
route2
]);
Маршруты часто строятся на основе внешних данных:
fetch("/api/points")
.then(res => res.json())
.then(points => {
routingControl.setWaypoints(
points.map(p => L.latLng(p.lat, p.lng))
);
});
При использовании публичного сервера:
В production-средах обычно используется собственный OSRM-инстанс.
Настройка кастомного backend:
L.Routing.control({
router: L.Routing.osrmv1({
serviceUrl: "https://my-server.com/route/v1"
})
}).addTo(map);
Преимущества:
CSS переопределение:
.leaflet-routing-container {
background: white;
font-size: 14px;
}
.leaflet-routing-alt {
max-height: 200px;
overflow-y: auto;
}
Удаление последней точки:
routingControl.spliceWaypoints(
routingControl.getWaypoints().length - 1,
1
);
Замена стартовой точки:
routingControl.spliceWaypoints(0, 1, L.latLng(51.51, -0.11));
Маршрут можно комбинировать с:
L.geoJSON(data).addTo(map);
routingControl.addTo(map);
Leaflet Routing Machine допускает расширение через:
planПример кастомного форматтера:
formatter: new L.Routing.Formatter({
language: "ru"
})
В SPA-приложениях маршрутизация часто управляется состоянием:
history.pushState({}, "", `?from=${a.lat},${a.lng}&to=${b.lat},${b.lng}`);
При массовых изменениях:
routingControl.route();