Операции с массивами

Работа с массивами является одной из центральных тем при разработке интерактивных карт с использованием MapLibre GL JS, поскольку практически все входные и промежуточные данные в библиотеке представлены в виде структур, основанных на массивах: списки координат, коллекции GeoJSON-объектов, наборы слоёв, фильтры, результаты кластеризации и динамически обновляемые источники данных.

Массивы как основа GeoJSON-модели

Основной формат данных, с которым работает MapLibre GL JS, — GeoJSON. Его структура опирается на массивы:

  • массивы координат (LineString, Polygon)
  • массивы объектов features
  • вложенные массивы для сложных геометрий

Типичная структура FeatureCollection:

const geojson = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: {
        type: "Point",
        coordinates: [37.6173, 55.7558]
      },
      properties: {
        name: "Москва"
      }
    },
    {
      type: "Feature",
      geometry: {
        type: "Point",
        coordinates: [30.3141, 59.9386]
      },
      properties: {
        name: "Санкт-Петербург"
      }
    }
  ]
};

Любая операция отображения, фильтрации или трансформации данных в MapLibre GL JS фактически сводится к операциям над массивом features.


Базовые операции над массивом features

Фильтрация данных (filter)

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

const cities = geojson.features.filter(feature => {
  return feature.properties.population > 1000000;
});

После фильтрации массив может быть повторно загружен в источник:

map.getSource("cities").setData({
  type: "FeatureCollection",
  features: cities
});

Фильтрация часто используется для:

  • отображения объектов по диапазону значений
  • переключения категорий
  • реализации UI-фильтров без перезагрузки данных

Преобразование данных (map)

Метод map используется для трансформации структуры массива без изменения исходного набора данных.

const transformed = geojson.features.map(feature => {
  return {
    ...feature,
    properties: {
      ...feature.properties,
      label: feature.properties.name.toUpperCase()
    }
  };
});

В MapLibre GL JS подобные преобразования часто применяются для:

  • нормализации данных
  • добавления вычисляемых свойств
  • подготовки данных под стилизацию

Агрегация данных (reduce)

Метод reduce используется для вычисления статистики по набору геоданных.

const totalPopulation = geojson.features.reduce((sum, feature) => {
  return sum + (feature.properties.population || 0);
}, 0);

В картографических приложениях агрегирование применяется для:

  • расчёта суммарных значений в области
  • построения тепловых карт
  • анализа распределения объектов

Сортировка массивов и приоритет отображения

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

const sorted = geojson.features.sort((a, b) => {
  return b.properties.importance - a.properties.importance;
});

В контексте MapLibre GL JS это влияет на:

  • порядок добавления слоёв
  • приоритет кликабельности объектов
  • визуальное перекрытие символов

Важно учитывать, что сортировка изменяет исходный массив, поэтому часто используется копирование:

const sortedCopy = [...geojson.features].sort(...);

Работа с массивами координат

Геометрические типы в GeoJSON содержат массивы различной вложенности.

Point

coordinates: [longitude, latitude]

LineString

coordinates: [
  [37.6, 55.7],
  [37.7, 55.8]
]

Polygon

coordinates: [
  [
    [37.6, 55.7],
    [37.7, 55.7],
    [37.7, 55.8],
    [37.6, 55.7]
  ]
]

Операции над такими массивами включают:

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

Иммутабельность и безопасная работа с данными

При работе с MapLibre GL JS важно избегать мутаций исходных массивов, так как источник данных может быть привязан к состоянию карты.

Неправильный подход:

geojson.features.push(newFeature);
map.getSource("data").setData(geojson);

Корректный подход:

const upd ated = {
  ...geojson,
  features: [...geojson.features, newFeature]
};

map.getSource("data").setData(upd ated);

Иммутабельность обеспечивает:

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

Сравнение массивов при обновлении источников

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

Пример дифференциального обновления:

function diffFeatures(oldArr, newArr) {
  const oldIds = new Se t(oldArr.map(f => f.id));
  return newArr.filter(f => !oldIds.has(f.id));
}

Такая логика используется для:

  • инкрементальных обновлений
  • синхронизации с сервером
  • работы в реальном времени

Кластеризация и группировка массивов

Кластеризация в MapLibre GL JS основана на группировке элементов массива.

Типичный подход — разбиение точек по пространственным признакам:

const clusters = points.reduce((acc, point) => {
  const key = `${Math.floor(point.coordinates[0])}:${Math.floor(point.coordinates[1])}`;
  if (!acc[key]) acc[key] = [];
  acc[key].push(point);
  return acc;
}, {});

Использование массивов в кластеризации позволяет:

  • снижать нагрузку на рендеринг
  • группировать близкие объекты
  • улучшать читаемость карты

Вложенные массивы и их обработка

При работе с полигонами и мультигеометрией часто требуется рекурсивная обработка массивов.

function flattenCoordinates(coords) {
  return coords.reduce((acc, item) => {
    if (Array.isArray(item[0])) {
      return acc.concat(flattenCoordinates(item));
    }
    return acc.concat([item]);
  }, []);
}

Такие операции применяются для:

  • вычисления bounding box
  • анализа геометрии
  • преобразования сложных структур

Поиск элементов в массивах

Поиск объектов по атрибутам — частая операция в интерактивных картах.

const feature = geojson.features.find(f => f.properties.id === targetId);

Также используется проверка наличия:

const exists = geojson.features.some(f => f.properties.active);

Эти операции применяются при:

  • обработке событий клика
  • синхронизации UI и карты
  • динамическом обновлении стилей

Группировка данных через массивы

Группировка используется для построения тематических слоёв.

const grouped = geojson.features.reduce((acc, f) => {
  const type = f.properties.type;
  if (!acc[type]) acc[type] = [];
  acc[type].push(f);
  return acc;
}, {});

После группировки данные могут быть распределены по слоям MapLibre GL JS:

  • отдельный слой на каждую категорию
  • разные стили для групп
  • управление видимостью через массивы идентификаторов

Оптимизация операций над массивами

При работе с большими наборами данных в MapLibre GL JS критично учитывать производительность:

  • избегание повторных map и filter на больших массивах
  • кэширование результатов трансформаций
  • использование for вместо цепочек методов в горячих циклах
  • предварительная индексация данных через Map или Se t

Пример индексации:

const index = new Map();
geojson.features.forEach(f => {
  index.set(f.properties.id, f);
});

Синхронизация массивов с источниками MapLibre

При обновлении данных на карте массивы должны быть синхронизированы с источниками через setData.

map.getSource("points").setData({
  type: "FeatureCollection",
  features: updatedFeatures
});

Типичные сценарии синхронизации:

  • потоковые обновления (real-time data)
  • фильтрация на клиенте
  • интерактивные изменения через UI

Композиция операций над массивами

На практике операции над массивами комбинируются в цепочки:

const result = geojson.features
  .filter(f => f.properties.active)
  .map(f => ({
    ...f,
    properties: {
      ...f.properties,
      score: f.properties.value * 2
    }
  }))
  .sort((a, b) => b.properties.score - a.properties.score);

Такая композиция позволяет формировать сложные вычислительные пайплайны, которые напрямую влияют на визуализацию данных в MapLibre GL JS.