GeoJSON источник

Роль GeoJSON в архитектуре источников

GeoJSON представляет собой один из базовых форматов описания географических данных в MapLibre GL JS. Он используется для передачи векторной информации в виде точек, линий и полигонов, а также их комбинаций в составе коллекций объектов. В контексте рендеринга карты GeoJSON выступает как динамический источник, позволяющий управлять слоями через структуру данных, а не через статические тайлы.

Ключевая особенность GeoJSON-источника заключается в том, что данные хранятся и обрабатываются на стороне клиента. Это открывает возможность оперативного обновления объектов карты без необходимости перегенерации тайлового слоя.

Структура GeoJSON-источника

В MapLibre GL JS источник типа geojson определяется внутри конфигурации карты через добавление в sources:

map.addSource('points-source', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: []
  }
});

Минимальная структура GeoJSON включает:

  • FeatureCollection — контейнер для набора объектов
  • Feature — отдельный объект геометрии
  • geometry — тип геометрии (Point, LineString, Polygon)
  • properties — пользовательские атрибуты объекта

Пример одного объекта:

{
  type: 'Feature',
  geometry: {
    type: 'Point',
    coordinates: [37.6173, 55.7558]
  },
  properties: {
    title: 'Москва',
    population: 12000000
  }
}

Подключение GeoJSON как источника данных

GeoJSON может быть передан в источник тремя основными способами:

  1. Inline-объект
  2. Внешний URL
  3. Динамическое обновление через setData

Пример загрузки через URL:

map.addSource('cities', {
  type: 'geojson',
  data: 'https://example.com/cities.geojson'
});

MapLibre автоматически выполняет загрузку и парсинг данных, после чего источник становится доступным для слоёв.

Связывание GeoJSON с визуальными слоями

Источник сам по себе не отображается на карте. Он используется слоями (layers), которые интерпретируют данные.

Отображение точек

map.addLayer({
  id: 'cities-layer',
  type: 'circle',
  source: 'cities',
  paint: {
    'circle-radius': 6,
    'circle-color': '#3b82f6'
  }
});

Отображение линий

map.addLayer({
  id: 'routes-layer',
  type: 'line',
  source: 'routes',
  paint: {
    'line-color': '#ef4444',
    'line-width': 2
  }
});

Отображение полигонов

map.addLayer({
  id: 'areas-layer',
  type: 'fill',
  source: 'areas',
  paint: {
    'fill-color': '#10b981',
    'fill-opacity': 0.4
  }
});

Динамическое обновление данных

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

Метод setData используется для замены содержимого источника:

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

source.setData({
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [30.3141, 59.9386]
      },
      properties: {
        title: 'Санкт-Петербург'
      }
    }
  ]
});

Каждое обновление приводит к пересчёту визуализации всех связанных слоёв.

Фильтрация GeoJSON-данных на уровне слоя

MapLibre позволяет фильтровать отображаемые объекты без изменения исходного GeoJSON:

map.setFilter('cities-layer', [
  '>',
  ['get', 'population'],
  1000000
]);

Фильтры поддерживают выражения:

  • сравнение значений
  • логические операции
  • работа с атрибутами properties
  • геометрические условия

Кластеризация точечных данных

Для больших наборов точек GeoJSON поддерживает кластеризацию, что снижает нагрузку на рендеринг.

map.addSource('points', {
  type: 'geojson',
  data: 'points.geojson',
  cluster: true,
  clusterMaxZoom: 14,
  clusterRadius: 50
});

Дополнительно создаются слои для отображения кластеров:

map.addLayer({
  id: 'clusters',
  type: 'circle',
  source: 'points',
  filter: ['has', 'point_count'],
  paint: {
    'circle-radius': 18,
    'circle-color': '#f59e0b'
  }
});

И слой для одиночных точек:

map.addLayer({
  id: 'unclustered-point',
  type: 'circle',
  source: 'points',
  filter: ['!', ['has', 'point_count']],
  paint: {
    'circle-radius': 5,
    'circle-color': '#2563eb'
  }
});

Управление идентификаторами объектов

При работе с динамическими данными важно иметь стабильный идентификатор объектов. Для этого используется параметр promoteId:

map.addSource('cities', {
  type: 'geojson',
  data: 'cities.geojson',
  promoteId: 'id'
});

Каждый Feature должен содержать поле id или указанное свойство.

Ограничения GeoJSON-источников

GeoJSON в MapLibre имеет ряд технических ограничений:

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

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

Пространственные трансформации и управление геометрией

GeoJSON поддерживает стандартные геометрические типы:

  • Point
  • LineString
  • Polygon
  • MultiPoint
  • MultiLineString
  • MultiPolygon

Каждый тип интерпретируется слоем по-своему. Например, Polygon требует замкнутого контура координат:

{
  type: 'Feature',
  geometry: {
    type: 'Polygon',
    coordinates: [
      [
        [30, 50],
        [40, 50],
        [40, 60],
        [30, 60],
        [30, 50]
      ]
    ]
  }
}

Использование внешних GeoJSON-источников

При загрузке данных с сервера важно учитывать формат ответа и CORS-политику. MapLibre ожидает корректный JSON-ответ с типом application/json.

fetch('/data/map.geojson')
  .then(response => response.json())
  .then(data => {
    map.getSource('dynamic').setData(data);
  });

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

Оптимизация работы с GeoJSON

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

  • упрощение геометрии (simplification)
  • сокращение числа свойств в properties
  • разделение данных на несколько источников
  • использование кластеризации для точек
  • ограничение обновлений setData

Особенно критичным становится количество вершин в LineString и Polygon, так как каждая точка участвует в отрисовке WebGL-сценой.

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

GeoJSON-слои могут участвовать в обработке событий:

map.on('click', 'cities-layer', (e) => {
  const feature = e.features[0];
  console.log(feature.properties.title);
});

При включённом queryRenderedFeatures возможно извлечение объектов напрямую из слоя, что делает GeoJSON-источник интерактивным компонентом пользовательского интерфейса карты.