Оптимизация для больших данных

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


Архитектура данных: основа производительности

Ключевое ограничение больших карт — объём GeoJSON и количество отрисовываемых объектов. При росте числа фич резко увеличивается нагрузка на:

  • парсинг JSON;
  • построение внутренних индексов;
  • WebGL-рендеринг;
  • пересчёт стилей при каждом движении камеры.

Разделение данных по источникам

На практике один большой GeoJSONSource почти всегда хуже, чем несколько специализированных:

  • отдельный источник для точек;
  • отдельный для линий;
  • отдельный для полигонов;
  • отдельный для динамических объектов.

Это уменьшает количество перерасчётов при фильтрации и позволяет изолировать тяжёлые слои.


Переход от GeoJSON к векторным тайлам

Главное правило масштабирования — уход от клиентского GeoJSON к серверной подготовке данных.

Преимущества vector tiles:

  • данные загружаются по тайлам, а не целиком;
  • рендеринг ограничен областью экрана;
  • поддерживается кеширование на уровне браузера;
  • снижается объём памяти.

MapLibre GL JS значительно эффективнее работает с vector-источниками, чем с массивными GeoJSON.


Ограничения GeoJSON и способы их смягчения

GeoJSON остаётся удобным, но плохо масштабируется. Основные проблемы:

  • линейный парсинг больших файлов;
  • отсутствие встроенной тайлизации;
  • высокая нагрузка на GC (garbage collector).

Практические оптимизации

1. Снижение точности координат

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

2. Упрощение геометрии

Перед загрузкой:

  • Douglas-Peucker simplification;
  • уменьшение числа вершин полигонов;
  • удаление избыточных узлов в линиях.

3. Разбиение данных

Большой GeoJSON разбивается по:

  • регионам;
  • типам объектов;
  • уровням детализации.

Кластеризация точек

При десятках тысяч точек обязательна кластеризация.

Встроенная кластеризация GeoJSON

MapLibre GL JS поддерживает параметр:

  • cluster: true

Плюсы:

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

Минусы:

  • ограниченная гибкость;
  • высокая нагрузка при сложных стилях кластеров.

Когда лучше использовать серверную кластеризацию

При:

  • 100k точек;

  • частых обновлениях данных;
  • сложной логике группировки.

Оптимизация слоёв (layers)

Количество и структура слоёв напрямую влияет на FPS.

Разделение paint и layout

  • layout пересчитывается реже, но дороже;
  • paint чаще обновляется, но легче.

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

  • минимизировать динамические изменения layout;
  • выносить визуальные эффекты в paint.

Использование zoom-ограничений

Каждый слой должен существовать только там, где он нужен.

  • minzoom — отключает слой на малых масштабах;
  • maxzoom — отключает на больших.

Это снижает:

  • количество draw calls;
  • количество проверок стилей;
  • нагрузку на GPU.

Оптимизация символов и текста

Текстовые слои — одни из самых дорогих.

Основные проблемы:

  • сложный layout текста;
  • collision detection (пересечения);
  • динамическое позиционирование.

Методы оптимизации:

1. Ограничение количества подписей

Не показывать текст на всех уровнях zoom.

2. Упрощение шрифтов

Использовать:

  • один стиль шрифта;
  • ограниченное число глифов.

3. Прекэширование glyphs

Использование glyphs серверов снижает задержки загрузки.


Иконки и спрайты

Отдельная зона оптимизации — sprite atlas.

Почему важно:

Каждая иконка = отдельный WebGL draw call, если не объединена.

Рекомендации:

  • использовать единый sprite sheet;
  • избегать загрузки множества маленьких PNG;
  • контролировать размер текстур (GPU memory limit).

Снижение нагрузки на рендер

Фильтрация на уровне стилей

Использование filter вместо предобработки данных может быть дорого при больших массивах.

Лучше:

  • предварительно разделять данные;
  • минимизировать сложные выражения.

Оптимизация источников данных (sources)

promoteId

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

  • ускорить lookup объектов;
  • уменьшить необходимость перебора свойств.

maxzoom / minzoom для source

Ограничивает количество тайлов и снижает сетевую нагрузку.


Работа с событиями карты

При больших данных особенно критичны события:

  • move
  • zoom
  • render

Типичные ошибки:

  • тяжёлая логика внутри move;
  • частые queryRenderedFeatures;
  • отсутствие throttling.

Оптимизация:

  • debounce обработчиков;
  • вынос вычислений в requestAnimationFrame;
  • кэширование результатов запросов.

queryRenderedFeatures и стоимость вычислений

Этот метод обращается к текущему кадру рендера.

При больших слоях:

  • становится дорогим;
  • блокирует UI при частом вызове.

Оптимизация:

  • ограничение частоты вызова;
  • использование bbox-фильтров;
  • сокращение слоёв, участвующих в запросе.

Управление видимой областью

setMaxBounds

Ограничение карты уменьшает:

  • число загружаемых тайлов;
  • объём отрисовки вне нужной зоны.

Raster vs Vector при больших данных

Raster tiles

Плюсы:

  • быстрый рендер;
  • минимальная нагрузка на CPU.

Минусы:

  • отсутствие интерактивности;
  • фиксированный стиль.

Vector tiles

Плюсы:

  • динамическая стилизация;
  • интерактивность;
  • масштабируемость.

Минусы:

  • более сложная подготовка данных.

Управление памятью WebGL

При долгой работе карты возникают:

  • утечки текстур;
  • накопление буферов;
  • перегрузка GPU.

Решения:

  • удаление неиспользуемых источников (removeSource);
  • контроль числа слоёв;
  • переиспользование стилей вместо пересоздания.

Батчинг и минимизация перерисовок

Любые вызовы:

  • setData
  • setLayoutProperty
  • setPaintProperty

должны быть сгруппированы.

Принцип:

  • один кадр = одно обновление состояния;
  • избегать каскадных изменений.

Разделение уровней детализации (LOD)

Для больших данных критично внедрение LOD:

  • низкий zoom → агрегированные данные;
  • средний zoom → упрощённые геометрии;
  • высокий zoom → полная детализация.

Это уменьшает:

  • число вершин;
  • количество объектов на экране;
  • нагрузку на рендер.

Асинхронная подготовка данных

Тяжёлые операции должны выполняться вне основного потока:

  • упрощение геометрии;
  • кластеризация;
  • фильтрация больших массивов.

Подготовленные данные затем передаются в MapLibre GL JS уже в оптимизированном виде, без блокировки UI.