HERE Maps API for JavaScript предоставляет развитую модель событий, позволяющую отслеживать взаимодействие пользователя с картой, изменения состояния визуализации и внутренние обновления слоёв. Логирование этих событий используется для аналитики поведения, отладки, мониторинга производительности и построения интерактивных сценариев.
Архитектура событий построена вокруг подписок на объекты карты и её компонентов. Каждый объект, связанный с визуализацией (карта, слои, маркеры, геометрия), может генерировать события, которые перехватываются обработчиками.
Основной способ регистрации событий — метод
addEventListener. Он доступен у экземпляра карты и
большинства интерактивных объектов.
const map = new H.Map(
document.getElementById('mapContainer'),
defaultLayers.vector.normal.map,
{
center: { lat: 52.52, lng: 13.405 },
zoom: 10,
pixelRatio: window.devicePixelRatio || 1
}
);
map.addEventListener('tap', function (evt) {
console.log('Событие tap:', evt);
});
Каждое событие передаёт объект evt, содержащий:
Наиболее часто используемые события связаны с пользовательским вводом:
tap — одиночное нажатиеlongpress — длительное нажатиеdragstart — начало перетаскиванияdrag — процесс перетаскиванияdragend — завершение перетаскиванияpointermove — движение указателяПример логирования всех взаимодействий:
const interactionEvents = [
'tap',
'longpress',
'dragstart',
'drag',
'dragend',
'pointermove'
];
interactionEvents.forEach(eventType => {
map.addEventListener(eventType, evt => {
console.log(`[${eventType}]`, {
screenX: evt.currentPointer.viewportX,
screenY: evt.currentPointer.viewportY,
geo: map.screenToGeo(
evt.currentPointer.viewportX,
evt.currentPointer.viewportY
)
});
});
});
Карты генерируют события при изменении масштаба, центра и ориентации.
mapviewchange — любое изменение представленияmapviewchangeend — завершение измененияmapviewchangestart — начало измененияmap.addEventListener('mapviewchange', () => {
const zoom = map.getZoom();
const center = map.getCenter();
console.log('Состояние карты:', {
zoom,
lat: center.lat,
lng: center.lng
});
});
Для логирования завершённых изменений используется более стабильное событие:
map.addEventListener('mapviewchangeend', () => {
console.log('Финальное состояние:', {
zoom: map.getZoom(),
center: map.getCenter()
});
});
Маркерные и векторные объекты также поддерживают события. Это важно для построения интерактивных слоёв.
const marker = new H.map.Marker({ lat: 52.5, lng: 13.4 });
marker.addEventListener('tap', evt => {
console.log('Клик по маркеру:', evt.target.getGeometry());
});
map.addObject(marker);
При работе с группами объектов события могут всплывать (event bubbling), что позволяет централизованно логировать взаимодействие:
const group = new H.map.Group();
group.addEventListener('tap', evt => {
console.log('Событие группы:', evt.target);
}, true);
map.addObject(group);
При масштабных проектах целесообразно выносить обработку событий в единый логгер.
class MapEventLogger {
constructor(mapInstance) {
this.map = mapInstance;
this.logs = [];
this.attach();
}
attach() {
const events = ['tap', 'drag', 'mapviewchangeend'];
events.forEach(type => {
this.map.addEventListener(type, evt => this.handle(type, evt));
});
}
handle(type, evt) {
const entry = {
type,
time: Date.now(),
zoom: this.map.getZoom(),
center: this.map.getCenter(),
raw: evt
};
this.logs.push(entry);
console.log('LOG:', entry);
}
export() {
return JSON.stringify(this.logs);
}
}
const logger = new MapEventLogger(map);
События pointermove и drag генерируются с
высокой частотой. Без оптимизации логирование может привести к
перегрузке.
function throttle(fn, delay) {
let lastCall = 0;
return function (...args) {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
fn.apply(this, args);
}
};
}
map.addEventListener(
'pointermove',
throttle(evt => {
console.log('Позиция:', evt.currentPointer);
}, 100)
);
Для корректного логирования часто требуется сопоставление пиксельных координат с географическими:
map.addEventListener('tap', evt => {
const geo = map.screenToGeo(
evt.currentPointer.viewportX,
evt.currentPointer.viewportY
);
console.log('Геокоординаты клика:', geo);
});
Обратное преобразование используется при генерации UI-логов:
const screenPoint = map.geoToScreen({ lat: 52.5, lng: 13.4 });
console.log(screenPoint);
При работе с динамическими слоями можно отслеживать загрузку и обновление данных:
tileloadstarttileloadtileerrorconst provider = new H.map.provider.TileProvider({
...options
});
provider.addEventListener('tileload', evt => {
console.log('Загружен тайл:', evt.tile);
});
provider.addEventListener('tileerror', evt => {
console.log('Ошибка тайла:', evt);
});
События могут комбинироваться в цепочки для анализа поведения:
let interactionStart = null;
map.addEventListener('dragstart', () => {
interactionStart = Date.now();
});
map.addEventListener('dragend', () => {
const duration = Date.now() - interactionStart;
console.log('Длительность перетаскивания:', duration);
});
Логи могут отправляться на сервер аналитики:
function sendLog(data) {
fetch('/api/map-logs', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
}
map.addEventListener('mapviewchangeend', () => {
sendLog({
zoom: map.getZoom(),
center: map.getCenter(),
timestamp: Date.now()
});
});
События ошибок важны для диагностики:
map.addEventListener('error', evt => {
console.error('Ошибка карты:', evt);
});
В сложных приложениях такие события используются для автоматического восстановления состояния или переключения слоёв.
Для полного аудита можно использовать универсальный обработчик:
const allEvents = [
'tap',
'longpress',
'dragstart',
'drag',
'dragend',
'mapviewchange',
'mapviewchangeend',
'pointermove'
];
allEvents.forEach(type => {
map.addEventListener(type, evt => {
console.log('EVENT:', {
type,
time: performance.now(),
target: evt.target || null
});
});
});
События распространяются по иерархии:
Перехват на уровне карты позволяет централизовать логику, но при необходимости можно ограничить обработку на уровне конкретного слоя или объекта, снижая шум логирования и повышая точность анализа поведения.