Инструкция по использованию Яндекс.Карты с кластеризацией меток и динамическим обновлением

Инструкция по использованию Яндекс.Карты с кластеризацией меток и динамическим обновлением

Игорь Мисайлов

Шаг 1: Получение API-ключа Яндекс.Карт

Для работы с Яндекс.Картами необходимо получить API-ключ. Следуйте этим шагам:

  1. Перейдите на страницу получения ключа API Яндекс.Карт.
  2. Войдите в свой аккаунт Яндекса (если еще не зарегистрированы, создайте новый).
  3. Создайте новый API-ключ, следуя инструкциям на сайте.
  4. Скопируйте полученный ключ. Он понадобится для работы карты.

Шаг 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) и использовать их для отображения в балуне или в другом месте на карте.

Обучающее видео

Автор статьи

Комментарии пользователей (0)

Подписаться
Уведомить о
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии