Сенсорные события

Сенсорное взаимодействие в HERE Maps API строится вокруг унифицированной модели событий, которая объединяет касания (touch), указательные события (pointer events) и высокоуровневые жесты карты. Архитектура взаимодействия рассчитана на работу как в мобильных браузерах, так и на десктопных устройствах с тачскринами и мышью, обеспечивая единый поток событий для обработки пользовательских действий.


Модель событий и уровень абстракции

В основе интерактивности карты лежат три слоя обработки:

  • Низкоуровневые события DOM (touchstart, touchmove, pointerdown и др.)
  • Промежуточный слой обработки жестов HERE (H.mapevents)
  • Высокоуровневые события карты (tap, drag, longpress, pointermove)

Такое разделение позволяет абстрагироваться от различий между устройствами ввода и сосредоточиться на логике взаимодействия с картой.

Ключевым компонентом является модуль:

const mapEvents = new H.mapevents.MapEvents(map);

Он подключает обработку сенсорных и указательных событий к экземпляру карты.

Далее создаётся поведенческий слой:

const beh * avior = new H.mapevents.Behavior(mapEvents);

Behavior отвечает за стандартные жесты: панорамирование, масштабирование, вращение и инерцию движения.


Базовые сенсорные жесты карты

После подключения H.mapevents.Behavior карта начинает автоматически обрабатывать стандартные жесты:

  • Pan (перемещение) — перетаскивание карты одним пальцем или мышью
  • Pinch zoom (масштабирование) — двумя пальцами
  • Double tap (двойной тап) — увеличение масштаба
  • Two-finger rotate (вращение) — поворот карты
  • Inertia (инерция) — продолжение движения после отпускания

Эти жесты реализуются внутри Behavior и не требуют ручной обработки DOM-событий.


События карты и их типы

HERE Maps API предоставляет набор событий уровня карты, которые абстрагированы от конкретного устройства ввода:

  • tap — одиночное касание или клик
  • longpress — длительное удержание
  • dragstart, drag, dragend — перетаскивание
  • pointermove — движение указателя
  • pointerdown, pointerup — начало и конец взаимодействия
  • wheel — масштабирование колесом мыши

Пример регистрации события касания:

map.addEventListener('tap', function (evt) {
    const coord = map.screenToGeo(
        evt.currentPointer.viewportX,
        evt.currentPointer.viewportY
    );

    console.log('Координаты точки:', coord.lat, coord.lng);
});

Событие содержит данные о позиции указателя и контекст взаимодействия.


Объект события и координаты

Каждое сенсорное событие содержит объект PointerEvent, включающий:

  • viewportX, viewportY — координаты на экране
  • target — объект карты или слой
  • type — тип события
  • currentPointer — активный указатель
  • pointers — список всех активных касаний

Преобразование экранных координат в географические выполняется через:

map.screenToGeo(viewportX, viewportY);

Обратное преобразование:

map.geoToScreen(latitude, longitude);

Это ключевой механизм связывания UI-событий с географической логикой.


Обработка одиночного касания

Событие tap используется для выбора объектов карты, установки маркеров и получения координат точки касания.

map.addEventListener('tap', function (evt) {
    const position = map.screenToGeo(
        evt.currentPointer.viewportX,
        evt.currentPointer.viewportY
    );

    const marker = new H.map.Marker(position);
    map.addObject(marker);
});

При использовании слоёв объектов событие может возвращать дополнительные данные:

map.addEventListener('tap', function (evt) {
    const object = evt.target;
    if (object instanceof H.map.Marker) {
        object.setVisibility(false);
    }
});

Длительное нажатие и контекстные действия

Событие longpress возникает при удержании точки контакта в течение заданного времени.

map.addEventListener('longpress', function (evt) {
    const coord = map.screenToGeo(
        evt.currentPointer.viewportX,
        evt.currentPointer.viewportY
    );

    console.log('Контекстное действие в точке:', coord);
});

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


Перетаскивание карты и управление движением

События dragstart, drag, dragend позволяют отслеживать движение карты:

