Клавиатурная навигация

Клавиатурная навигация в веб-картах является критически важной частью доступности и интерактивности интерфейса. В экосистеме HERE Technologies она реализуется на уровне карты и её UI-компонентов, позволяя пользователю перемещать карту, изменять масштаб и взаимодействовать с объектами без использования мыши.

Основная цель клавиатурного управления — обеспечить полноценную работу карты для пользователей с ограниченной моторикой, а также для сценариев, где мышь недоступна или нежелательна (например, киоски, терминалы, навигационные панели).


Базовая модель фокуса в HERE Maps

Любая интерактивная карта в JavaScript API строится вокруг DOM-элемента контейнера. Именно он становится точкой входа для клавиатурных событий.

Ключевые принципы:

  • контейнер карты должен получать фокус (tabindex)
  • события клавиатуры обрабатываются только при активном фокусе
  • управление картой привязано к состоянию focus/blur

Простейшая инициализация контейнера:

<div id="mapContainer" tabindex="0"></div>
const platform = new H.service.Platform({
  apikey: 'YOUR_API_KEY'
});

const defaultLayers = platform.createDefaultLayers();

const map = new H.Map(
  document.getElementById('mapContainer'),
  defaultLayers.vector.normal.map,
  {
    center: { lat: 52.5200, lng: 13.4050 },
    zoom: 10,
    pixelRatio: window.devicePixelRatio || 1
  }
);

Добавление tabindex="0" критично: без него элемент не может быть активирован с клавиатуры.


Включение поведения клавиатурной навигации

В HERE Maps API клавиатурное управление не всегда включено автоматически в зависимости от конфигурации слоя взаимодействия. Основной механизм реализуется через поведенческий объект (behavior).

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

Этот слой отвечает за:

  • обработку клавиатурных событий
  • интерпретацию стрелок, пробела, +/- клавиш
  • синхронизацию с жестами и мышью

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


Основные клавиши управления картой

Стандартный набор клавиатурных действий в HERE Maps API включает следующие элементы управления:

Перемещение карты

  • стрелка вверх — сдвиг карты на север
  • стрелка вниз — сдвиг на юг
  • стрелка влево — сдвиг на запад
  • стрелка вправо — сдвиг на восток

Перемещение происходит с фиксированным шагом, зависящим от текущего масштаба.


Масштабирование

  • + или = — увеличение масштаба
  • - — уменьшение масштаба

Масштабирование выполняется относительно центра текущего вида карты.


Дополнительные клавиши

В зависимости от конфигурации поведения могут поддерживаться:

  • Page Up / Page Down — альтернативное масштабирование
  • Home — возврат к заданному центру (если реализовано в приложении)
  • Space — временная фиксация взаимодействия (в некоторых кастомных сценариях)

Обработка событий клавиатуры вручную

Хотя встроенный behavior покрывает базовые сценарии, в сложных интерфейсах требуется перехват и расширение логики.

Пример обработки событий:

map.getElement().addEventListener('keydown', function (event) {
  switch (event.key) {
    case 'ArrowUp':
      map.getViewModel().setLookAtData({
        position: map.getCenter().toScreenCoordinates(map.getZoom())
      });
      break;

    case 'ArrowDown':
      map.setCenter({
        lat: map.getCenter().lat - 0.01,
        lng: map.getCenter().lng
      });
      break;
  }
});

В реальных приложениях прямое изменение координат используется редко; предпочтительнее применять методы map.getViewModel() и map.getViewPort() для корректной синхронизации с внутренними состояниями.


Фокус-менеджмент и доступность

Ключевой аспект клавиатурной навигации — управление фокусом.

Рекомендуемая модель:

  1. контейнер карты получает tabindex
  2. при фокусе активируется обработка поведения
  3. при потере фокуса — отключается реакция на клавиши

Пример контроля состояния:

const mapElement = map.getElement();

mapElement.addEventListener('focus', () => {
  behavior.enable();
});

mapElement.addEventListener('blur', () => {
  behavior.disable();
});

Такой подход предотвращает конфликт клавиш с другими элементами интерфейса страницы.


Конфликты клавиатурных сочетаний

При интеграции карты в сложные интерфейсы часто возникают конфликты:

  • глобальные hotkeys приложения
  • управление формами
  • редакторы текста
  • навигационные панели

Для устранения конфликтов применяется:

