Стилизация инструментов рисования в Mapbox GL JS и плагине Mapbox GL Draw основана на переопределении набора слоёв (layers), которые отвечают за отображение геометрии в разных состояниях редактирования. В отличие от стандартных слоёв карты, Draw использует внутреннюю систему стилей, описываемую массивом объектов слоя, где каждый объект соответствует определённому состоянию feature.
Ключевая идея: каждый элемент геометрии имеет состояние, а каждое состояние визуализируется отдельным слоем.
Система стилизации Mapbox Draw опирается на три уровня:
Draw-слои добавляются поверх карты и управляют отображением:
Каждый тип геометрии разбивается на несколько визуальных слоёв.
Стиль описывается массивом объектов:
const draw = new MapboxDraw({
styles: [
{
id: 'gl-draw-polygon-fill',
type: 'fill',
filter: ['all',
['==', '$type', 'Polygon'],
['!=', 'mode', 'static']
],
paint: {
'fill-color': '#3bb2d0',
'fill-opacity': 0.4
}
}
]
});
Каждый объект содержит:
id — уникальное имя слояtype — тип рендера (fill,
line, circle)filter — логика выбора featurepaint — визуальные параметрыlayout — поведение слояDraw использует внутренние состояния объектов:
active — объект редактируетсяinactive — обычное состояниеselected — выделенный объектstatic — неизменяемый объектЭти состояния позволяют строить интерфейс редактирования без DOM-слоёв, используя только WebGL рендеринг.
Полигон разбивается на два ключевых слоя:
{
id: 'gl-draw-polygon-fill',
type: 'fill',
filter: ['all',
['==', '$type', 'Polygon'],
['!=', 'mode', 'static']
],
paint: {
'fill-color': [
'case',
['boolean', ['feature-state', 'selected'], false],
'#fbb03b',
'#3bb2d0'
],
'fill-opacity': 0.5
}
}
{
id: 'gl-draw-polygon-stroke',
type: 'line',
filter: ['all',
['==', '$type', 'Polygon']
],
paint: {
'line-color': '#000',
'line-width': 2
}
}
Особенность: контур и заливка независимы и могут иметь разные состояния.
Линии требуют отдельного контроля ширины и цвета:
{
id: 'gl-draw-line',
type: 'line',
filter: ['all',
['==', '$type', 'LineString']
],
paint: {
'line-color': '#ff0000',
'line-width': 3
}
}
Толщина может зависеть от состояния:
'line-width': [
'case',
['boolean', ['feature-state', 'active'], false],
5,
2
]
Точки используются для:
{
id: 'gl-draw-point',
type: 'circle',
filter: ['all',
['==', '$type', 'Point']
],
paint: {
'circle-radius': 6,
'circle-color': '#ffcc00'
}
}
Draw использует свойства:
meta: 'vertex'meta: 'midpoint'meta: 'feature'Пример фильтра:
filter: ['all',
['==', 'meta', 'vertex']
]
Вершины — ключевой элемент UX редактирования.
{
id: 'gl-draw-polygon-and-line-vertex',
type: 'circle',
filter: ['all',
['==', 'meta', 'vertex']
],
paint: {
'circle-radius': 4,
'circle-color': '#ffffff',
'circle-stroke-color': '#333',
'circle-stroke-width': 2
}
}
Особенность: вершины часто визуально отличаются от основной геометрии.
Midpoints позволяют добавлять новые узлы:
{
id: 'gl-draw-polygon-midpoint',
type: 'circle',
filter: ['all',
['==', 'meta', 'midpoint']
],
paint: {
'circle-radius': 3,
'circle-color': '#888'
}
}
Они активируются только в режиме редактирования.
Mapbox GL JS предоставляет механизм feature-state,
который используется Draw для изменения внешнего вида объектов без
пересоздания GeoJSON.
Пример:
map.setFeatureState(
{ source: 'mapbox-gl-draw', id: featureId },
{ active: true }
);
И использование в стиле:
'circle-color': [
'case',
['boolean', ['feature-state', 'active'], false],
'#f00',
'#00f'
]
Mapbox Draw позволяет полностью заменить стандартные стили:
const draw = new MapboxDraw({
styles: customStylesArray
});
Это полностью отключает дефолтную визуальную модель.
Порядок в массиве styles определяет:
Типичная последовательность:
Слои Draw могут конфликтовать с пользовательскими слоями карты. Управление решается:
map.addLayerbeforeIdmap.addLayer(customLayer, 'gl-draw-polygon-fill');
Стили Draw активно используют expression API:
'fill-color': [
'interpolate',
['linear'],
['zoom'],
10, '#2DC4B2',
15, '#3BB3C3'
]
'circle-opacity': [
'case',
['==', ['feature-state', 'selected'], true],
1,
0.5
]
Режимы редактирования влияют на стили:
draw_polygondraw_line_stringdraw_pointsimple_selectdirect_selectФильтры часто используют mode:
filter: ['==', 'mode', 'simple_select']
Для сложных сцен важно:
Сложные редакторы часто строят 6–10 слоёв:
Такая структура обеспечивает гибкость UX без изменения данных GeoJSON.