В веб-картографии под альтернативными маршрутами понимается набор различных траекторий движения между одной и той же парой точек, рассчитанных с учётом различных критериев оптимизации. Классическая задача кратчайшего пути не ограничивается единственным решением: при изменении параметров стоимости ребёр графа появляются маршруты, отличающиеся по длине, времени, количеству поворотов, дорожным ограничениям или дорожной обстановке.
В рамках веб-клиентов визуализация таких маршрутов реализуется поверх интерактивных картографических библиотек, среди которых ключевую роль занимает MapLibre GL JS, обеспечивающая рендеринг векторных слоёв и динамическое обновление геометрий через источники данных.
MapLibre GL JS не выполняет маршрутизацию самостоятельно. Она оперирует результатами внешних routing-движков, которые формируют геометрию маршрутов в формате GeoJSON или polyline.
На практике используются специализированные серверные решения:
Каждый из них способен возвращать несколько альтернативных маршрутов при включённой соответствующей опции запроса.
Пример логики генерации:
В случае OSRM параметр alternatives=true инициирует
поиск дополнительных маршрутов с ограничением на степень отклонения от
основного пути.
Типовая структура ответа маршрутизатора включает массив маршрутов:
{
"routes": [
{
"geometry": "...",
"distance": 12000,
"duration": 900
},
{
"geometry": "...",
"distance": 12500,
"duration": 870
}
]
}
Каждый маршрут преобразуется в GeoJSON LineString:
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [[lon, lat], [lon, lat]]
},
"properties": {
"id": 1,
"distance": 12000,
"duration": 900
}
}
Такая структура позволяет MapLibre GL JS рендерить каждый маршрут как отдельный слой или как набор feature внутри одного source.
В MapLibre GL JS альтернативные маршруты обычно реализуются через один GeoJSON source и несколько line layers.
Базовая схема:
один источник данных route-source
несколько слоёв:
map.addSource('routes', {
type: 'geojson',
data: routesGeojson
});
Далее добавляются слои:
map.addLayer({
id: 'route-alt',
type: 'line',
source: 'routes',
filter: ['==', ['get', 'selected'], false],
paint: {
'line-color': '#888',
'line-width': 4,
'line-opacity': 0.6
}
});
map.addLayer({
id: 'route-main',
type: 'line',
source: 'routes',
filter: ['==', ['get', 'selected'], true],
paint: {
'line-color': '#2E86FF',
'line-width': 6,
'line-opacity': 1
}
});
Такое разделение позволяет отделить визуально основной маршрут от альтернатив без дублирования источников.
Альтернативные маршруты предполагают интерактивность: выбор одного варианта изменяет состояние карты.
Механизм обновления данных:
function setSelectedRoute(index) {
const updated = {
type: 'FeatureCollection',
features: routes.features.map((f, i) => ({
...f,
properties: {
...f.properties,
selected: i === index
}
}))
};
map.getSource('routes').setData(updated);
}
MapLibre GL JS перерасчитывает стили слоёв без перерисовки всей сцены, что критично для производительности при частых обновлениях.
Для работы с альтернативами важна читаемость, особенно при пересечении геометрий.
Используются следующие техники:
Пример стилизации:
'line-dasharray': [2, 2]
или градиент:
'line-gradient': [
'interpolate',
['linear'],
['line-progress'],
0, '#00c853',
1, '#d50000'
]
Каждый альтернативный маршрут сопровождается метаданными:
Эти параметры используются не только для отображения, но и для ранжирования.
Пример функции выбора:
function score(route) {
return route.distance * 0.5 + route.duration * 0.5;
}
На практике весовые коэффициенты зависят от домена: логистика, пешеходная навигация, автомобильная навигация.
В некоторых архитектурах альтернативные маршруты не разделяются на слои, а объединяются в MultiLineString:
{
"type": "Feature",
"geometry": {
"type": "MultiLineString",
"coordinates": [
[[lon, lat], [lon, lat]],
[[lon, lat], [lon, lat]]
]
}
}
В таком случае MapLibre GL JS использует один слой, а различие
маршрутов задаётся через feature-state или свойства.
Feature-state позволяет изменять визуальные свойства без пересоздания GeoJSON:
map.setFeatureState(
{ source: 'routes', id: 1 },
{ selected: true }
);
И в стиле слоя:
'line-color': [
'case',
['boolean', ['feature-state', 'selected'], false],
'#2E86FF',
'#999'
]
Такой подход снижает нагрузку при большом количестве альтернатив.
При изменении условий движения альтернативные маршруты могут пересчитываться:
Архитектура обновления обычно включает:
При увеличении числа альтернатив возникают проблемы производительности:
Оптимизации:
Альтернативные маршруты часто интегрируются в интерфейсы:
MapLibre GL JS выступает только как слой визуализации, тогда как логика выбора реализуется на уровне бизнес-логики приложения.
При наложении альтернатив возникают проблемы визуального перекрытия. Для их решения применяются:
Пример:
'line-translate': [2, 2]
Система альтернативных маршрутов в связке с MapLibre GL JS представляет собой многоуровневую архитектуру:
Такая декомпозиция позволяет масштабировать навигационные сценарии от простых картографических визуализаций до полноценных навигационных систем с динамическим выбором маршрутов.