1. Приоритет обработки событий

mapElement.addEventListener('keydown', (event) => {
  if (document.activeElement !== mapElement) return;
});

2. Отмена всплытия событий

event.stopPropagation();
event.preventDefault();

Использовать осторожно, чтобы не нарушить доступность.


Настройка поведения клавиш

В стандартной конфигурации поведение клавиатуры можно модифицировать через отключение отдельных компонентов mapevents.

Пример отключения жестов при сохранении клавиатуры:

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

behavior.disable(H.mapevents.Behavior.WHEELZOOM);

Хотя пример показывает отключение колесика мыши, аналогичный принцип применяется для комплексной настройки поведения.


Клавиатурная навигация и кастомные контролы

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

Пример кастомной кнопки:

const button = document.createElement('button');
button.innerText = 'Zoom +';
button.setAttribute('aria-label', 'Увеличить масштаб карты');

button.addEventListener('click', () => {
  map.setZoom(map.getZoom() + 1);
});

button.addEventListener('keydown', (e) => {
  if (e.key === 'Enter' || e.key === ' ') {
    map.setZoom(map.getZoom() + 1);
  }
});

Ключевые моменты:

  • использование <button> вместо <div>
  • наличие aria-label
  • обработка Enter и Space

Работа с ARIA-атрибутами

Доступность карты напрямую связана с ARIA-разметкой.

Рекомендуемые атрибуты:

<div id="mapContainer"
     tabindex="0"
     role="application"
     aria-label="Интерактивная карта">
</div>

role="application" сообщает скринридерам, что внутри контейнера работает отдельное интерактивное приложение.


Синхронизация с виртуальными слоями

HERE Maps API активно использует слои для отображения данных (тайлы, маркеры, полигоны). При клавиатурной навигации важно учитывать:

  • изменение центра карты должно обновлять все overlay-слои
  • фокус не должен теряться при перерисовке
  • события клавиатуры должны оставаться привязанными к контейнеру

Пример защиты от потери событий:

map.addEventListener('mapviewchange', () => {
  map.getElement().focus();
});

Клавиатурная навигация по объектам карты

Более сложный уровень взаимодействия — переход между объектами:

  • маркерами
  • POI
  • полигонами

Подход строится на логике «фокусируемого списка объектов»:

const objects = [];

map.addObject(marker);

objects.push(marker);

Навигация:

let index = 0;

map.getElement().addEventListener('keydown', (e) => {
  if (e.key === 'Tab') {
    e.preventDefault();
    index = (index + 1) % objects.length;
    map.setCenter(objects[index].getGeometry());
  }
});

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


Интеграция с SPA-фреймворками

При использовании React, Vue или Angular важно учитывать жизненный цикл карты:

  • повторная инициализация может сбрасывать поведение клавиатуры
  • необходимо пересоздавать MapEvents при remount
  • фокус должен управляться через ref

Пример логики:

useEffect(() => {
  const map = new H.Map(...);

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

  return () => map.dispose();
}, []);

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

Хотя клавиатурные события относительно лёгкие, проблемы могут возникать при:

  • частом обновлении центра карты
  • сложных overlay-рендерах
  • анимациях переходов

Рекомендуемые подходы:

  • debounce для кастомных обработчиков
  • использование встроенных методов pan/zoom вместо ручных вычислений
  • минимизация DOM-операций внутри keydown

Расширенные сценарии управления

В некоторых интерфейсах клавиатурная навигация дополняется:

  • маршрутизацией стрелками по UI карты
  • переключением слоёв (Ctrl + L)
  • быстрым поиском (Ctrl + F с кастомной логикой)

Такие сценарии требуют строгого контроля конфликтов и документирования hotkeys, чтобы не нарушать стандартное поведение браузера.


Обработка потери фокуса и восстановления состояния

При переключении между вкладками или элементами интерфейса карта может терять активное состояние.

Типичный подход:

window.addEventListener('blur', () => {
  behavior.disable();
});

window.addEventListener('focus', () => {
  behavior.enable();
});

Это предотвращает случайные перемещения карты при возврате пользователя на страницу.


Стабильность клавиатурного UX

Клавиатурная навигация должна оставаться предсказуемой:

  • одинаковые шаги перемещения при одинаковом масштабе
  • отсутствие «скачков» центра
  • сохранение фокуса после обновлений слоя

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