Кластеризація маркерів: де ламається карта і що втрачає замовник
Карта з десятком міток працює миттєво, і на цьому етапі здається, що завдання вирішено.
Але варто базі вирости до сотень і тисяч об'єктів — і застосунок починає помітно гальмувати: відмальовування просідає, жести смикаються, а на слабких пристроях карта в застосунку підвисає на кожному переміщенні.
Причина не в «слабкому телефоні», а в тому, що кожен об'єкт відмальовується як окремий елемент. Чим більше точок на карті, тим дорожче обходиться кожен кадр.
Далі з'являється другий, менш очевидний збій — втрата видимості. Коли мітки стоять щільно, вони перекривають одна одну: користувач бачить одну іконку там, де насправді їх двадцять. Об'єкт фізично є в даних, але на екрані його немає.
Для сценарію замовника це пряма втрата — клієнт не знаходить потрібну точку і йде, хоча вона була поруч.
Третій збій протилежний за симптомом, але так само б'є по результату — хибне відчуття порожнечі. Якщо при зменшенні масштабу карта не перезбирає дані, частина об'єктів просто зникає з видачі, і користувач робить висновок, що пропозицій у його районі немає. Насправді вони є, але інтерфейс їх не показав.
Усі три збої ростуть з одного кореня: карта намагається показати все одразу, замість того щоб показувати потрібне на поточному масштабі. Кластеризація маркерів вирішує саме це — групує близькі об'єкти в один вузол і розкриває їх у міру наближення.
Продуктивність карти перестає залежати від загальної кількості точок, а відображення об'єктів на карті залишається чесним на будь-якому зумі.
Розбираємо, як це закривається на практиці і які параметри групування визначають, чи буде карта чутливою.
Що дає кластеризація маркерів: ефект у цифрах і режимах
Кластеризація маркерів — це не «гарна карта», а спосіб утримати швидкість відмальовування картки в передбачуваних межах при зростанні кількості об'єктів.
Без неї кожна точка на карті — окремий елемент інтерфейсу: на кількох тисячах міток прокручування та масштабування починають відставати від жесту, а на слабких пристроях карта підгальмовує вже при відкритті.
Групування точок на карті переводить цю залежність у майже постійну: кількість об'єктів, що відмальовуються, визначається не обсягом даних, а поточним масштабом.
Що змінюється в цифрах
- Час відмальовування кадру. При десятках тисяч міток без групування кадр збирається помітно довше; після впровадження — стабільно в межах одного-двох кадрів на будь-якому масштабі.
- Час до інтерактивної карти. Екран перестає чекати повного завантаження всіх точок: спочатку показуються кластери, деталізація підтягується в міру наближення.
- Вартість простою карти. Поки користувач чекає на відгук, сценарій не виконується — замовлення втрачає конверсію. Чутлива карта повертає ці дії у воронку.
- Споживання пам'яті. Замість тисяч живих об'єктів на екрані — одиниці кластерів, що знижує ризик падіння застосунку на довгій сесії.
Режими відображення карти
Режим вибирається під сценарій, а не «за замовчуванням»: десь важлива щільність, десь — точність окремої мітки. Нижче — робочі альтернативи, між якими реально вибирають.
| Варіант | Коли підходить | Обмеження |
|---|---|---|
| Сіткове групування | Щільні однорідні дані, простий сценарій | Кластери «стрибають» при зміні масштабу |
| Ієрархічне групування | Різнорідні об'єкти, потрібна деталізація за рівнями | Складніше налаштування порогів |
| Групування за регіонами | Заздалегідь відома географія, стабільні зони | Погано працює на нечітких межах |
| Без групування | Менше сотні міток, висока точність | Деградація при зростанні даних |
Наші інженери налаштовують пороги, поведінку при перекритті та плавність переходів між рівнями — Supercluster та аналогічні бібліотеки дають базу, але параметри під конкретний набір даних підбираються вручну.
Чому це окупається
Ефект не в самому групуванні, а в тому, що карта перестає бути вузьким місцем сценарію. Користувач доходить до мети без пауз, а продукт витримує зростання бази об'єктів без переписування екрана.
Як ми впроваджуємо кластеризацію: етапи інженерної роботи
Впровадження кластеризації починається не з коду, а з аудиту карти застосунку: дивимося, скільки об'єктів реально завантажується на екран, як влаштовано джерело даних, де втрачається чутливість під час зуму та панорамування.
На цьому етапі фіксуємо поточні метрики — час відмальовування області, кількість одночасних запитів, поведінку за слабкої мережі — щоб після робіт було з чим порівняти.
- Аудит карти застосунку. Розбираємо поточну реалізацію: як формуються маркери, звідки надходять координати, чи є дублі та «мертві» точки. Визначаємо пороги, після яких карта починає гальмувати, і цільові значення за кількістю об'єктів на екрані.
- Проєктування схеми групування. Обираємо модель кластеризації під характер даних: статичні точки, динамічні об'єкти або змішаний набір. Узгоджуємо поведінку на різних масштабах — де маркер залишається одиничним, а де об'єднується в групу.
- Налаштування групування маркерів. Реалізуємо розбиття за сіткою з перерахунком під час зміни масштабу, налаштовуємо радіус об'єднання та пріоритети відображення. Окремо опрацьовуємо підписи кластерів і плавність перебудови, щоб карта не «стрибала» під час зуму.
- Оптимізація завантаження даних. Переводимо підвантаження на область видимості: застосунок запитує лише ті об'єкти, що потрапляють на екран, і кешує вже отримані. Це знімає зайве навантаження на серверну частину та прискорює відгук карти.
- Перевірка карти. Проганяємо сценарії на різних обсягах даних, слабкому каналі та старих пристроях: зум, панорамування, перехід із кластера в окремі точки. Звіряємо поведінку з узгодженими порогами та виправляємо розбіжності.
- Передача документації. Віддаємо замовнику налаштування групування, схему джерела даних, опис порогів і поведінки на кожному масштабі. Фіксуємо, як змінювати параметри без участі розробника.
Кожен етап закінчується артефактом, який можна перевірити: звіт з аудиту, узгоджена схема, робочий прототип на реальних даних, результати перевірки.
Такий порядок прибирає ситуацію, коли кластеризацію впроваджено, але карта все одно гальмує на щільних ділянках — розбіжності видно на етапі перевірки, а не після випуску.
Чим кластеризація на клієнті відрізняється від серверного групування?
Клієнтська кластеризація рахує групи прямо на пристрої: застосунок тримає всі точки в пам'яті, перераховує сітку при кожному зсуві чи зумі та малює один маркер на комірку.
Серверне групування переносить цю роботу на бекенд — застосунок надсилає видиму область і рівень зуму, а у відповідь отримує вже готові кластери з координатами та лічильником.
Різниця проявляється не в картинці, а в тому, де витрачається ресурс і що відбувається, коли мережа просідає.
Клієнтський варіант виграє на малих і середніх наборах: до кількох тисяч точок перерахунок сітки вкладається в кадр, карта залишається чутливою без жодного запиту, а при слабкому зв'язку поведінка взагалі не змінюється — дані вже на пристрої.
Межа настає на обсязі: десятки тисяч маркерів з'їдають пам'ять, перерахунок на кожному русі починає ронити частоту кадрів, а холодний старт розтягується, поки вантажиться весь набір. Плюс дані лежать на клієнті цілком — це питання не лише ваги, а й того, що взагалі йде на пристрій.
Серверне групування знімає навантаження із застосунку: пристрій зберігає лише те, що потрапило на екран, обсяг вибірки обмежений видимою областю, а важкі набори живуть на бекенді. Плата — залежність від каналу.
Кожен зсув карти перетворюється на запит, і при слабкому зв'язку користувач бачить порожню карту або підвантаження замість маркерів.
Лікується це кешем останніх відповідей по тайлах, об'єднанням близьких запитів і відрисовкою попереднього стану, поки не прийшла нова відповідь, — але це вже окремий шар роботи поверх архітектури карти.
На практиці вибір рідко бінарний. Часто беруть гібрид: базовий шар кластерів приходить із сервера, а деталізація всередині щільних зон рахується на клієнті з уже завантаженого набору.
Межа між підходами проходить по обсягу даних, вимогах до свіжості точок і тому, наскільки критична робота в метро, на трасі чи в підвалі — тобто там, де зв'язок пропадає.
Кейс: як кластеризація маркерів прискорила карту в застосунку доставки
У застосунку доставки карта показувала всі активні замовлення та кур'єрів одночасно — при щільному навантаженні району на екран виводилися тисячі міток.
Вимірювання на реальних пристроях давали час відмальовування кадру близько 1,2 секунди при панорамуванні та до 2,5 секунди при зумі: інтерфейс смикався, а частина об'єктів не встигала промальовуватися до наступного жесту.
Окрема проблема — загублені об'єкти: при швидкому перетягуванні карти мітки, що потрапили в кадр у момент перемальовування, просто не з'являлися, і диспетчер бачив неповну картину району.
Ми почали з профілювання: зняли таймлайни рендерингу на середньому та слабкому пристрої, порахували, скільки міток реально потрапляє у видиму область при типових сценаріях роботи диспетчера.
Виявилося, що на екрані фізично вміщується 20–40 об'єктів, а в шар відмальовування йшли всі — різниця і була джерелом просідання.
Що змінили
Ввели кластеризацію маркерів із перерахунком сітки під поточний масштаб: на дальньому зумі близькі точки згортаються в один маркер із числом, на крупному — розкриваються назад в окремі об'єкти.
Перерахунок іде інкрементально при зміні області видимості, а не на кожен кадр, тому панорамування більше не запускає повне перезбирання шару.
Додали поріг розкриття кластера та пріоритет відображення: проблемні замовлення та активні кур'єри залишаються видимими довше за інших. Це прибрало сценарій, коли важлива мітка ховалася всередині групи.
Метрики до і після
| Показник | До | Після |
|---|---|---|
| Час відмальовування кадру при панорамуванні | ~1,2 с | 40–60 мс |
| Час відмальовування при зумі | до 2,5 с | 60–90 мс |
| Частка загублених об'єктів при швидкому зсуві | до 15% | менше 1% |
| Кількість об'єктів у шарі відмальовування | всі активні | 20–40 видимих |
Плавність повернулася на пристроях, де карта раніше була непридатною для роботи. Диспетчери перестали чекати відгуку при перетягуванні, а неповна картина району більше не призводила до помилкових призначень.
Логіку кластеризації та перерахунку сітки будували на можливостях картографічного шару MapLibre — він дає кероване джерело даних і не тягне за собою зайву вагу в збірці застосунку.
Сумніви перед впровадженням: сумісність, міграція, відкат, доступи
Кластеризація маркерів рідко ламає сам застосунок — вона конфліктує з уже працюючою картою: чужими шарами, кастомними пінами, логікою фільтрів і правами на ключі.
Тому до старту ми фіксуємо точки стикування: яка карта використовується зараз, як віддаються тайли і хто володіє ключем доступу.
Що якщо карта вже інтегрована і її не можна змінювати? Кластеризація ставиться поверх поточного шару — наявні маркери, попапи та обробники залишаються на місці, змінюється лише спосіб відрисовки при щільному скупченні точок. Міграція карти не потрібна: підключення йде до тієї самої карти, що вже в застосунку.
Що якщо потрібно повернутися до попередньої поведінки? Відкат змін робиться перемикачем у конфігурації: кластеризація вмикається і вимикається без перезбирання релізу, а попередня логіка відображення маркерів зберігається як запасний режим.
Як вирішуються доступи до карти та ключів?
Ключі та токени залишаються у вашому акаунті картографічного провайдера — ми не переносимо їх на свою сторону.
Доступи видаються на час робіт і відкликаються після здачі, а конфігурація ключів описана в документації по карті: де зберігається, як ротується, які обмеження по доменах і застосунках виставлені.
На руки після здачі замовник отримує:
- конфігурацію кластеризації: пороги об'єднання, поведінка на різних масштабах, стилі кластерів;
- схему сумісності карти — які шари та обробники зачеплені, які залишилися недоторканими;
- регламент міграції карти та порядок перемикання між режимами відображення;
- процедуру відкату змін з покроковою перевіркою після повернення;
- матрицю доступів до карти: хто володіє ключами, кому видано доступ, як він відкликається;
- документацію по карті з описом конфігурації, обмежень і точок розширення.
Опишіть вашу задачу — повернемося з оцінкою та планом робіт по вашому застосунку.







