Свойства features

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

Feature является фундаментальной сущностью, на которой строится вся логика взаимодействия с данными: от визуализации до обработки событий и динамического стайлинга.


Структура feature в GeoJSON

В большинстве случаев MapLibre GL JS работает с feature в формате GeoJSON. Базовая структура выглядит следующим образом:

{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [30.5, 50.5]
  },
  "properties": {
    "name": "Объект",
    "category": "poi",
    "population": 1200
  }
}

Геометрия feature

Поле geometry определяет пространственное представление объекта:

  • Point — точечные объекты (POI, маркеры)
  • LineString — линии (дороги, маршруты)
  • Polygon — полигоны (здания, зоны)
  • MultiPoint / MultiLineString / MultiPolygon — коллекции геометрий

Геометрия определяет, как feature будет отображён на карте и как будет участвовать в пространственных операциях.


Properties как основа атрибутивных данных

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

Типичные свойства feature

  • идентификаторы (id, fid)
  • классификация (type, class, category)
  • числовые параметры (height, population, value)
  • текстовые атрибуты (name, description)
  • технические параметры (уровень детализации, источник данных)

Пример расширенного набора:

"properties": {
  "id": 10234,
  "name": "Central Park",
  "type": "park",
  "area": 341,
  "protected": true
}

Использование feature в источниках данных

MapLibre GL JS поддерживает два основных типа источников, где feature играет ключевую роль:

GeoJSON source

map.addSource('places', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: [...]
  }
});

Каждый элемент массива features — это отдельный feature.

Vector tiles source

Векторные тайлы содержат уже предобработанные features, разделённые по слоям. В этом случае features загружаются динамически в зависимости от viewport.

map.addSource('roads', {
  type: 'vector',
  url: 'mapbox://tileset-id'
});

Доступ к properties в стилях

Одной из ключевых возможностей MapLibre GL JS является data-driven styling — стилизация на основе свойств feature.

Оператор get

paint: {
  'circle-radius': ['get', 'population'],
  'circle-color': ['get', 'color']
}

Условные выражения

paint: {
  'fill-color': [
    'case',
    ['==', ['get', 'type'], 'park'],
    '#00ff00',
    '#ff0000'
  ]
}

Properties становятся частью выражений MapLibre Expression Language, что позволяет создавать сложную логику визуализации без дополнительного кода.


Feature в событиях карты

При взаимодействии с картой (click, hover) MapLibre возвращает массив features, попадающих под курсор.

map.on('click', 'places-layer', (e) => {
  const features = e.features;
  console.log(features[0].properties);
});

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

  • геометрию
  • properties
  • идентификатор слоя
  • ссылку на source

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


QueryRenderedFeatures и работа с feature

Метод queryRenderedFeatures позволяет получать features, визуально присутствующие на экране.

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

Фильтрация по properties:

const parks = map.queryRenderedFeatures().filter(
  f => f.properties.type === 'park'
);

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


Feature-state и динамические изменения

Feature-state позволяет изменять визуальное состояние feature без изменения исходных данных.

map.setFeatureState(
  {
    source: 'places',
    id: 123
  },
  {
    selected: true
  }
);

Использование в стилях:

paint: {
  'circle-color': [
    'case',
    ['boolean', ['feature-state', 'selected'], false],
    '#ff0000',
    '#0000ff'
  ]
}

Особенности feature-state

  • не изменяет исходный GeoJSON
  • работает только для источников с id
  • оптимизирован для интерактивности
  • обновляется без перезагрузки слоя

Feature ID и индексирование

Каждый feature может иметь уникальный идентификатор:

{
  "type": "Feature",
  "id": 42,
  "properties": {}
}

ID используется для:

  • feature-state
  • кэширования
  • быстрого доступа
  • синхронизации состояния UI

При отсутствии id MapLibre может генерировать внутренние идентификаторы, но это ограничивает возможности управления состоянием.


Фильтрация features в слоях

Слои могут фильтровать features по их properties:

filter: ['==', ['get', 'type'], 'water']

Комбинированные фильтры:

filter: [
  'all',
  ['==', ['get', 'type'], 'road'],
  ['>=', ['get', 'width'], 5]
]

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


Кластеризация feature

Для точечных данных GeoJSON поддерживает кластеризацию:

map.addSource('points', {
  type: 'geojson',
  data: geojson,
  cluster: true,
  clusterRadius: 50
});

В этом режиме:

  • отдельные features объединяются в кластеры
  • создаются агрегированные features
  • properties включают point_count
{
  "properties": {
    "point_count": 12,
    "cluster": true
  }
}

Преобразование feature в рендеринговую модель

Перед отрисовкой MapLibre выполняет несколько этапов:

  1. загрузка features из source
  2. разбиение по tile-структуре
  3. применение фильтров
  4. вычисление layout properties
  5. применение paint expressions
  6. генерация GPU-геометрии

Properties на каждом этапе могут использоваться для принятия решений о визуализации.


Производительность при работе с properties

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

  • количество уникальных keys в properties
  • сложность expression-логики
  • использование feature-state вместо модификации данных
  • минимизацию queryRenderedFeatures в циклах

Оптимизация часто достигается переносом логики в стили MapLibre, а не в JavaScript.


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

Отсутствие стабильного id

Без стабильного id невозможно корректно использовать feature-state, что приводит к неконтролируемым обновлениям UI.

Перегрузка properties

Избыточные данные в properties увеличивают размер GeoJSON и замедляют загрузку.

Использование JavaScript вместо expressions

Перенос логики из стилей в JS снижает производительность, так как рендер перестаёт быть декларативным.


Feature как центральная модель данных

Feature объединяет геометрию и семантику, выступая связующим звеном между:

  • источниками данных
  • рендерингом на GPU
  • интерактивными событиями
  • динамическими состояниями
  • фильтрацией и стилями

В архитектуре MapLibre GL JS именно features определяют, какие объекты существуют на карте и как они ведут себя в различных состояниях отображения.