В Google Maps JavaScript API каждый маркер
(google.maps.Marker) является отдельным DOM-подобным
объектом, который участвует в рендеринге, обработке событий и пересчёте
позиций при каждом изменении карты. При увеличении количества маркеров
до сотен и тысяч начинают проявляться типичные проблемы:
- рост времени первичного рендера карты;
- увеличение нагрузки на CPU при панорамировании и зуме;
- деградация отклика интерфейса при обработке событий
mouseover, click;
- рост потребления памяти из-за хранения состояния каждого
маркера;
- частые перерасчёты позиций в проекции Web Mercator.
Ключевой фактор деградации — не только отрисовка, но и постоянное
участие каждого маркера в жизненном цикле карты.
Базовый принцип оптимизации
Основная стратегия работы с большим количеством маркеров заключается
в одном принципе:
на карте одновременно должны находиться только те маркеры,
которые действительно видимы и значимы для текущего
масштаба
Отсюда вытекают три направления оптимизации:
- уменьшение числа одновременно отображаемых объектов;
- замена маркеров на агрегированные структуры;
- перенос части логики на сервер или предобработку данных.
Кластеризация маркеров
Наиболее распространённый подход — кластеризация.
Кластеризация объединяет близко расположенные точки в один объект,
отображаемый как единый маркер с числом элементов внутри.
Для Google Maps JavaScript API чаще всего используется библиотека
MarkerClusterer:
Принцип работы кластеризации
Алгоритм работает в несколько этапов:
- Определяется текущий viewport карты.
- Все маркеры преобразуются в пиксельные координаты.
- Близкие точки группируются по радиусу кластеризации.
- Вместо множества маркеров создаётся один кластерный объект.
- При изменении zoom пересчёт выполняется заново.
Практическая структура
кластера
Кластер обычно содержит:
- количество точек внутри;
- геометрический центр (centroid);
- список дочерних маркеров (или их идентификаторы);
- уровень зума, на котором кластер должен распадаться.
Эффект оптимизации
При корректной настройке:
- 10 000 точек могут отображаться как 50–200 кластеров;
- количество DOM-объектов уменьшается на порядок;
- снижается нагрузка на события и перерисовку.
Ограничение
количества маркеров по viewport
Альтернативный или дополнительный метод — отрисовка только видимой
области карты.
Логика фильтрации
При каждом событии:
выполняется проверка попадания точки в текущие границы:
- северо-восточная и юго-западная границы viewport;
- сравнение координат маркеров с bounds.
Только попавшие в диапазон элементы создаются и отображаются.
Преимущество подхода
- минимальное количество активных объектов;
- отсутствие необходимости держать всю коллекцию в DOM;
- естественная масштабируемость.
Ограничение
При большом массиве данных фильтрация на клиенте становится узким
местом. В таких случаях применяется серверная фильтрация.
Серверная агрегация данных
При работе с десятками или сотнями тысяч точек оптимальнее переносить
обработку на сервер.
Подход
Клиент отправляет:
- bounding box карты;
- уровень зума;
Сервер возвращает:
- только точки внутри области;
- или уже агрегированные кластеры.
Преимущества
- минимизация трафика;
- снижение нагрузки на браузер;
- возможность сложной гео-агрегации (grid clustering, H3,
geohash).
Типичные методы агрегации
- geohash-группировка;
- hexagonal binning (H3);
- квадратная сетка (grid index).
Использование уровней
детализации (LOD)
LOD (Level of Detail) позволяет менять представление данных в
зависимости от масштаба.
Пример логики:
- zoom 3–6: страны / регионы;
- zoom 7–10: города;
- zoom 11–14: районы;
- zoom 15–20: отдельные объекты.
Эффект
LOD полностью заменяет тысячи маркеров несколькими слоями данных.
Замена маркеров на
кастомные overlay-слои
Стандартные маркеры являются тяжёлым объектом. Альтернативой
выступают:
OverlayView;
- Canvas-слои;
- WebGL-рендеринг.
Canvas-рендеринг
При использовании canvas:
- все точки рисуются в одном холсте;
- отсутствует создание DOM-узлов;
- отрисовка происходит батчами.
Преимущество:
- десятки тысяч точек без падения FPS.
Недостаток:
- сложная обработка событий (hit-testing вручную).
WebGL-подход
На больших наборах данных используется WebGL:
- GPU-ускоренная отрисовка;
- возможность миллиона точек;
- минимальная нагрузка на main thread.
Снижение количества
обработчиков событий
Каждый маркер в Google Maps JavaScript API может иметь собственные
обработчики:
При тысячах маркеров это создаёт значительную нагрузку.
Оптимизация через
делегирование событий
Вместо навешивания событий на каждый маркер:
- используется один глобальный обработчик;
- определяется объект по координатам курсора;
- выполняется lookup в структуре данных.
Lazy rendering (ленивая
отрисовка)
Подход заключается в том, что маркеры создаются только:
- при входе в viewport;
- при достижении определённого zoom;
- при остановке движения карты (
idle).
Техническая схема
- Пользователь двигает карту.
- Маркеры временно скрываются.
- После стабилизации viewport выполняется пересчёт.
- Отображаются только релевантные объекты.
Использование
простых иконок вместо сложных DOM-структур
Производительность сильно зависит от сложности маркера.
Медленные варианты:
- HTML-маркеры (
AdvancedMarkerElement с DOM);
- кастомные SVG с анимацией;
- сложные React/Vue компоненты внутри маркера.
Быстрые варианты:
- bitmap-иконки;
- заранее отрендеренные изображения;
- минимальные SVG без фильтров.
Батчинг обновлений карты
Частая ошибка — обновление маркеров по одному.
Неправильно:
- добавление каждого маркера отдельно;
- последовательные вызовы
setMap.
Правильно:
- формирование массива;
- массовое добавление;
- единичное обновление слоя.
Дебаунсинг событий карты
События:
zoom_changed
bounds_changed
drag
могут вызываться десятки раз в секунду.
Решение
Используется debounce/throttle:
- обновление происходит после паузы;
- уменьшается число перерасчётов кластеров;
- стабилизируется FPS.
Предварительное вычисление
кластеров
Для статических наборов данных применяются:
- предрасчёт кластеров на разных zoom уровнях;
- хранение результатов в кеше;
- мгновенная отрисовка без вычислений на клиенте.
Итоговая
архитектура высокопроизводительной карты
Оптимизированная система обычно включает:
- серверную агрегацию;
- LOD-структуру данных;
- клиентскую кластеризацию;
- ограничение viewport;
- canvas или WebGL слой;
- минимальное число DOM-маркеров.
Такой подход позволяет работать с геоданными объёмом в сотни тысяч
или даже миллионы точек без заметной деградации интерфейса.