map.addEventListener('dragstart', function () {
    console.log('Начало перемещения карты');
});

map.addEventListener('drag', function (evt) {
    const deltaX = evt.currentPointer.viewportX - evt.startX;
    const deltaY = evt.currentPointer.viewportY - evt.startY;

    console.log('Смещение:', deltaX, deltaY);
});

map.addEventListener('dragend', function () {
    console.log('Завершение перемещения');
});

Эти события полезны для синхронизации UI-элементов с движением карты.


Мультисенсорные жесты и масштабирование

Масштабирование двумя пальцами обрабатывается автоматически, однако его параметры могут быть перехвачены через события указателей.

map.addEventListener('pointermove', function (evt) {
    if (evt.pointers.length === 2) {
        console.log('Мультисенсорный жест масштабирования');
    }
});

Механизм Behavior интерпретирует расстояние между касаниями как коэффициент масштабирования.


Отключение стандартного поведения

Иногда требуется подавление стандартных жестов карты для реализации кастомной логики взаимодействия.

behavior.disable(H.mapevents.Behavior.Feature.PANNING);
behavior.disable(H.mapevents.Behavior.Feature.ZOOMING);
behavior.disable(H.mapevents.Behavior.Feature.ROTATING);

После отключения стандартных обработчиков события начинают поступать в сыром виде, что позволяет полностью контролировать обработку касаний.


Кастомная обработка pointer-событий

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

map.addEventListener('pointerdown', function (evt) {
    console.log('Pointer down:', evt.pointerId);
});

map.addEventListener('pointerup', function (evt) {
    console.log('Pointer up:', evt.pointerId);
});

При необходимости можно реализовать собственную систему жестов поверх этих событий.


Сопоставление экранных и географических координат

Сенсорные события практически всегда требуют преобразования координат:

map.addEventListener('tap', function (evt) {
    const geo = map.screenToGeo(
        evt.currentPointer.viewportX,
        evt.currentPointer.viewportY
    );

    const screen = map.geoToScreen(geo.lat, geo.lng);

    console.log('Geo:', geo, 'Screen:', screen);
});

Такое двустороннее преобразование используется при создании интерактивных слоёв, визуализаций и пользовательских объектов.


Работа с множественными касаниями

Система pointer events поддерживает несколько одновременных точек взаимодействия:

map.addEventListener('pointermove', function (evt) {
    evt.pointers.forEach(function (pointer) {
        console.log(pointer.pointerId, pointer.viewportX, pointer.viewportY);
    });
});

Это важно для реализации кастомных жестов, таких как масштабирование по расстоянию между пальцами или вращение по углу между точками касания.


Приоритет событий и предотвращение конфликтов

При активном Behavior часть событий может перехватываться встроенной логикой карты. Для предотвращения конфликта используется контроль propagation:

map.addEventListener('tap', function (evt) {
    evt.stopPropagation();
});

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


Производительность при обработке сенсорных событий

Частые события pointermove и drag могут вызывать нагрузку на основной поток. Для оптимизации применяется:

  • ограничение частоты обработки (throttling)
  • использование requestAnimationFrame
  • минимизация вычислений внутри обработчиков
let lastTime = 0;

map.addEventListener('pointermove', function (evt) {
    const now = Date.now();
    if (now - lastTime < 16) return;
    lastTime = now;

    // обработка движения
});

Интеграция сенсорных событий с объектами карты

События могут быть привязаны к графическим объектам:

const marker = new H.map.Marker({ lat: 52.5, lng: 13.4 });

marker.addEventListener('tap', function () {
    console.log('Маркер активирован');
});

map.addObject(marker);

Это позволяет строить интерактивные слои с независимой логикой поведения для каждого объекта.


Синхронизация жестов и состояния карты

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

  • центр карты изменяется при drag
  • уровень масштабирования изменяется при pinch zoom
  • угол поворота изменяется при rotate gesture

Отслеживание состояния:

map.addEventListener('mapviewchange', function () {
    console.log(map.getCenter(), map.getZoom());
});

Это позволяет синхронизировать внешние компоненты интерфейса с действиями пользователя на карте.