
Инструкция по использованию Яндекс.Карты с кластеризацией меток и динамическим обновлением
Шаг 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)