Advanced Markers

Advanced Markers — современный механизм отображения маркеров в Google Maps JavaScript API, пришедший на смену классическому классу google.maps.Marker. Новая система предоставляет значительно более широкие возможности кастомизации внешнего вида, улучшенную производительность и удобную интеграцию с HTML и CSS.

Основным классом выступает google.maps.marker.AdvancedMarkerElement, позволяющий создавать маркеры на основе DOM-элементов, использовать сложное оформление и внедрять интерактивные пользовательские компоненты непосредственно на карту.


Причины появления Advanced Markers

Традиционные маркеры долгое время были основным способом отображения объектов на карте. Однако с ростом требований к интерфейсам появились ограничения:

  • ограниченная настройка внешнего вида;
  • сложность создания уникального дизайна;
  • необходимость использования изображений для нестандартных маркеров;
  • ограниченные возможности анимации;
  • недостаточная гибкость при работе с HTML-контентом.

Advanced Markers решают эти проблемы благодаря использованию современных веб-технологий.

Основные преимущества:

  • поддержка HTML-разметки;
  • полноценная работа CSS;
  • высокая гибкость оформления;
  • улучшенная интеграция с DOM;
  • поддержка пользовательских компонентов;
  • удобная работа с интерактивными элементами.

Подключение библиотеки Marker

Для работы необходимо подключить библиотеку marker.

Загрузка через importLibrary

const { Map } = await google.maps.importLibrary("maps");
const { AdvancedMarkerElement } =
    await google.maps.importLibrary("marker");

Создание карты:

const map = new Map(document.getElementById("map"), {
    center: {
        lat: 55.7558,
        lng: 37.6176
    },
    zoom: 12,
    mapId: "DEMO_MAP_ID"
});

Параметр mapId является обязательным для большинства сценариев использования Advanced Markers.


Создание простого Advanced Marker

Минимальный пример:

const marker = new AdvancedMarkerElement({
    map: map,
    position: {
        lat: 55.7558,
        lng: 37.6176
    }
});

Маркер сразу отображается на карте после создания.


Основные свойства AdvancedMarkerElement

map

Карта, на которой отображается маркер.

const marker = new AdvancedMarkerElement({
    map: map
});

position

Координаты объекта.

position: {
    lat: 55.7558,
    lng: 37.6176
}

Также поддерживается объект LatLng.

position: new google.maps.LatLng(
    55.7558,
    37.6176
)

title

Текстовая подсказка.

const marker = new AdvancedMarkerElement({
    map,
    position,
    title: "Москва"
});

Текст отображается при наведении курсора.


content

Позволяет использовать собственный DOM-элемент.

const div = document.createElement("div");
div.textContent = "Офис";

const marker = new AdvancedMarkerElement({
    map,
    position,
    content: div
});

Именно свойство content превращает Advanced Marker в мощный инструмент кастомизации.


Использование PinElement

Google предоставляет готовый класс PinElement, позволяющий быстро создавать стилизованные маркеры.

const { PinElement } =
    await google.maps.importLibrary("marker");

Создание пина:

const pin = new PinElement();

const marker = new AdvancedMarkerElement({
    map,
    position,
    content: pin.element
});

Настройка цвета маркера

Цвет фона

const pin = new PinElement({
    background: "#4285F4"
});

Цвет границы

const pin = new PinElement({
    borderColor: "#1A73E8"
});

Цвет значка

const pin = new PinElement({
    glyphColor: "#FFFFFF"
});

Полная настройка

const pin = new PinElement({
    background: "#FF5722",
    borderColor: "#BF360C",
    glyphColor: "#FFFFFF"
});

Использование символов внутри маркера

Свойство glyph позволяет размещать символы или текст.

const pin = new PinElement({
    glyph: "A"
});

Результат:

[A]

Можно использовать цифры:

glyph: "1"

Или эмодзи:

glyph: "?"

Изменение масштаба маркера

Свойство scale управляет размером.

const pin = new PinElement({
    scale: 1.5
});

Уменьшение:

const pin = new PinElement({
    scale: 0.8
});

Создание HTML-маркера

Одним из главных преимуществ Advanced Markers является возможность использовать произвольную HTML-разметку.

Создание DOM-элемента

const markerElement =
    document.createElement("div");

markerElement.classList.add("office-marker");

markerElement.innerHTML = `
    <strong>Главный офис</strong>
`;

CSS:

.office-marker {
    background: white;
    border-radius: 8px;
    padding: 10px 15px;
    box-shadow: 0 2px 10px rgba(0,0,0,.3);
    border: 1px solid #ddd;
    font-size: 14px;
}

Создание маркера:

new AdvancedMarkerElement({
    map,
    position,
    content: markerElement
});

Карточка объекта на карте

Практический пример отображения информации.

const card = document.createElement("div");

card.innerHTML = `
<div class="place-card">
    <h3>Ресторан</h3>
    <p>Итальянская кухня</p>
</div>
`;

CSS:

.place-card {
    width: 180px;
    background: white;
    border-radius: 12px;
    padding: 12px;
    box-shadow: 0 4px 20px rgba(0,0,0,.15);
}

.place-card h3 {
    margin: 0 0 6px;
}

Использование:

new AdvancedMarkerElement({
    map,
    position,
    content: card
});

Добавление изображения

Внутрь маркера можно помещать изображения.

const container =
    document.createElement("div");

