Система событий в Google Maps JavaScript API построена вокруг событийной модели браузера и расширяет стандартный DOM-подход собственными событиями карты, слоёв и объектов. Логирование событий в контексте картографических приложений охватывает фиксацию пользовательских взаимодействий, состояния карты, перемещения камеры, работы с маркерами и слоями, а также системных изменений, влияющих на отображение данных.
События в Google Maps JavaScript API делятся на несколько уровней:
Основной механизм подписки реализуется через:
map.addListener('click', (event) => {
console.log(event.latLng.toString());
});
Альтернативный вариант через глобальный обработчик:
google.maps.event.addListener(map, 'click', function(event) {
console.log(event.latLng.lat(), event.latLng.lng());
});
Несмотря на наличие устаревающего подхода через
google.maps.event, современная практика ориентируется на
addListener, как более читаемый и контекстно привязанный
способ.
При построении системы логирования основное внимание уделяется событиям, отражающим поведение пользователя и изменения состояния карты.
События:
dragstartdragdragendbounds_changedcenter_changedЛогирование этих событий позволяет отслеживать навигационные паттерны пользователя:
map.addListener('dragend', () => {
const center = map.getCenter();
logEvent('map_dragend', {
lat: center.lat(),
lng: center.lng()
});
});
Событие bounds_changed может генерироваться очень часто,
поэтому его использование требует контроля частоты логирования.
Событие zoom_changed фиксирует изменение уровня
приближения:
map.addListener('zoom_changed', () => {
logEvent('zoom_changed', {
zoom: map.getZoom()
});
});
Это событие часто используется для анализа того, на каких уровнях детализации пользователь взаимодействует с картой.
map.addListener('idle', () => {
logEvent('map_idle', {
center: map.getCenter().toJSON(),
zoom: map.getZoom()
});
});
idle полезно для фиксации стабильного состояния карты
после серии изменений.
Маркерные события являются одними из наиболее информативных для аналитики взаимодействия.
marker.addListener('click', () => {
logEvent('marker_click', {
id: marker.id,
position: marker.getPosition().toJSON()
});
});
marker.addListener('dragend', () => {
const pos = marker.getPosition();
logEvent('marker_dragend', {
lat: pos.lat(),
lng: pos.lng()
});
});
При необходимости можно фиксировать дополнительные события:
mouseovermouseoutrightclickОднако их логирование должно быть ограничено из-за высокой частоты вызовов.
Эффективная система логирования в картографических приложениях обычно строится по следующему принципу:
function logEvent(type, payload) {
console.log('[MAP_EVENT]', type, payload);
}
В реальных системах вместо console.log используется
отправка на сервер:
function logEvent(type, payload) {
fetch('/api/logs', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
type,
payload,
timestamp: Date.now()
})
});
}
При высокой активности пользователя прямые запросы на сервер создают нагрузку. Используется буферизация:
const eventBuffer = [];
function logEvent(type, payload) {
eventBuffer.push({
type,
payload,
timestamp: Date.now()
});
}
Отправка по таймеру:
setInterval(() => {
if (eventBuffer.length === 0) return;
const batch = eventBuffer.splice(0, eventBuffer.length);
fetch('/api/logs/batch', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(batch)
});
}, 5000);
Некоторые события требуют ограничения частоты вызовов.
bounds_changedlet lastLog = 0;
map.addListener('bounds_changed', () => {
const now = Date.now();
if (now - lastLog < 1000) return;
lastLog = now;
logEvent('bounds_changed', {
bounds: map.getBounds().toJSON()
});
});
let timeout;
map.addListener('center_changed', () => {
clearTimeout(timeout);
timeout = setTimeout(() => {
logEvent('center_changed_stable', {
center: map.getCenter().toJSON()
});
}, 800);
});
Эффективное логирование включает расширение событий дополнительным контекстом:
function getContext(map) {
return {
zoom: map.getZoom(),
center: map.getCenter().toJSON(),
bounds: map.getBounds()?.toJSON() || null,
devicePixelRatio: window.devicePixelRatio,
screen: {
width: window.innerWidth,
height: window.innerHeight
}
};
}
Использование:
map.addListener('idle', () => {
logEvent('map_idle', getContext(map));
});
События карты редко рассматриваются изолированно. В аналитике важно фиксировать сценарии:
infoWindow.addListener('domready', () => {
logEvent('info_window_open', {
markerId: currentMarkerId
});
});
Логи часто отправляются в внешние системы:
Пример отправки в аналитическую систему:
function logEvent(type, payload) {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: type,
...payload
});
}
Картографические события генерируют большие объёмы данных. Для оптимизации применяются:
Пример фильтрации:
function shouldLogZoom(oldZoom, newZoom) {
return oldZoom !== newZoom;
}
При использовании слоёв (Heatmap, GeoJSON, TileLayer) логируются:
geoJsonLayer.addListener('click', (event) => {
logEvent('geojson_click', {
feature: event.feature.getProperty('id')
});
});
Ошибочная реализация логирования может приводить к деградации интерфейса:
Корректный подход включает:
const listener = map.addListener('click', handler);
// при уничтожении карты
google.maps.event.removeListener(listener);
Логирование событий карты может затрагивать чувствительные данные:
Поэтому применяются:
Пример округления:
function roundCoord(value) {
return Math.round(value * 1000) / 1000;
}
Использование:
map.addListener('click', (event) => {
logEvent('map_click', {
lat: roundCoord(event.latLng.lat()),
lng: roundCoord(event.latLng.lng())
});
});