Формат GeoJSON

Leaflet активно использует GeoJSON как основной стандарт обмена географическими данными. GeoJSON представляет собой текстовый формат на основе JSON, предназначенный для описания геометрии объектов, их свойств и пространственных коллекций. Его ключевая особенность — строгая структура и совместимость с большинством геоинформационных систем и веб-картографических библиотек.

Структура GeoJSON

GeoJSON-документ всегда является объектом JSON с обязательным полем type. Основные структуры включают:

  • Feature
  • FeatureCollection
  • Геометрии (Point, LineString, Polygon и другие)

Базовая структура Feature:

{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [30.5, 50.5]
  },
  "properties": {
    "name": "Объект",
    "category": "marker"
  }
}

FeatureCollection объединяет несколько объектов:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [30.5, 50.5]
      },
      "properties": {
        "name": "Точка A"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [30.1, 50.1],
          [30.9, 50.9]
        ]
      },
      "properties": {
        "name": "Линия"
      }
    }
  ]
}

Геометрические типы

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

Point

Одиночная точка на карте:

{
  "type": "Point",
  "coordinates": [30.5, 50.5]
}

LineString

Ломаная линия, состоящая из массива координат:

{
  "type": "LineString",
  "coordinates": [
    [30.1, 50.1],
    [30.2, 50.2],
    [30.3, 50.3]
  ]
}

Polygon

Многоугольник, задаваемый замкнутым контуром:

{
  "type": "Polygon",
  "coordinates": [
    [
      [30.0, 50.0],
      [31.0, 50.0],
      [31.0, 51.0],
      [30.0, 50.0]
    ]
  ]
}

MultiPoint, MultiLineString, MultiPolygon

Используются для хранения множественных объектов одного типа. Например, MultiPolygon позволяет описывать сложные области с островами и внутренними границами.

Особенности координатной системы

GeoJSON использует порядок координат:

[долгота, широта]

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

Координаты всегда задаются в системе WGS84 (EPSG:4326), что обеспечивает глобальную совместимость.

Использование GeoJSON в Leaflet

В Leaflet работа с GeoJSON реализуется через метод L.geoJSON().

Базовый пример загрузки данных:

L.geoJSON(geojsonData).addTo(map);

Где geojsonData — объект GeoJSON.

Настройка отображения объектов

Параметр style

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

L.geoJSON(geojsonData, {
  style: function (feature) {
    return {
      color: "blue",
      weight: 3,
      opacity: 0.7
    };
  }
}).addTo(map);

pointToLayer

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

L.geoJSON(geojsonData, {
  pointToLayer: function (feature, latlng) {
    return L.circleMarker(latlng, {
      radius: 6,
      fillColor: "red",
      color: "#000",
      weight: 1,
      opacity: 1,
      fillOpacity: 0.8
    });
  }
}).addTo(map);

Работа с событиями через onEachFeature

GeoJSON-слой позволяет привязывать события к каждому объекту:

L.geoJSON(geojsonData, {
  onEachFeature: function (feature, layer) {
    layer.bindPopup(feature.properties.name);
  }
}).addTo(map);

Этот механизм используется для:

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

Фильтрация данных

GeoJSON можно фильтровать до отображения:

L.geoJSON(geojsonData, {
  filter: function (feature) {
    return feature.properties.category === "park";
  }
}).addTo(map);

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

Работа с FeatureCollection и слоями

GeoJSON в Leaflet автоматически преобразуется в слои:

  • Point → Marker или CircleMarker
  • LineString → Polyline
  • Polygon → Polygon

Каждый объект становится отдельным Leaflet-слоем, что позволяет управлять ими через стандартные методы:

geoLayer.eachLayer(function (layer) {
  layer.setStyle({ color: "green" });
});

Доступ к данным объектов

Каждый слой хранит ссылку на исходный Feature:

L.geoJSON(geojsonData, {
  onEachFeature: function (feature, layer) {
    console.log(feature.properties);
  }
});

Это позволяет связывать визуальные элементы с бизнес-данными.

Вложенные и сложные структуры

GeoJSON поддерживает вложенные структуры, включая:

  • MultiPolygon с внутренними отверстиями
  • коллекции объектов с разными типами геометрии
  • комбинации FeatureCollection внутри FeatureCollection (через агрегацию на уровне приложения)

Пример Polygon с отверстием:

{
  "type": "Polygon",
  "coordinates": [
    [
      [0, 0],
      [10, 0],
      [10, 10],
      [0, 10],
      [0, 0]
    ],
    [
      [2, 2],
      [8, 2],
      [8, 8],
      [2, 8],
      [2, 2]
    ]
  ]
}

Производительность при работе с GeoJSON

При больших объёмах данных поведение зависит от нескольких факторов:

  • количество объектов
  • сложность геометрии
  • наличие стилей и событий

Практическая модель оптимизации:

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

Преобразование GeoJSON в слои и обратно

Leaflet позволяет извлекать GeoJSON из слоя:

const data = geoLayer.toGeoJSON();

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

  • сохранении изменений пользователя
  • редактировании геометрий
  • синхронизации с сервером

Типичные ошибки при работе с GeoJSON

Неверный порядок координат

Частая проблема:

[широта, долгота] вместо [долгота, широта]

Отсутствие Feature-обёртки

Некоторые API возвращают геометрию без Feature, что требует преобразования.

Некорректные замыкания Polygon

Polygon должен быть замкнутым, первая и последняя координаты должны совпадать.

Несоответствие типов

LineString не может содержать вложенные массивы, предназначенные для Polygon.

Интеграция GeoJSON с динамическими источниками

GeoJSON часто используется как формат обмена с API:

fetch("/api/objects")
  .then(res => res.json())
  .then(data => {
    L.geoJSON(data).addTo(map);
  });

Динамическая загрузка позволяет:

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

Расширение GeoJSON через properties

Поле properties не ограничено стандартом и используется как контейнер бизнес-логики:

"properties": {
  "id": 123,
  "status": "active",
  "population": 50000
}

Эти данные используются для:

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