Отображение маршрутов

Маршруты в OpenLayers реализуются через векторную геометрию, где основным примитивом выступает LineString — последовательность координат, формирующая линию на карте. Такая модель позволяет описывать как простые пути между двумя точками, так и сложные маршруты с множеством сегментов, поворотов и промежуточных узлов.

Векторный маршрут обычно помещается в слой VectorLayer, который использует источник данных VectorSource. Геометрия маршрута может быть создана вручную, загружена из GeoJSON, получена из внешнего API маршрутизации или импортирована из файлов форматов GPX/KML.


Геометрия маршрута: LineString

Базовая структура маршрута строится на основе объекта LineString, принимающего массив координат:

import LineString from 'ol/geom/LineString.js';

const routeGeometry = new LineString([
  [37.6173, 55.7558],
  [37.629, 55.75],
  [37.640, 55.745]
]);

Однако координаты в OpenLayers должны соответствовать проекции карты. В большинстве случаев используется EPSG:3857, поэтому географические координаты необходимо преобразовать:

import {fromLonLat} from 'ol/proj.js';

const routeGeometry = new LineString([
  fromLonLat([37.6173, 55.7558]),
  fromLonLat([37.629, 55.75]),
  fromLonLat([37.640, 55.745])
]);

Векторный слой маршрута

Для отображения линии используется комбинация VectorSource и VectorLayer.

import VectorSource from 'ol/source/Vector.js';
import VectorLayer from 'ol/layer/Vector.js';
import Feature from 'ol/Feature.js';

const routeFeature = new Feature({
  geometry: routeGeometry
});

const routeSource = new VectorSource({
  features: [routeFeature]
});

const routeLayer = new VectorLayer({
  source: routeSource
});

Добавление слоя в карту:

map.addLayer(routeLayer);

Стилизация маршрута

Визуальное оформление маршрута определяется через стиль Style и Stroke. Основные параметры включают цвет, толщину линии и тип штриховки.

import Style from 'ol/style/Style.js';
import Stroke from 'ol/style/Stroke.js';

const routeStyle = new Style({
  stroke: new Stroke({
    color: '#1e88e5',
    width: 4
  })
});

routeLayer.setStyle(routeStyle);

Пунктирные и альтернативные маршруты

Для отображения альтернативных маршрутов используется штриховая линия:

const alternativeStyle = new Style({
  stroke: new Stroke({
    color: '#90caf9',
    width: 3,
    lineDash: [10, 10]
  })
});

Такая визуализация часто применяется при сравнении нескольких маршрутов между одинаковыми точками.


Загрузка маршрута из GeoJSON

Наиболее распространённый способ получения маршрута — формат GeoJSON. OpenLayers предоставляет готовый формат GeoJSON для автоматического преобразования данных.

import GeoJSON from 'ol/format/GeoJSON.js';
import VectorSource from 'ol/source/Vector.js';

const geojsonSource = new VectorSource({
  url: '/api/route.geojson',
  format: new GeoJSON()
});

GeoJSON-структура маршрута:

{
  "type": "Feature",
  "geometry": {
    "type": "LineString",
    "coordinates": [
      [37.6173, 55.7558],
      [37.629, 55.75],
      [37.640, 55.745]
    ]
  }
}

При использовании GeoJSON важно учитывать систему координат. Часто данные приходят в EPSG:4326, что требует трансформации:

const geojsonFormat = new GeoJSON({
  featureProjection: 'EPSG:3857'
});

Построение маршрута через OSRM API

Маршруты могут формироваться динамически через внешние сервисы, например OSRM.

Запрос:

https://router.project-osrm.org/route/v1/driving/37.6173,55.7558;37.640,55.745?geometries=geojson

Обработка ответа:

fetch(url)
  .then(response => response.json())
  .then(data => {
    const coordinates = data.routes[0].geometry.coordinates;

    const route = new Feature({
      geometry: new LineString(
        coordinates.map(coord => fromLonLat(coord))
      )
    });

    routeSource.addFeature(route);
  });

