Экспорт нарисованных объектов

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


Источник данных для экспорта: GeoJSON как базовая модель

Любые рисуемые объекты в веб-картах, построенных на MapLibre GL JS, в конечном счёте сводятся к структуре:

  • Feature
  • FeatureCollection
  • геометрии: Point, LineString, Polygon
  • свойства properties

Стандартом обмена выступает GeoJSON (RFC 7946), где координаты всегда задаются в системе WGS84 (долгота, широта).


Экспорт объектов, созданных через MapLibre GL Draw

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

Получение всех объектов

const data = draw.getAll();
console.log(data);

Метод возвращает объект формата:

{
  "type": "FeatureCollection",
  "features": [...]
}

Каждый элемент содержит:

  • геометрию
  • уникальный id
  • пользовательские properties

Фильтрация объектов перед экспортом

Часто требуется экспортировать только часть объектов, например только полигоны или только выбранные элементы.

const all = draw.getAll();

const polygons = {
  type: "FeatureCollection",
  features: all.features.filter(f => f.geometry.type === "Polygon")
};

Или экспорт только выбранных объектов:

const selected = draw.getSelected();

Формирование файла GeoJSON для загрузки

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

Создание Blob и скачивание

function exportGeoJSON(data) {
  const json = JSON.stringify(data, null, 2);
  const blob = new Blob([json], { type: "application/geo+json" });

  const url = URL.createObjectURL(blob);

  const a = document.createElement("a");
  a.href = url;
  a.download = "map-data.geojson";
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);

  URL.revokeObjectURL(url);
}

Вызов:

exportGeoJSON(draw.getAll());

Экспорт объектов из пользовательских источников (Source)

Если объекты добавлены не через Draw, а через GeoJSONSource, используется прямое извлечение данных из источника.

Получение данных из источника

const source = map.getSource("user-data");
const data = source._data;

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

  • _data — внутреннее поле
  • для динамических источников лучше хранить копию данных отдельно
  • MapLibre GL JS не предоставляет полноценного публичного метода “get all features” для всех случаев

Экспорт объектов с карты через queryRenderedFeatures

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

Получение объектов в области

const features = map.queryRenderedFeatures({
  layers: ["draw-layer"]
});

Далее требуется преобразовать результат в GeoJSON:

const geojson = {
  type: "FeatureCollection",
  features: features.map(f => ({
    type: "Feature",
    geometry: f.geometry,
    properties: f.properties
  }))
};

Экспорт только выделенной области карты

Часто требуется экспортировать объекты в пределах текущего viewport.

const bounds = map.getBounds();

const features = map.queryRenderedFeatures({
  bbox: [
    bounds.getWest(),
    bounds.getSouth(),
    bounds.getEast(),
    bounds.getNorth()
  ]
});

Очистка и нормализация экспортируемых данных

Перед сохранением данные часто приводят к единому виду:

Удаление служебных полей

function cleanFeature(feature) {
  const { id, layer, source, state, ...rest } = feature;
  return rest;
}

Нормализация FeatureCollection

const cleaned = {
  type: "FeatureCollection",
  features: geojson.features.map(cleanFeature)
};

Экспорт в пользовательские форматы на основе GeoJSON

Хотя MapLibre GL JS работает с GeoJSON, часто требуется преобразование:

JSON (расширенный формат)

const exportData = {
  exportedAt: new Date().toISOString(),
  data: draw.getAll()
};

CSV (для точечных объектов)

function toCSV(features) {
  return features.map(f => {
    const [lng, lat] = f.geometry.coordinates;
    return `${lng},${lat}`;
  }).join("\n");
}

Сохранение стиля вместе с геометрией

GeoJSON не хранит визуальные стили MapLibre GL JS (цвет, толщина линий, заливка). Для сохранения визуального состояния необходимо дополнительно сохранять метаданные.

Пример расширения properties

const styledFeature = {
  ...feature,
  properties: {
    ...feature.properties,
    stroke: "#ff0000",
    "stroke-width": 2,
    fill: "#00ff00"
  }
};

Экспорт через серверное хранилище

В сложных приложениях экспорт часто делегируется серверу.

Отправка GeoJSON на сервер

fetch("/api/export", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify(draw.getAll())
});

Сервер может:

  • сохранять файл
  • конвертировать в Shapefile
  • индексировать в пространственной базе (PostGIS)

Работа с координатами при экспорте

MapLibre GL JS использует стандарт:

  • долгота (longitude)
  • широта (latitude)

При экспорте важно учитывать:

  • порядок координат [lng, lat]
  • отсутствие проекции Web Mercator в GeoJSON
  • сохранение точности (обычно 6–7 знаков достаточно)

Экспорт большого количества объектов

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

Батч-экспорт

const all = draw.getAll();

const chunkSize = 500;
for (let i = 0; i < all.features.length; i += chunkSize) {
  const chunk = {
    type: "FeatureCollection",
    features: all.features.slice(i, i + chunkSize)
  };

  exportGeoJSON(chunk);
}

Экспорт в момент взаимодействия с картой

Иногда требуется фиксировать состояние карты и объектов одновременно.

const snapshot = {
  center: map.getCenter(),
  zoom: map.getZoom(),
  bearing: map.getBearing(),
  pitch: map.getPitch(),
  features: draw.getAll()
};

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


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

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

Практическая структура экспортного модуля

В реальных приложениях логика экспорта обычно централизуется:

class ExportManager {
  constructor(draw) {
    this.draw = draw;
  }

  exportAll() {
    const data = this.draw.getAll();
    this.download(data);
  }

  exportSelected() {
    const data = this.draw.getSelected();
    this.download(data);
  }

  download(data) {
    const blob = new Blob([JSON.stringify(data)], {
      type: "application/geo+json"
    });

    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");

    a.href = url;
    a.download = "export.geojson";
    a.click();

    URL.revokeObjectURL(url);
  }
}