При отображении большого количества маркеров на карте возникает несколько проблем:
Кластеризация решает эти проблемы путём объединения близко расположенных маркеров в единый объект — кластер. Вместо десятков или сотен отдельных точек отображается один элемент с числом, указывающим количество объектов внутри группы.
При изменении масштаба карты кластеры автоматически пересчитываются. Чем больше масштаб, тем сильнее происходит детализация, а отдельные маркеры постепенно становятся видимыми.
Для работы с кластерами в Google Maps JavaScript API используется отдельная библиотека:
<script
src="https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js">
</script>
Современная реализация основана на пакете:
@googlemaps/markerclusterer
Основной класс:
MarkerClusterer
Он принимает карту и массив маркеров, после чего автоматически группирует их по алгоритму кластеризации.
Базовое подключение карты:
<!DOCTYPE html>
<html>
<head>
<title>Marker Clustering</title>
<style>
#map {
width: 100%;
height: 600px;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
<script src="https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js"></script>
<script src="app.js"></script>
</body>
</html>
Начальная настройка карты:
const map = new google.maps.Map(
document.getElementById("map"),
{
center: {
lat: 55.7558,
lng: 37.6176
},
zoom: 5
}
);
После создания карты можно приступать к добавлению маркеров.
Кластеризатор работает не с координатами, а с объектами
Marker.
Пример массива данных:
const locations = [
{ lat: 55.7558, lng: 37.6176 },
{ lat: 59.9343, lng: 30.3351 },
{ lat: 56.8389, lng: 60.6057 },
{ lat: 54.7104, lng: 20.4522 }
];
Создание маркеров:
const markers = locations.map(position => {
return new google.maps.Marker({
position
});
});
Обратите внимание: маркеры пока не привязаны к карте через свойство
map. Их отображением будет управлять кластеризатор.
Минимальная конфигурация:
new markerClusterer.MarkerClusterer({
map,
markers
});
Или:
const markerCluster = new markerClusterer.MarkerClusterer({
map: map,
markers: markers
});
После выполнения кода маркеры автоматически группируются.
const map = new google.maps.Map(
document.getElementById("map"),
{
center: {
lat: 55.7558,
lng: 37.6176
},
zoom: 4
}
);
const locations = [
{ lat: 55.7558, lng: 37.6176 },
{ lat: 55.7512, lng: 37.6184 },
{ lat: 55.7544, lng: 37.6200 },
{ lat: 59.9343, lng: 30.3351 },
{ lat: 59.9370, lng: 30.3300 },
{ lat: 59.9300, lng: 30.3400 }
];
const markers = locations.map(location => {
return new google.maps.Marker({
position: location
});
});
const clusterer =
new markerClusterer.MarkerClusterer({
map,
markers
});
Результат:
Обычно данные поступают из базы данных или API.
Генерация случайных координат:
const markers = [];
for (let i = 0; i < 1000; i++) {
const lat =
55 + Math.random() * 10;
const lng =
35 + Math.random() * 15;
markers.push(
new google.maps.Marker({
position: { lat, lng }
})
);
}
Создание кластера:
new markerClusterer.MarkerClusterer({
map,
markers
});
Даже при нескольких тысячах объектов карта остаётся удобной для взаимодействия.
Библиотека позволяет выбирать алгоритмы формирования групп.
Импорт алгоритма:
const algorithm =
new markerClusterer.SuperClusterAlgorithm();
Использование:
new markerClusterer.MarkerClusterer({
map,
markers,
algorithm
});
Алгоритм SuperClusterAlgorithm основан на
пространственном индексировании и обеспечивает высокую
производительность при работе с десятками тысяч маркеров.
Радиус определяет, насколько близко должны находиться маркеры для объединения.
Пример:
const algorithm =
new markerClusterer.SuperClusterAlgorithm({
radius: 80
});
Подключение:
new markerClusterer.MarkerClusterer({
map,
markers,
algorithm
});
Типичные значения:
| Радиус | Поведение |
|---|---|
| 40 | Мелкие кластеры |
| 60 | Стандартное объединение |
| 80 | Крупные группы |
| 100+ | Агрессивная кластеризация |
Маленький радиус увеличивает детализацию, большой — уменьшает количество отображаемых объектов.
Иногда необходимо отключить кластеризацию после достижения определённого масштаба.
Пример:
const algorithm =
new markerClusterer.SuperClusterAlgorithm({
maxZoom: 15
});
Использование:
new markerClusterer.MarkerClusterer({
map,
markers,
algorithm
});
Поведение:
Создание кластеризатора:
const clusterer =
new markerClusterer.MarkerClusterer({
map,
markers: []
});
Создание нового маркера:
const marker =
new google.maps.Marker({
position: {
lat: 55.75,
lng: 37.61
}
});
Добавление:
clusterer.addMarker(marker);
Добавление нескольких объектов:
clusterer.addMarkers([
marker1,
marker2,
marker3
]);
Кластеры будут автоматически пересчитаны.
Удаление одного объекта:
clusterer.removeMarker(marker);
Удаление нескольких:
clusterer.removeMarkers([
marker1,
marker2
]);
Полная очистка:
clusterer.clearMarkers();
После удаления структура кластеров пересчитывается автоматически.
Иногда требуется доступ к текущему набору объектов.
const markers =
clusterer.getMarkers();
console.log(markers);
Это может использоваться для анализа данных или построения статистики.
По умолчанию используется стандартный стиль Google Maps.
Для создания собственного оформления применяется объект
renderer.
Пример:
const renderer = {
render({ count, position }) {
return new google.maps.Marker({
position,
label: {
text: String(count),
color: "#ffffff",
fontSize: "14px"
},
icon: {
path: google.maps.SymbolPath.CIRCLE,
fillColor: "#1976D2",
fillOpacity: 1,
strokeColor: "#ffffff",
strokeWeight: 2,
scale: 25
}
});
}
};
Подключение:
new markerClusterer.MarkerClusterer({
map,
markers,
renderer
});
В результате кластеры получают собственный дизайн.
Количество маркеров внутри кластера можно использовать для выбора цвета.
const renderer = {
render({ count, position }) {
let color = "#4CAF50";
if (count > 50) {
color = "#FF9800";
}
if (count > 100) {
color = "#F44336";
}
return new google.maps.Marker({
position,
label: {
text: String(count),
color: "#fff"
},
icon: {
path: google.maps.SymbolPath.CIRCLE,
fillColor: color,
fillOpacity: 1,
strokeWeight: 2,
scale: 28
}
});
}
};
Такой подход позволяет визуально оценивать плотность объектов на карте.
Событие клика помогает реализовать собственную логику взаимодействия.
Пример:
const clusterer =
new markerClusterer.MarkerClusterer({
map,
markers,
});
Обработчик:
google.maps.event.addListener(
map,
"click",
() => {
console.log("Клик по карте");
}
);
Для кластеров чаще применяется кастомный рендерер и собственные обработчики внутри создаваемых маркеров.
Например:
const clusterMarker =
new google.maps.Marker({
position
});
clusterMarker.addListener(
"click",
() => {
console.log(count);
}
);
Стандартное поведение большинства кластеризаторов заключается в увеличении масштаба карты после выбора группы объектов.
При клике происходит:
Такой механизм обеспечивает удобную навигацию по большим наборам данных.
Для крупных проектов рекомендуется:
SuperClusterAlgorithm;Пример конфигурации:
const clusterer =
new markerClusterer.MarkerClusterer({
map,
markers,
algorithm:
new markerClusterer.SuperClusterAlgorithm({
radius: 60,
maxZoom: 16
})
});
Такая схема позволяет эффективно отображать десятки и даже сотни тысяч географических объектов.
Ошибка:
MarkerClusterer is not defined
Причина:
<script src="https://maps.googleapis.com/maps/api/js"></script>
Отсутствует библиотека кластеризации.
Необходимо подключить:
<script
src="https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js">
</script>
Нежелательный вариант:
new google.maps.Marker({
position,
map
});
и одновременно:
new MarkerClusterer({
map,
markers
});
В таком случае объект отображается дважды.
Правильнее:
new google.maps.Marker({
position
});
Управление отображением передаётся кластеризатору.
Пример:
radius: 200
Последствия:
Обычно достаточно диапазона:
40–80
Нежелательно:
setInterval(() => {
new MarkerClusterer({
map,
markers
});
}, 1000);
Это приводит к росту потребления памяти и ухудшению производительности.
Предпочтительно обновлять существующий экземпляр через методы:
addMarker()
removeMarker()
clearMarkers()
Кластеризация активно применяется в системах, где требуется отображать большое количество географических объектов:
Во всех этих случаях использование кластеров позволяет сохранить высокую производительность интерфейса и обеспечить удобную работу с большими массивами пространственных данных.