
Инструкция по использованию Яндекс.Карты с кластеризацией меток и динамическим обновлением
Шаг 1: Получение API-ключа Яндекс.Карт
Для работы с Яндекс.Картами необходимо получить API-ключ. Следуйте этим шагам:
- Перейдите на страницу получения ключа API Яндекс.Карт.
- Войдите в свой аккаунт Яндекса (если еще не зарегистрированы, создайте новый).
- Создайте новый API-ключ, следуя инструкциям на сайте.
- Скопируйте полученный ключ. Он понадобится для работы карты.

Шаг 2: Подключение Яндекс.Карт на страницу
Вставьте следующий код в раздел <head> вашего HTML-документа:
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU&apikey=ВАШ_API_КЛЮЧ" type="text/javascript"></script>
Замените ВАШ_API_КЛЮЧ на API-ключ, который вы получили на предыдущем шаге.
Шаг 3: HTML-разметка
Создайте контейнер, в котором будет отображаться карта:
<div id="yandex-map"></div>
Также, в вашем HTML должны быть карточки объектов, для которых вы хотите отображать метки на карте. Каждая карточка должна содержать атрибуты data-lat (широта) и data-lon (долгота), а также дополнительные атрибуты, которые будут отображаться в балуне карты.
Пример карточки:
<div class="map-objects-container">
<div class="map-object" data-lat="55.75" data-lon="37.62" data-title="Магазин 1" data-address="Москва, ул. Тверская, 1" data-phone="+7 (495) 123-45-67"></div>
<div class="map-object" data-lat="55.76" data-lon="37.63" data-title="Магазин 2" data-address="Москва, ул. Арбат, 2" data-phone="+7 (495) 234-56-78"></div>
</div>
Каждая карточка может содержать дополнительные атрибуты, такие как data-title, data-address, data-phone и т.д.
Шаг 4: Добавление JavaScript для инициализации карты и кластеризации меток
Вставьте следующий код JavaScript в файл или в конце HTML-документа перед закрывающимся тегом </body>:
document.addEventListener("DOMContentLoaded", function () {
let observer = null;
let map = null;
// Переменные, которые можно настроить
const containerSelector = ".map-objects-container"; // Контейнер с объектами
const objectSelector = ".map-object"; // Класс объектов
const mapContainerId = "yandex-map"; // Контейнер для карты
// Конфигурация карты
const mapOptions = {
center: [55.751244, 37.618423], // Начальные координаты
zoom: 5, // Начальный зум
controls: ['zoomControl', 'geolocationControl'], // Контролы
type: 'yandex#map', // Тип карты
};
function initMap() {
if (map) {
map.destroy();
}
map = new ymaps.Map(mapContainerId, mapOptions);
// Определяем кастомный макет балуна
ymaps.layout.storage.add('custom#balloonLayout', ymaps.templateLayoutFactory.createClass(
`<div class="custom-balloon">
<div class="custom-balloon__content">$[properties.balloonContent]</div>
<button class="custom-balloon__close">✖</button>
</div>`, {
build: function () {
this.constructor.superclass.build.call(this);
document.querySelector('.custom-balloon__close').addEventListener('click', () => {
this.getData().geoObject.balloon.close();
});
}
}));
addMarkers();
}
function addMarkers() {
map.geoObjects.removeAll();
let objects = document.querySelectorAll(`${containerSelector} ${objectSelector}[data-lat][data-lon]`);
let coordinates = [];
const clusterer = new ymaps.Clusterer({
preset: 'islands#invertedRedClusterIcons',
groupByCoordinates: false,
zoomMargin: 100,
clusterDisableClickZoom: false
});
objects.forEach(function (object) {
let lat = parseFloat(object.getAttribute("data-lat"));
let lon = parseFloat(object.getAttribute("data-lon"));
let title = object.getAttribute("data-title") || "Без названия";
let address = object.getAttribute("data-address") || "Адрес не указан";
let phone = object.getAttribute("data-phone") || "Телефон не указан";
if (!isNaN(lat) && !isNaN(lon)) {
let placemark = new ymaps.Placemark([lat, lon], {
balloonContent: `
<strong>${title}</strong><br>
<span class="balloon-address">${address}</span><br>
<span class="balloon-phone">${phone}</span>
`
}, {
balloonLayout: 'custom#balloonLayout'
});
clusterer.add(placemark);
coordinates.push([lat, lon]);
}
});
map.geoObjects.add(clusterer);
if (coordinates.length > 0) {
let bounds = getBounds(coordinates);
map.setBounds(bounds, { checkZoomRange: true });
} else {
map.setCenter(mapOptions.center, mapOptions.zoom);
}
}
function getBounds(coordinates) {
let latitudes = coordinates.map(coord => coord[0]);
let longitudes = coordinates.map(coord => coord[1]);
let minLat = Math.min(...latitudes);
let maxLat = Math.max(...latitudes);
let minLon = Math.min(...longitudes);
let maxLon = Math.max(...longitudes);
return [[minLat, minLon], [maxLat, maxLon]];
}
const objectsContainer = document.querySelector(containerSelector);
if (objectsContainer) {
observer = new MutationObserver(debounce(initMap, 500));
observer.observe(objectsContainer, { childList: true, subtree: true });
}
function debounce(func, wait) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
initMap();
});
Шаг 5: Обновление карты при изменении данных
Если данные о дилерах изменяются динамически (например, через фильтры или асинхронную загрузку контента), карта будет автоматически обновляться. Для этого используется MutationObserver, который отслеживает изменения внутри контейнера .map-objects-container.
Дополнительные настройки
- Метки: Вы можете добавить любые атрибуты в карточки дилеров (например, data-email, data-rating, data-description) и использовать их для отображения в балуне или в другом месте на карте.
Комментарии пользователей (1)