LineString геометрия

LineString представляет собой линейную геометрию, описывающую последовательность координат, соединённых непрерывной линией. В контексте веб-картографии и MapLibre GL JS этот тип геометрии используется для отображения маршрутов, треков, дорог, кабельных линий, траекторий движения и любых других объектов, обладающих линейной природой без ширины и площади как у полигонов.

LineString в MapLibre GL JS базируется на стандарте GeoJSON. Структура данных строго определена:

{
  "type": "LineString",
  "coordinates": [
    [37.6173, 55.7558],
    [37.6250, 55.7600],
    [37.6400, 55.7700]
  ]
}

Ключевые особенности:

  • координаты задаются в формате [долгота, широта]
  • минимум две точки обязательны
  • порядок точек определяет направление линии
  • интерпретация координат всегда географическая (WGS84)

LineString не содержит свойств ширины или стиля — он описывает только геометрию. Визуальное представление задаётся на уровне слоя (layer).

Источник данных LineString в MapLibre GL JS

Для отображения LineString в MapLibre GL JS используется источник типа geojson:

map.on('load', () => {
  map.addSource('route', {
    type: 'geojson',
    data: {
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: [
          [37.6173, 55.7558],
          [37.6250, 55.7600],
          [37.6400, 55.7700]
        ]
      }
    }
  });
});

Важно учитывать:

  • источник может содержать как Feature, так и FeatureCollection
  • LineString обычно помещается в Feature.geometry
  • данные могут динамически обновляться через setData

Отображение LineString через слой line

Для визуализации используется слой типа line:

map.addLayer({
  id: 'route-line',
  type: 'line',
  source: 'route',
  layout: {
    'line-join': 'round',
    'line-cap': 'round'
  },
  paint: {
    'line-color': '#3b82f6',
    'line-width': 4
  }
});

Основные параметры отображения

line-color

  • задаёт цвет линии
  • поддерживает выражения и интерполяции

line-width

  • толщина линии в пикселях
  • может зависеть от масштаба

line-opacity

  • прозрачность линии
  • значение от 0 до 1

line-dasharray

  • создание пунктирных линий
  • массив чисел определяет паттерн

Пример пунктирной линии:

paint: {
  'line-color': '#ef4444',
  'line-width': 3,
  'line-dasharray': [2, 2]
}

Работа с несколькими LineString в одном источнике

GeoJSON поддерживает коллекции:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "LineString",
        "coordinates": [[0, 0], [10, 10]]
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "LineString",
        "coordinates": [[10, 0], [20, 10]]
      }
    }
  ]
}

MapLibre GL JS автоматически отрисует каждую линию в рамках одного слоя.

Динамическое обновление LineString

Одно из ключевых преимуществ GeoJSON источников — возможность обновления данных:

const source = map.getSource('route');

source.setData({
  type: 'Feature',
  geometry: {
    type: 'LineString',
    coordinates: [
      [37.6173, 55.7558],
      [37.6500, 55.7800],
      [37.7000, 55.8000]
    ]
  }
});

Это используется для:

  • обновления треков GPS в реальном времени
  • анимации движения объектов
  • построения маршрутов после вычислений на сервере

Анимация линии через интерполяцию координат

LineString часто применяется для визуализации движения. Простейший подход — постепенное увеличение массива координат.

let index = 1;

function animateLine() {
  const coords = fullRoute.slice(0, index);

  map.getSource('route').setData({
    type: 'Feature',
    geometry: {
      type: 'LineString',
      coordinates: coords
    }
  });

  index++;
  if (index <= fullRoute.length) {
    requestAnimationFrame(animateLine);
  }
}

Более сложные сценарии используют интерполяцию между точками, особенно при работе с временными рядами GPS-данных.

Стилизация LineString через выражения

MapLibre GL JS поддерживает мощную систему выражений:

paint: {
  'line-color': [
    'interpolate',
    ['linear'],
    ['zoom'],
    5, '#2563eb',
    10, '#10b981',
    15, '#f59e0b'
  ],
  'line-width': [
    'interpolate',
    ['linear'],
    ['zoom'],
    5, 2,
    15, 8
  ]
}

Такой подход позволяет:

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

Обработка кликов по LineString

Для интерактивности используется событие click:

