Методы работы с маркерами

В Leaflet маркер является базовой сущностью для отображения точечных объектов на карте. Создание маркера выполняется через конструктор L.marker, который принимает координаты в формате широты и долготы.

const marker = L.marker([55.751244, 37.618423]);

Первый аргумент — массив координат [lat, lng]. Внутри библиотеки координаты нормализуются и преобразуются в систему проекции карты (обычно Web Mercator).

Маркер сам по себе не отображается на карте до тех пор, пока не будет добавлен в слой карты.


Добавление маркера на карту

Для отображения маркера используется метод addTo(map) либо классический способ через addLayer.

marker.addTo(map);

Альтернативный вариант:

map.addLayer(marker);

Разница между подходами заключается в архитектурной семантике:

  • addTo(map) — принадлежность объекта карте
  • addLayer(marker) — управление слоями карты как коллекцией

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

Получение текущего положения

const position = marker.getLatLng();
console.log(position.lat, position.lng);

Метод getLatLng() возвращает объект LatLng, содержащий:

  • lat — широта
  • lng — долгота

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

marker.setLatLng([59.934280, 30.335099]);

Также можно передавать объект:

marker.setLatLng({ lat: 59.934280, lng: 30.335099 });

При изменении координат автоматически пересчитывается позиция на экране без необходимости перерисовки всей карты.


Настройки маркера при создании

Конструктор L.marker принимает второй аргумент — объект опций.

const marker = L.marker([55.75, 37.61], {
    draggable: true,
    opacity: 0.8,
    zIndexOffset: 1000
});

Основные параметры

draggable

  • включает возможность перетаскивания маркера мышью

opacity

  • задаёт прозрачность от 0 до 1

zIndexOffset

  • управляет порядком наложения маркеров

autoPan

  • автоматически сдвигает карту при перетаскивании маркера к краю

Перетаскивание маркера (dragging)

При включённой опции draggable: true становится доступен набор событий и методов.

Программное включение и отключение

marker.dragging.enable();
marker.dragging.disable();

События перетаскивания

marker.on('dragstart', () => {
    console.log('перетаскивание началось');
});

marker.on('drag', () => {
    console.log('маркер движется');
});

marker.on('dragend', () => {
    console.log('перетаскивание завершено');
});

События позволяют синхронизировать позицию маркера с внешними данными, например формами ввода координат.


Работа с иконками маркера

Маркер по умолчанию использует стандартную иконку, но её можно заменить через setIcon.

const customIcon = L.icon({
    iconUrl: 'icon.png',
    iconSize: [32, 32],
    iconAnchor: [16, 32]
});

marker.setIcon(customIcon);

Основные методы иконок

  • L.icon() — создание растровой иконки
  • L.divIcon() — HTML-иконка, создаваемая через DOM

Пример HTML-иконки:

const htmlIcon = L.divIcon({
    html: '<div class="custom-marker"></div>',
    className: 'custom-wrapper'
});

marker.setIcon(htmlIcon);

divIcon часто используется для динамических маркеров с изменяемым содержимым.


Привязка всплывающих окон (Popup)

Создание и привязка popup

marker.bindPopup('Текст всплывающего окна');

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


Открытие и закрытие popup программно

marker.openPopup();
marker.closePopup();

Также возможно создание независимого popup:

const popup = L.popup().setContent('Информация');
marker.bindPopup(popup);

Параметры popup

marker.bindPopup('Текст', {
    maxWidth: 200,
    closeButton: true,
    autoClose: false
});

Подсказки (Tooltip)

Tooltip отличается от popup тем, что отображается без клика (или при наведении).

marker.bindTooltip('Подсказка');

Управление отображением

marker.openTooltip();
marker.closeTooltip();

Опции tooltip

marker.bindTooltip('Подсказка', {
    direction: 'top',
    permanent: false,
    opacity: 0.9
});

Основные направления:

  • top
  • bottom
  • left
  • right
  • center

События маркера

Маркер поддерживает широкий набор событий, основанных на системе Evented.

Основные события

marker.on('click', () => {});
marker.on('mouseover', () => {});
marker.on('mouseout', () => {});

События карты, связанные с маркером

marker.on('add', () => {});
marker.on('remove', () => {});

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

function handler() {
    console.log('click');
}

marker.on('click', handler);
marker.off('click', handler);

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

Добавление и удаление слоя

map.removeLayer(marker);
map.addLayer(marker);

Проверка наличия на карте

map.hasLayer(marker);

Изменение z-index и приоритета отображения

marker.setZIndexOffset(500);

Это влияет на визуальное перекрытие маркеров при их наложении в одной точке.


Прозрачность и визуальные параметры

marker.setOpacity(0.5);

Возвращение к полной видимости:

marker.setOpacity(1);

Обновление маркера без пересоздания

Вместо удаления и повторного создания можно обновлять свойства:

marker.setLatLng([60.0, 30.0])
       .setOpacity(0.7)
       .setIcon(customIcon);

Цепочка методов позволяет минимизировать количество операций над DOM и слоями карты.


Кастомные данные и расширение маркера

Маркер может хранить произвольные данные:

marker.options.id = 123;
marker.options.type = 'shop';

Или через bindPopup с функцией:

marker.bindPopup(() => {
    return `ID: ${marker.options.id}`;
});

Методы контроля состояния

Проверка состояния drag

marker.dragging && marker.dragging.enabled();

Получение карты, к которой привязан маркер

const mapInstance = marker._map;

(внутреннее свойство, используется с осторожностью при расширениях)


Производственные особенности работы с большим количеством маркеров

При большом количестве объектов стандартные маркеры становятся тяжёлыми для DOM. Используются методы оптимизации:

  • кластеризация (через плагины)
  • динамическое добавление/удаление слоёв
  • обновление координат без пересоздания
  • переиспользование иконок

Базовый приём обновления набора маркеров:

markers.forEach(m => {
    m.setLatLng(getNewCoords(m));
});

Интеграция маркеров с внешними данными

Маркер часто выступает связующим звеном между географией и прикладной логикой:

marker.on('click', () => {
    fetch(`/api/point/${marker.options.id}`)
        .then(r => r.json())
        .then(data => marker.bindPopup(data.name).openPopup());
});

События позволяют строить реактивные интерфейсы без дополнительного слоя управления состоянием.


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

marker.remove();

Альтернативно:

map.removeLayer(marker);

После удаления объект остаётся в памяти, если на него есть ссылки, но перестаёт участвовать в рендеринге карты.