container.innerHTML = `
<img
    src="store.jpg"
    width="80"
    height="80"
>
`;

Создание:

new AdvancedMarkerElement({
    map,
    position,
    content: container
});

Интерактивные элементы

HTML-маркер может содержать кнопки и формы.

const panel = document.createElement("div");

panel.innerHTML = `
<button id="detailsBtn">
    Подробнее
</button>
`;

После добавления в DOM:

setTimeout(() => {
    document
        .getElementById("detailsBtn")
        .addEventListener("click", () => {
            alert("Информация");
        });
}, 0);

Обработка событий

Событие click

marker.addListener("click", () => {
    console.log("Маркер нажат");
});

Переход к объекту

marker.addListener("click", () => {

    map.panTo(marker.position);

    map.setZoom(16);

});

Получение координат

marker.addListener("click", () => {

    console.log(
        marker.position.lat,
        marker.position.lng
    );

});

Изменение позиции

Маркер можно перемещать динамически.

marker.position = {
    lat: 59.9386,
    lng: 30.3141
};

Или:

marker.position =
    new google.maps.LatLng(
        59.9386,
        30.3141
    );

Удаление маркера

Удаление производится отсоединением от карты.

marker.map = null;

Повторное отображение:

marker.map = map;

Управление видимостью

Скрытие:

marker.map = null;

Показ:

marker.map = map;

Такой подход заменяет методы setVisible() классических маркеров.


Работа с большим количеством маркеров

Создание массива объектов:

const locations = [
    { lat: 55.75, lng: 37.61 },
    { lat: 55.77, lng: 37.63 },
    { lat: 55.74, lng: 37.60 }
];

Генерация:

locations.forEach(location => {

    new AdvancedMarkerElement({
        map,
        position: location
    });

});

Кластеризация Advanced Markers

Для группировки большого количества объектов применяется Marker Clusterer.

Установка:

<script src="
https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js">
</script>

Создание массива:

const markers = locations.map(location => {

    return new AdvancedMarkerElement({
        position: location
    });

});

Кластеризация:

new markerClusterer.MarkerClusterer({
    map,
    markers
});

Кластеры позволяют эффективно отображать тысячи объектов без снижения производительности.


Использование CSS-анимаций

HTML-маркеры прекрасно работают с CSS.

.pulse-marker {
    width: 20px;
    height: 20px;
    background: red;
    border-radius: 50%;

    animation:
        pulse 1.5s infinite;
}

@keyframes pulse {

    0% {
        transform: scale(1);
    }

    50% {
        transform: scale(1.5);
    }

    100% {
        transform: scale(1);
    }

}

Создание:

const markerNode =
    document.createElement("div");

markerNode.className =
    "pulse-marker";

new AdvancedMarkerElement({
    map,
    position,
    content: markerNode
});

Использование SVG

SVG позволяет создавать полностью масштабируемые маркеры.

const svg = document.createElement("div");

svg.innerHTML = `
<svg width="50" height="50">
    <circle
        cx="25"
        cy="25"
        r="20"
        fill="#4285F4"
    />
</svg>
`;

Применение:

new AdvancedMarkerElement({
    map,
    position,
    content: svg
});

Использование пользовательских компонентов

Advanced Markers хорошо сочетаются с современными фреймворками.

Пример DOM-компонента:

const component =
    document.createElement("div");

component.innerHTML = `
<div class="marker-widget">
    <span>Склад №3</span>
</div>
`;

Разметка может генерироваться:

  • React;
  • Vue;
  • Angular;
  • Svelte;
  • Lit;
  • Web Components.

После рендера элемент передается в content.


Сравнение Marker и AdvancedMarkerElement

Возможность Marker Advanced Marker
Пользовательский HTML Нет Да
Полноценный CSS Нет Да
SVG-контент Ограниченно Да
DOM-элементы Нет Да
Готовые PinElement Нет Да
Современная архитектура Нет Да
Гибкая кастомизация Ограничена Да
Интерактивные компоненты Ограничены Да

Рекомендации по производительности

Минимизировать количество DOM-узлов

Плохо:

<div>
    <div>
        <div>
            <div>
                Текст
            </div>
        </div>
    </div>
</div>

Лучше:

<div>Текст</div>

Использовать CSS вместо JavaScript-анимаций

Предпочтительно:

animation: pulse 1s infinite;

Вместо:

setInterval(() => {
    ...
}, 16);

Кластеризовать большие наборы данных

При количестве объектов более нескольких сотен рекомендуется использовать Marker Clusterer.


Переиспользовать DOM-элементы

Если внешний вид маркеров одинаковый, желательно использовать шаблоны и фабрики компонентов вместо создания сложной разметки вручную для каждого объекта.


Типичные сценарии применения

Advanced Markers особенно эффективны для:

  • каталогов недвижимости;
  • сервисов доставки;
  • транспортных систем;
  • логистических платформ;
  • отображения офисов компаний;
  • туристических карт;
  • карт торговых центров;
  • систем мониторинга транспорта;
  • корпоративных GIS-решений;
  • административных панелей и дашбордов.

Благодаря поддержке HTML, CSS, SVG и пользовательских DOM-компонентов класс AdvancedMarkerElement является основным инструментом создания современных интерактивных маркеров в Google Maps JavaScript API и предоставляет значительно более широкие возможности по сравнению с устаревшим подходом на основе google.maps.Marker.