Google Maps JavaScript API предоставляет механизм отображения
информационных окон (InfoWindow), которые связываются с маркерами карты
и позволяют выводить контекстные данные по объектам геопространства.
Взаимодействие между Marker и InfoWindow
реализуется через событийную модель, где открытие окна информации
происходит в ответ на пользовательские действия или программные
события.
Каждый маркер в API представляет собой объект, связанный с координатами и визуальным отображением на карте. InfoWindow — отдельный объект, содержащий HTML-контент и позиционируемый относительно карты или конкретного маркера.
Связь между ними устанавливается через метод open,
который принимает карту и маркер как аргументы:
const infoWindow = new google.maps.InfoWindow({
content: '<div>Точка интереса</div>'
});
const marker = new google.maps.Marker({
position: { lat: 55.751244, lng: 37.618423 },
map: map,
title: 'Москва'
});
marker.addListener('click', () => {
infoWindow.open({
anchor: marker,
map: map,
shouldFocus: false
});
});
В данной модели anchor определяет объект привязки.
Использование маркера в качестве якоря обеспечивает автоматическое
позиционирование InfoWindow над соответствующей точкой.
Распространённый подход заключается в использовании единственного экземпляра InfoWindow для всех маркеров. Это снижает нагрузку на DOM и предотвращает дублирование окон.
const infoWindow = new google.maps.InfoWindow();
const markers = locations.map((location) => {
const marker = new google.maps.Marker({
position: location.position,
map: map,
title: location.name
});
marker.addListener('click', () => {
infoWindow.setContent(`
<div>
<h3>${location.name}</h3>
<p>${location.description}</p>
</div>
`);
infoWindow.open({
anchor: marker,
map: map
});
});
return marker;
});
При каждом клике содержимое окна обновляется методом
setContent, а позиция автоматически синхронизируется с
активным маркером.
InfoWindow не закрывается автоматически при открытии нового окна, если используется несколько экземпляров. При работе с единым экземпляром поведение упрощается, поскольку новое открытие переопределяет предыдущее состояние.
Закрытие осуществляется через метод:
infoWindow.close();
Также возможно отслеживание состояния через событие
closeclick:
infoWindow.addListener('closeclick', () => {
console.log('InfoWindow закрыт');
});
Содержимое InfoWindow может изменяться без его закрытия. Это используется при асинхронной загрузке данных или обновлении информации по событию.
marker.addListener('click', async () => {
infoWindow.setContent('<div>Загрузка...</div>');
infoWindow.open({ anchor: marker, map });
const data = await fetch(`/api/location/${marker.id}`).then(r => r.json());
infoWindow.setContent(`
<div>
<strong>${data.name}</strong>
<p>${data.details}</p>
</div>
`);
});
Подобная схема обеспечивает промежуточную визуализацию состояния загрузки и последующую подмену контента без повторного открытия окна.
В случаях использования кастомных маркеров, созданных через
OverlayView, привязка InfoWindow требует явного указания
позиции через объект LatLng:
infoWindow.open({
map: map,
position: { lat: 55.751244, lng: 37.618423 }
});
Отсутствие anchor компенсируется прямым указанием
координат, что актуально для нестандартных визуальных слоёв.
При работе с множеством маркеров часто применяется паттерн единственного активного InfoWindow. Перед открытием нового окна предыдущее закрывается автоматически:
let activeInfoWindow = null;
markers.forEach((marker, index) => {
marker.addListener('click', () => {
if (activeInfoWindow) {
activeInfoWindow.close();
}
infoWindow.setContent(`<div>${locations[index].name}</div>`);
infoWindow.open({ anchor: marker, map });
activeInfoWindow = infoWindow;
});
});
Такая логика исключает перекрытие интерфейса и упрощает управление состоянием отображения.
Контент InfoWindow поддерживает полноценный HTML, включая обработчики событий, однако после повторного открытия содержимое пересоздаётся, что требует повторной инициализации интерактивных элементов.
infoWindow.setContent(`
<div id="iw-content">
<button id="action-btn">Действие</button>
</div>
`);
infoWindow.addListener('domready', () => {
document.getElementById('action-btn').addEventListener('click', () => {
console.log('Кнопка нажата');
});
});
Событие domready гарантирует, что DOM внутри InfoWindow
уже отрисован и доступен для манипуляций.
Позиционирование окна может корректироваться через параметры
pixelOffset, что позволяет компенсировать перекрытие
маркера:
const infoWindow = new google.maps.InfoWindow({
content: 'Контент',
pixelOffset: new google.maps.Size(0, -30)
});
Это особенно важно при использовании кастомных иконок маркеров с нестандартными размерами.
InfoWindow автоматически синхронизирует своё положение при изменении
центра карты или масштаба. Привязка к anchor обеспечивает
постоянную актуализацию позиции без необходимости ручного пересчёта
координат.
При использовании фиксированной позиции (position)
требуется ручное управление обновлением при изменении состояния карты,
если связанный объект перемещается логически.
Объект InfoWindow сохраняет состояние до явного удаления или замены. Повторное использование одного экземпляра считается оптимальной практикой для снижения накладных расходов. При этом важно учитывать, что содержимое и слушатели событий не сохраняются между открытиями, если они пересоздаются динамически.
Поведение жизненного цикла включает:
open;setContent;close;