map.on('click', 'route-line', (e) => {
  const features = map.queryRenderedFeatures(e.point, {
    layers: ['route-line']
  });

  if (features.length) {
    console.log(features[0].geometry);
  }
});

Дополнительно можно реализовать:

  • выделение линии при наведении
  • подсветку сегментов
  • показ всплывающих окон с данными маршрута

Выделение активной линии

Часто используется второй слой для состояния hover:

map.addLayer({
  id: 'route-line-hover',
  type: 'line',
  source: 'route',
  paint: {
    'line-color': '#f97316',
    'line-width': 6
  },
  filter: ['==', ['get', 'id'], 'active']
});

Изменение состояния:

map.setFeatureState(
  { source: 'route', id: 1 },
  { active: true }
);

Разбиение LineString на сегменты

LineString можно использовать для анализа геометрии:

  • вычисление длины маршрута
  • определение поворотов
  • сегментация по расстоянию

Хотя MapLibre GL JS не выполняет геоаналитику, он отображает уже подготовленные данные.

Типичный подход:

  • сервер вычисляет сегменты
  • клиент визуализирует их как отдельные LineString

Оптимизация производительности

При работе с большими линиями (десятки тысяч точек):

  • использовать simplification (Douglas-Peucker)
  • уменьшать плотность координат при малых масштабах
  • избегать частых setData
  • разделять длинные линии на сегменты

Пример упрощения:

  • оригинальный трек: 50 000 точек
  • упрощённый: 2 000–5 000 точек

Работа с прерывистыми линиями

LineString не поддерживает разрывы внутри одной геометрии. Для разрывов используются:

  • MultiLineString
  • несколько Feature объектов
{
  "type": "MultiLineString",
  "coordinates": [
    [[0, 0], [5, 5]],
    [[10, 10], [15, 15]]
  ]
}

В MapLibre GL JS это позволяет:

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

Использование свойств feature для стилизации

LineString часто дополняется атрибутами:

{
  "type": "Feature",
  "properties": {
    "type": "highway",
    "speed": 80
  },
  "geometry": {
    "type": "LineString",
    "coordinates": [...]
  }
}

Далее свойства используются в стилях:

paint: {
  'line-color': [
    'match',
    ['get', 'type'],
    'highway', '#ef4444',
    'street', '#3b82f6',
    '#999999'
  ]
}

Геометрические ограничения и особенности

LineString имеет ряд строгих правил:

  • не может быть замкнутым (для этого используется Polygon)
  • не имеет толщины в геометрическом смысле
  • направление может быть значимым (например, в транспортных данных)
  • самопересечения допустимы, но не интерпретируются семантически

Типовые сценарии применения

LineString применяется в следующих задачах:

  • отображение маршрутов транспорта
  • визуализация логистических цепочек
  • трекинг GPS-устройств
  • отображение рек и каналов
  • построение пешеходных и велосипедных маршрутов
  • визуализация сетей (кабели, трубопроводы)

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

map.on('load', () => {
  map.addSource('track', {
    type: 'geojson',
    data: {
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: []
      }
    }
  });

  map.addLayer({
    id: 'track-line',
    type: 'line',
    source: 'track',
    paint: {
      'line-color': '#22c55e',
      'line-width': 5
    }
  });
});

function updateTrack(newPoint) {
  const source = map.getSource('track');
  const data = source._data;

  data.geometry.coordinates.push(newPoint);

  source.setData(data);
}

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

Использование LineString в связке с временными данными

LineString часто расширяется временной осью:

{
  "type": "Feature",
  "properties": {
    "timestamps": [1710000000, 1710000060, 1710000120]
  },
  "geometry": {
    "type": "LineString",
    "coordinates": [...]
  }
}

Это позволяет:

  • строить анимацию движения по времени
  • анализировать скорость
  • фильтровать сегменты по интервалам

Взаимодействие с камерой и масштабом

LineString тесно связан с визуальным восприятием карты:

  • при малом масштабе линии могут объединяться
  • при большом масштабе проявляются детали
  • line-width часто адаптируется под zoom
'line-width': [
  'interpolate',
  ['exponential', 1.5],
  ['zoom'],
  5, 1,
  18, 10
]

Такие настройки обеспечивают стабильное визуальное восприятие на всех уровнях масштабирования.