Загрузка GeoJSON-данных

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

Типичная структура GeoJSON включает набор объектов типа Feature внутри FeatureCollection:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [76.95, 43.25]
      },
      "properties": {
        "name": "Объект A",
        "category": "example"
      }
    }
  ]
}

Координаты в GeoJSON всегда задаются в порядке [долгота, широта], что критично при переносе данных в Leaflet, где стандартное представление — [широта, долгота].


Базовая загрузка GeoJSON в Leaflet

Leaflet предоставляет встроенный слой L.geoJSON, который преобразует GeoJSON-структуры в визуальные объекты карты.

const map = L.map('map').setView([43.25, 76.95], 10);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: 'OpenStreetMap'
}).addTo(map);

const geojsonData = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [76.95, 43.25]
      },
      "properties": {
        "name": "Точка 1"
      }
    }
  ]
};

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

При таком подключении каждый объект автоматически интерпретируется и добавляется на карту в виде соответствующего слоя.


Загрузка GeoJSON из внешнего файла

На практике данные чаще хранятся отдельно и подгружаются через HTTP-запросы. Основной подход — использование fetch.

fetch('/data/points.geojson')
  .then(response => response.json())
  .then(data => {
    L.geoJSON(data).addTo(map);
  });

При работе с сервером важно учитывать корректную настройку CORS, иначе браузер может блокировать запрос.

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


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

Leaflet позволяет управлять тем, как именно GeoJSON объекты будут визуализированы через опции pointToLayer, style и onEachFeature.

Стилизация линий и полигонов

Для геометрий типа LineString и Polygon используется функция style:

L.geoJSON(data, {
  style: function (feature) {
    return {
      color: '#2b8cbe',
      weight: 3,
      opacity: 0.8
    };
  }
}).addTo(map);

Стиль может зависеть от свойств объекта:

style: function (feature) {
  return {
    color: feature.properties.category === 'highway' ? 'red' : 'blue',
    weight: 2
  };
}

Преобразование точек в маркеры

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

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

Этот подход позволяет заменить маркеры на кастомные визуальные элементы, включая circleMarker, marker с иконками или даже комбинированные слои.


Обработка событий и привязка данных

Каждый GeoJSON объект может быть связан с интерактивным поведением через onEachFeature.

L.geoJSON(data, {
  onEachFeature: function (feature, layer) {
    if (feature.properties && feature.properties.name) {
      layer.bindPopup(feature.properties.name);
    }

    layer.on('click', function () {
      console.log(feature.properties);
    });
  }
}).addTo(map);

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


Фильтрация объектов GeoJSON

Leaflet поддерживает фильтрацию элементов до их добавления на карту через опцию filter.

L.geoJSON(data, {
  filter: function (feature) {
    return feature.properties.population > 10000;
  }
}).addTo(map);

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


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

GeoJSON слой можно обновлять без пересоздания карты. Обычно используется комбинация удаления и добавления слоя или метод clearLayers.

const layer = L.geoJSON(data).addTo(map);

// обновление данных
layer.clearLayers();
layer.addData(newData);

Метод addData позволяет добавлять новые объекты поверх существующих, что полезно для потоковых данных или периодического обновления.


Работа с большими GeoJSON наборами

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

Кластеризация точек

Для точечных данных используется библиотека Leaflet.markercluster.

const markers = L.markerClusterGroup();

L.geoJSON(data, {
  pointToLayer: function (feature, latlng) {
    return L.marker(latlng);
  }
}).eachLayer(function (layer) {
  markers.addLayer(layer);
});

map.addLayer(markers);

Кластеризация уменьшает количество DOM-элементов и ускоряет отрисовку.


Упрощение геометрии

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


Использование функций трансформации данных

Leaflet позволяет модифицировать GeoJSON на этапе загрузки.

coordsToLatLng

L.geoJSON(data, {
  coordsToLatLng: function (coords) {
    return new L.LatLng(coords[1], coords[0]);
  }
}).addTo(map);

Эта функция полезна при нестандартных форматах координат или интеграции с внешними системами.


geometryToLayer

Позволяет полностью контролировать создание слоёв:

L.geoJSON(data, {
  geometryToLayer: function (feature, latlng) {
    if (feature.geometry.type === 'Point') {
      return L.circle(latlng, { radius: 500 });
    }
  }
}).addTo(map);

Подключение GeoJSON через AJAX-библиотеки

Помимо fetch, часто используется XMLHttpRequest или библиотеки вроде Axios.

axios.get('/data/map.geojson')
  .then(response => {
    L.geoJSON(response.data).addTo(map);
  });

Такие подходы полезны в проектах с единым HTTP-слоем или централизованной обработкой запросов.


Объединение нескольких GeoJSON источников

Leaflet позволяет комбинировать данные из разных источников в один слой.

const layer = L.geoJSON().addTo(map);

fetch('/data/a.geojson')
  .then(r => r.json())
  .then(data => layer.addData(data));

fetch('/data/b.geojson')
  .then(r => r.json())
  .then(data => layer.addData(data));

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


Работа с атрибутами properties

Секция properties используется для хранения бизнес-данных объектов. Leaflet не накладывает ограничений на структуру этих данных, что позволяет использовать их для визуализации и логики.

L.geoJSON(data, {
  onEachFeature: function (feature, layer) {
    const props = feature.properties;

    const html = `
      <div>
        <strong>${props.name}</strong><br>
        Категория: ${props.category}
      </div>
    `;

    layer.bindPopup(html);
  }
}).addTo(map);

Преобразование координат и системы координат

GeoJSON использует систему WGS84 (EPSG:4326). Leaflet также работает в этой системе по умолчанию. Однако при получении данных из других систем координат требуется предварительная трансформация.

Это обычно выполняется на сервере с использованием GDAL или Proj4. В клиентской части возможна интеграция proj4leaflet, позволяющая отображать нестандартные проекции.


Контроль ошибок загрузки

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

fetch('/data/map.geojson')
  .then(response => {
    if (!response.ok) {
      throw new Error('Ошибка загрузки данных');
    }
    return response.json();
  })
  .then(data => {
    L.geoJSON(data).addTo(map);
  })
  .catch(error => {
    console.error(error);
  });

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


Комбинирование GeoJSON с другими слоями Leaflet

GeoJSON часто используется совместно с тайловыми слоями, WMS и кастомными оверлеями.

L.tileLayer(urlTemplate).addTo(map);

const geoLayer = L.geoJSON(data, {
  style: { color: 'green' }
}).addTo(map);

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