В таких сценариях важным элементом становится преобразование координат из формата API в проекцию карты.


Обновление маршрута в реальном времени

При изменении точек маршрута геометрия может обновляться без пересоздания слоя:

routeGeometry.setCoordinates([
  fromLonLat([37.6173, 55.7558]),
  fromLonLat([37.6500, 55.7600])
]);

OpenLayers автоматически перерисует слой при изменении геометрии, так как наблюдает за состоянием объекта Feature.


Интерактивные маршруты

Маршруты могут реагировать на события карты. Например, изменение стиля при наведении:

map.on('pointermove', function (event) {
  map.forEachFeatureAtPixel(event.pixel, function (feature) {
    feature.setStyle(new Style({
      stroke: new Stroke({
        color: '#ff5252',
        width: 5
      })
    }));
  });
});

Для возврата исходного стиля обычно хранится отдельная ссылка на стиль по умолчанию.


Несколько маршрутов на карте

Для отображения нескольких маршрутов используется один слой с несколькими Feature:

const routes = new VectorSource({
  features: [
    new Feature({ geometry: route1 }),
    new Feature({ geometry: route2 }),
    new Feature({ geometry: route3 })
  ]
});

Каждый маршрут может иметь собственный стиль через функцию:

routeLayer.setStyle(function (feature) {
  const type = feature.get('type');

  if (type === 'fastest') {
    return fastStyle;
  }

  return alternativeStyle;
});

Импорт маршрутов из GPX и KML

OpenLayers поддерживает специализированные форматы через ol/format.

GPX:

import GPX from 'ol/format/GPX.js';

const source = new VectorSource({
  url: '/data/track.gpx',
  format: new GPX()
});

KML:

import KML from 'ol/format/KML.js';

const source = new VectorSource({
  url: '/data/route.kml',
  format: new KML()
});

Такие форматы часто содержат не только линии маршрута, но и точки интереса и временные данные.


Сглаживание и визуальная оптимизация маршрутов

При работе с большим количеством координат линия может выглядеть «ломаной». Для улучшения визуального восприятия применяется упрощение геометрии:

import {simplifyLineString} from 'ol/geom/flat/simplify.js';

Также используется уменьшение количества точек на этапе подготовки данных на сервере.


Масштабирование и подгонка маршрута под экран

После добавления маршрута часто выполняется автоматическое центрирование:

map.getView().fit(routeSource.getExtent(), {
  padding: [50, 50, 50, 50],
  duration: 1000
});

Это позволяет корректно отобразить весь маршрут в пределах текущего viewport.


Работа с направлением маршрута

Для отображения направления движения вдоль линии применяются символы (Icon или Circle) с привязкой к сегментам LineString:

import Point from 'ol/geom/Point.js';

const arrow = new Feature({
  geometry: new Point(routeGeometry.getCoordinateAt(0.5))
});

Для более сложных случаев используется вычисление угла наклона сегмента и динамическое размещение маркеров вдоль линии.


Производительность при большом количестве маршрутов

При отображении множества маршрутов критично учитывать:

  • использование упрощённых геометрий на низких масштабах
  • отключение ненужных стилей на неактивных слоях
  • кластеризацию точек, если маршрут включает остановки
  • минимизацию пересчёта координат в циклах рендеринга

Векторный рендер OpenLayers оптимизирован, но перегрузка количеством Feature приводит к деградации FPS, особенно при сложных стилях и анимации.


Анимация движения по маршруту

Перемещение объекта вдоль маршрута реализуется через интерполяцию координат:

const coords = routeGeometry.getCoordinates();
let index = 0;

function animate() {
  if (index < coords.length) {
    markerFeature.getGeometry().setCoordinates(coords[index]);
    index++;
    requestAnimationFrame(animate);
  }
}

Для плавного движения между точками применяется линейная интерполяция между сегментами линии, а не дискретный переход.