В библиотеке Leaflet иконки маркеров реализуются через систему
классов L.Icon и L.DivIcon, где базовый класс
L.Icon отвечает за отображение растровых изображений
маркеров и их поведения на карте. Архитектура класса построена вокруг
описания ресурсов изображения и параметров позиционирования, что
позволяет гибко управлять тем, как маркер визуально привязан к
координате на карте.
L.Icon определяет внешний вид маркера через набор
параметров:
Экземпляр L.Icon не занимается логикой карты или
координатами, он исключительно описывает визуальное представление
маркера.
Создание иконки осуществляется через конструктор:
const icon = L.icon(options);
где options — объект конфигурации.
Параметр iconUrl задаёт путь к изображению маркера.
const icon = L.icon({
iconUrl: 'marker.png'
});
Это обязательное поле, без которого иконка не может быть корректно отрисована (если не используется кастомная реализация).
iconSize определяет размеры изображения в пикселях.
iconSize: [32, 32]
Размер влияет на:
Важно, что Leaflet не масштабирует изображение автоматически под контейнер карты, поэтому размер должен соответствовать фактическому разрешению ресурса или быть явно адаптирован.
iconAnchor задаёт точку внутри изображения, которая
будет привязана к географической координате маркера.
iconAnchor: [16, 32]
Если иконка размером 32×32, то точка [16, 32] означает
нижний центр изображения.
Без правильного iconAnchor маркеры визуально «прыгают»
относительно координаты, особенно при использовании нестандартных
иконок.
popupAnchor определяет смещение всплывающего окна
относительно точки привязки иконки.
popupAnchor: [0, -32]
Обычно используется для того, чтобы popup появлялся над маркером, а не перекрывал его.
Логика смещения всегда строится от iconAnchor.
Тень маркера задаётся отдельно:
shadowUrl: 'marker-shadow.png',
shadowSize: [41, 41]
Тень рисуется под основной иконкой и также требует корректной синхронизации размеров. Несовпадение размеров тени и иконки часто приводит к визуальным артефактам.
Аналогично iconAnchor, определяет точку привязки
тени:
shadowAnchor: [12, 41]
Это позволяет выровнять тень относительно основного маркера.
Позволяет добавить CSS-класс к контейнеру иконки:
className: 'custom-marker'
Используется для:
const customIcon = L.icon({
iconUrl: 'marker.png',
shadowUrl: 'marker-shadow.png',
iconSize: [32, 32],
shadowSize: [41, 41],
iconAnchor: [16, 32],
shadowAnchor: [12, 41],
popupAnchor: [0, -32],
className: 'custom-marker'
});
Иконка передаётся в объект маркера через параметр
icon:
L.marker([51.5, -0.09], { icon: customIcon }).addTo(map);
Маркер использует только визуальное представление, а не изменяет геометрию координат.
L.Icon реализует два ключевых метода:
createIconcreateShadowЭти методы возвращают DOM-элементы, которые добавляются в карту.
Создаёт основной элемент изображения:
<img> или <div> (в
зависимости от реализации)src = iconUrlУпрощённая логика:
createIcon() {
const img = document.createElement('img');
img.src = this.options.iconUrl;
img.style.width = this.options.iconSize[0] + 'px';
img.style.height = this.options.iconSize[1] + 'px';
return img;
}
Работает аналогично createIcon, но создаёт отдельный
слой тени:
createShadow() {
const img = document.createElement('img');
img.src = this.options.shadowUrl;
return img;
}
Если shadowUrl не задан, метод может возвращать
null.
L.Icon можно расширять для создания кастомных
классов:
const MyIcon = L.Icon.extend({
options: {
iconUrl: 'custom.png',
iconSize: [40, 40],
iconAnchor: [20, 40]
}
});
Использование:
const icon = new MyIcon();
Такой подход полезен при создании набора стандартизированных иконок для разных типов объектов (магазины, остановки, события).
Поддержка экранов с высокой плотностью пикселей реализуется через
параметр iconRetinaUrl:
const icon = L.icon({
iconUrl: 'marker.png',
iconRetinaUrl: 'marker@2x.png',
iconSize: [32, 32]
});
При обнаружении retina-дисплея библиотека автоматически подменяет изображение.
Если не указать icon, используется
L.Icon.Default, который:
Это поведение обеспечивает работоспособность карты без дополнительной настройки.
Иконка маркера является DOM-элементом, поэтому её поведение частично контролируется через CSS:
.custom-marker {
transition: transform 0.2s ease;
}
Это позволяет реализовать:
Важно учитывать, что позиционирование маркера управляется Leaflet,
поэтому нельзя произвольно изменять position без риска
нарушения привязки.
При работе с большим количеством маркеров важно учитывать:
L.Icon создаёт отдельный DOM-узелОптимизационные подходы:
L.IconDivIcon вместо изображений при массовых
объектахХотя основная тема — L.Icon, важно учитывать
альтернативу:
L.Icon — изображения (<img>)L.DivIcon — HTML-элементы
(<div>)L.DivIcon используется для:
L.Icon предпочтителен для:
Неверный iconAnchor
Отсутствие iconSize
Использование изображений без оптимизации
Несоответствие shadow размерам
Динамическая смена iconUrl без обновления маркера
Иконку можно изменить после создания маркера:
marker.setIcon(newIcon);
При этом Leaflet пересоздаёт DOM-элемент и обновляет отображение.
Такой подход используется для:
В сложных приложениях часто используется фабрика:
function createIcon(type) {
return L.icon({
iconUrl: `${type}.png`,
iconSize: [32, 32],
iconAnchor: [16, 32]
});
}
Это упрощает управление наборами иконок и уменьшает дублирование конфигураций.
L.Icon представляет собой слой абстракции над
DOM-элементом изображения, где:
Такая архитектура позволяет сочетать простоту использования с достаточной гибкостью для кастомных картографических интерфейсов.