Состояние объектов (feature-state) в Mapbox GL JS представляет собой механизм хранения динамических параметров, привязанных к конкретным геометрическим объектам слоя без изменения исходных данных источника. Такой подход позволяет разделять статические геоданные и временные состояния интерфейса: наведение, выделение, активность, загрузка и любые пользовательские флаги.
Каждый геометрический объект в источнике может иметь уникальный идентификатор. Именно этот идентификатор используется как ключ для привязки состояния.
Feature-state хранится отдельно от:
Состояние задаётся и читается через API карты, а затем используется
внутри стилей через выражения feature-state.
Ключевая идея:
состояние не является частью данных — оно существует только на уровне отображения
Feature-state работает только при наличии стабильного идентификатора объекта.
Для GeoJSON:
{
"type": "Feature",
"id": 42,
"properties": {
"name": "Object A"
},
"geometry": {
"type": "Point",
"coordinates": [30, 60]
}
}
Для vector tiles необходимо:
feature.id в тайлахpromoteId при добавлении
источникаПример:
map.addSource('places', {
type: 'geojson',
data: geojsonData,
promoteId: 'id'
});
Без идентификатора feature-state невозможен, поскольку система не имеет ключа для привязки состояния.
Основной метод:
map.setFeatureState(
{ source: 'places', id: 42 },
{ hover: true }
);
Второй аргумент — объект состояния, содержащий произвольные ключи:
{
hover: true,
selected: false,
loading: true
}
Состояние не ограничено фиксированной схемой и может расширяться по мере необходимости.
const state = map.getFeatureState({
source: 'places',
id: 42
});
Возвращается объект текущего состояния:
{
hover: true,
selected: false
}
Если состояние не установлено, возвращается пустой объект.
Удаление конкретного ключа:
map.removeFeatureState({
source: 'places',
id: 42
}, 'hover');
Удаление всего состояния объекта:
map.removeFeatureState({
source: 'places',
id: 42
});
Очистка состояния всего источника:
map.removeFeatureState({
source: 'places'
});
Главная ценность feature-state проявляется в стилях слоя через выражение:
["feature-state", "key"]
Пример изменения цвета при наведении:
map.addLayer({
id: 'points',
type: 'circle',
source: 'places',
paint: {
'circle-radius': 6,
'circle-color': [
'case',
['boolean', ['feature-state', 'hover'], false],
'#ff0000',
'#3388ff'
]
}
});
Логика:
hover === true → красный цветСценарий основан на динамическом обновлении состояния при событиях
mousemove и mouseleave.
let hoveredId = null;
map.on('mousemove', 'points', (e) => {
if (e.features.length === 0) return;
const id = e.features[0].id;
if (hoveredId !== null) {
map.setFeatureState(
{ source: 'places', id: hoveredId },
{ hover: false }
);
}
hoveredId = id;
map.setFeatureState(
{ source: 'places', id },
{ hover: true }
);
});
При уходе курсора:
map.on('mouseleave', 'points', () => {
if (hoveredId !== null) {
map.setFeatureState(
{ source: 'places', id: hoveredId },
{ hover: false }
);
}
hoveredId = null;
});
Feature-state часто используется вместо модификации GeoJSON для хранения выбранного элемента.
map.setFeatureState(
{ source: 'places', id: selectedId },
{ selected: true }
);
В стиле:
'circle-stroke-width': [
'case',
['boolean', ['feature-state', 'selected'], false],
3,
1
]
Feature-state может управлять визуальными параметрами, изменяющимися во времени:
map.setFeatureState(
{ source: 'places', id: 10 },
{ progress: 0.6 }
);
Использование в стиле:
'circle-radius': [
'*',
10,
['feature-state', 'progress']
]
Частый шаблон — индикация асинхронных операций:
map.setFeatureState(
{ source: 'places', id: 77 },
{ loading: true }
);
'circle-opacity': [
'case',
['boolean', ['feature-state', 'loading'], false],
0.5,
1
]
Feature-state не является частью данных источника и не сохраняется при:
setDataПосле обновления данных состояние может быть потеряно, если идентификаторы изменились или источник пересоздан.
Использование feature-state снижает необходимость:
setDataСистема работает на уровне WebGL-стиля, что позволяет:
Feature-state имеет ряд технических ограничений:
idПри увеличении сложности интерфейса состояние структурируется через именование ключей:
{
hover: true,
selected: false,
popupOpen: true,
loading: false
}
Для сложных сценариев применяется префиксирование логических доменов:
{
ui_hover: true,
ui_selected: false,
data_loading: true
}
Это снижает конфликтность состояний при масштабировании приложения.
При удалении объектов или смене наборов данных важно очищать state:
map.removeFeatureState({ source: 'places' });
Либо точечно:
map.removeFeatureState({ source: 'places', id: 42 });
Игнорирование очистки приводит к накоплению неиспользуемых записей состояния в памяти.
Feature-state не заменяет фильтрацию данных. Его задача — визуальное
представление состояния, тогда как filter управляет
составом отображаемых объектов.
Комбинация:
В крупных приложениях feature-state используется как слой представления над:
Схема взаимодействия:
Этот подход позволяет избегать прямого изменения геоданных и сохранять чистую модель источника.