Библиотека MapLibre GL JS предоставляет низкоуровневый рендеринг векторных карт на WebGL, однако для работы с интерактивным рисованием геометрий используется дополнительный инструмент — MapLibre GL Draw. Это расширение позволяет создавать, редактировать и удалять географические объекты непосредственно на карте, оперируя стандартом GeoJSON и интегрируясь с системой слоёв MapLibre.
MapLibre GL Draw представляет собой контрол, который подключается к экземпляру карты MapLibre GL JS и управляет отдельным слоем данных. В основе лежит модель:
Каждый объект на карте хранится как GeoJSON Feature:
Редактирование не изменяет напрямую слой MapLibre, а обновляет внутреннее состояние, которое затем пересобирает источник данных.
MapLibre GL Draw обычно используется как отдельный пакет:
npm install @maplibre/maplibre-gl-draw
Подключение в проекте:
import maplibregl from "maplibre-gl";
import MapboxDraw from "@maplibre/maplibre-gl-draw";
import "@maplibre/maplibre-gl-draw/dist/mapbox-gl-draw.css";
Несмотря на историческое имя MapboxDraw, пакет совместим с MapLibre GL JS через адаптированный API.
Контрол добавляется через стандартный механизм MapLibre:
const map = new maplibregl.Map({
container: "map",
style: "https://demotiles.maplibre.org/style.json",
center: [30.3, 59.9],
zoom: 10
});
const draw = new MapboxDraw({
displayControlsDefault: false,
controls: {
point: true,
line_string: true,
polygon: true,
trash: true
}
});
map.addControl(draw);
После добавления контрол становится частью UI карты и начинает управлять собственным слоем данных.
Ключевая концепция MapLibre GL Draw — режимы редактирования:
simple_select — выбор объектовdirect_select — точечное редактирование вершинdraw_point — создание точекdraw_line_string — создание линийdraw_polygon — создание полигоновstatic — режим без редактированияСмена режима выполняется программно:
draw.changeMode("draw_polygon");
Каждый режим имеет собственную логику взаимодействия с мышью и состоянием.
draw.add({
type: "Feature",
geometry: {
type: "Point",
coordinates: [30.3, 59.9]
},
properties: {}
});
const data = draw.getAll();
Результат всегда возвращается в формате FeatureCollection.
draw.delete(featureId);
или массово:
draw.deleteAll();
MapLibre GL Draw поддерживает два уровня взаимодействия:
draw.changeMode("simple_select", {
featureIds: ["id1", "id2"]
});
draw.changeMode("direct_select", {
featureId: "id1"
});
В этом режиме доступны:
Контрол генерирует набор событий, позволяющих синхронизировать данные:
map.on("draw.create", (e) => {
console.log(e.features);
});
map.on("draw.update", (e) => {
console.log(e.features);
});
map.on("draw.delete", (e) => {
console.log(e.features);
});
map.on("draw.modechange", (e) => {
console.log(e.mode);
});
Эта событийная модель позволяет интегрировать Draw в любые внешние состояния приложения.
Конфигурация UI элементов управляется через
controls:
const draw = new MapboxDraw({
controls: {
point: true,
line_string: true,
polygon: true,
trash: true,
combine_features: true,
uncombine_features: true
}
});
Дополнительно можно скрыть стандартные кнопки:
displayControlsDefault: false
MapLibre GL Draw поддерживает операции объединения объектов:
Пример сценария:
draw.changeMode("simple_select", {
featureIds: ["a", "b"]
});
draw.combineFeatures();
Валидация выполняется на уровне пользовательской логики:
Пример проверки:
map.on("draw.create", (e) => {
const feature = e.features[0];
if (feature.geometry.type === "Polygon") {
if (feature.geometry.coordinates[0].length < 4) {
draw.delete(feature.id);
}
}
});
MapLibre GL Draw использует внутренние слои MapLibre, которые можно переопределять:
const draw = new MapboxDraw({
styles: [
{
id: "gl-draw-polygon-fill",
type: "fill",
paint: {
"fill-color": "#00ff00",
"fill-opacity": 0.3
}
}
]
});
Кастомизация затрагивает:
Внутри MapLibre GL Draw создаётся отдельный source:
Это означает, что любые внешние изменения должны учитывать актуальное состояние:
const all = draw.getAll();
map.getSource("mapbox-gl-draw-cold").setData(all);
GeoJSON можно сохранять и восстанавливать:
const geojson = draw.getAll();
localStorage.setItem("draw-data", JSON.stringify(geojson));
const saved = JSON.parse(localStorage.getItem("draw-data"));
draw.set(saved);
Это позволяет реализовать:
Draw не изолирован от основной карты. Он может взаимодействовать с пользовательскими слоями:
Пример:
map.on("click", (e) => {
const features = map.queryRenderedFeatures(e.point);
console.log(features);
});
MapLibre GL Draw поддерживает touch-интеракции:
Особое внимание требуется к:
При работе с тысячами объектов критично:
Оптимизация часто включает:
MapLibre GL Draw позволяет создавать собственные режимы:
const customMode = {
onSetup() {
return {};
},
onClick(state, e) {
console.log(e.lngLat);
}
};
draw.addMode("custom_mode", customMode);
Это используется для:
Библиотека поддерживает базовые типы:
import { MapboxDraw } from "@maplibre/maplibre-gl-draw";
Основные типы:
Типизация важна при работе с серверной валидацией GeoJSON.
MapLibre GL Draw строго следует спецификации RFC 7946:
Любое отклонение от стандарта приводит к некорректному отображению или потере данных при сериализации.
В архитектуре SPA часто используется схема:
Пример подхода:
map.on("draw.update", () => {
const data = draw.getAll();
fetch("/api/save", {
method: "POST",
body: JSON.stringify(data)
});
});
В продвинутых сценариях требуется учитывать:
Реализация часто требует внешних библиотек геообработки, таких как turf.js, которые работают совместно с Draw.
import * as turf from "@turf/turf";
const cleaned = turf.cleanCoords(feature);
Draw может сосуществовать с:
Важно учитывать порядок слоёв:
Контрол можно динамически добавлять и удалять:
map.addControl(draw);
map.removeControl(draw);
Это полезно при переключении режимов приложения: