Клавиатурная навигация в Leaflet основана на встроенном обработчике
L.Map.Keyboard, который перехватывает события клавиатуры,
когда контейнер карты находится в фокусе, и преобразует их в действия
панорамирования и масштабирования. Этот механизм работает поверх
стандартной системы событий браузера и тесно связан с управлением
фокусом DOM-элемента карты.
По умолчанию клавиатурная навигация активна, если карта создана без явного отключения соответствующей опции.
const map = L.map('map', {
keyboard: true
});
Опция keyboard управляет тем, будет ли экземпляр
L.Map регистрировать обработчик клавиатуры. При значении
false карта полностью игнорирует нажатия клавиш, даже если
контейнер находится в фокусе.
Отключение после инициализации:
map.keyboard.disable();
Повторное включение:
map.keyboard.enable();
Leaflet использует фиксированный набор клавиш, привязанный к стандартным действиям:
← ↑ → ↓) — панорамирование карты+ и - — увеличение и уменьшение
масштабаHome — возврат к начальному виду (если задан
setView)End — переход к максимальному доступному состоянию
(зависит от конфигурации и слоёв)Панорамирование выполняется дискретными шагами, величина которых задаётся через параметр конфигурации карты.
Интенсивность перемещения карты при нажатии клавиш регулируется параметром:
const map = L.map('map', {
keyboard: true,
keyboardPanDelta: 80
});
keyboardPanDelta определяет количество пикселей, на
которое сдвигается карта при одном нажатии стрелки. Чем больше значение,
тем быстрее происходит перемещение.
Клавиатурная навигация работает только тогда, когда контейнер карты
находится в фокусе. Leaflet устанавливает tabIndex на
элемент карты, чтобы он стал фокусируемым:
const map = L.map('map', {
keyboard: true,
tabIndex: 0
});
tabIndex: 0 позволяет элементу участвовать в
естественном порядке фокуса страницы.
Получение фокуса программно:
map.getContainer().focus();
При потере фокуса обработка клавиш прекращается автоматически, что предотвращает конфликт с другими элементами интерфейса.
Внутри Leaflet используется объект L.Map.Keyboard,
который подписывается на события keydown и интерпретирует
коды клавиш.
Упрощённая логика:
map.keyboard = new L.Map.Keyboard(map);
map.keyboard._onKeyDown = function (e) {
switch (e.keyCode) {
case 37: map.panBy([-this._map.keyboardPanDelta, 0]); break;
case 38: map.panBy([0, -this._map.keyboardPanDelta]); break;
case 39: map.panBy([this._map.keyboardPanDelta, 0]); break;
case 40: map.panBy([0, this._map.keyboardPanDelta]); break;
case 187: map.zoomIn(); break;
case 189: map.zoomOut(); break;
}
};
Реальная реализация учитывает дополнительные проверки состояния, предотвращает обработку при вводе в элементы формы и нормализует коды клавиш между браузерами.
Leaflet автоматически игнорирует события, если фокус находится внутри интерактивных элементов:
<input><textarea><select>Это предотвращает конфликт между вводом текста и управлением картой.
Логика проверки основана на document.activeElement:
const el = document.activeElement;
const isInput = el && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA');
Полное отключение клавиатурной навигации:
const map = L.map('map', {
keyboard: false
});
Частичная кастомизация через отключение стандартного обработчика и регистрацию собственного:
map.keyboard.disable();
map.getContainer().addEventListener('keydown', function (e) {
if (e.key === 'ArrowUp') {
map.panBy([0, -50]);
}
});
Такой подход позволяет полностью заменить стандартную модель управления.
Leaflet не предоставляет встроенной системы сложных комбинаций (например, Ctrl + стрелка), однако такие сценарии реализуются через проверку модификаторов события:
map.getContainer().addEventListener('keydown', function (e) {
if (e.ctrlKey && e.key === '+') {
map.zoomIn();
}
if (e.shiftKey && e.key === 'ArrowLeft') {
map.panBy([-200, 0]);
}
});
Важно учитывать, что стандартный обработчик Leaflet может перехватывать часть событий, поэтому при расширении логики его обычно отключают.
Клавиатурное панорамирование интегрировано с системой анимации карты. При каждом нажатии стрелки создаётся новое перемещение с учётом текущего состояния инерции.
Если включена инерция:
const map = L.map('map', {
inertia: true
});
то последовательные нажатия клавиш могут суммировать движение, создавая плавный эффект смещения.
Клавиатурная навигация тесно связана с доступностью интерфейса. Контейнер карты должен быть фокусируемым и иметь понятную семантику для вспомогательных технологий.
Leaflet добавляет базовые атрибуты:
role="application" или region (в
зависимости от версии и конфигурации)tabIndex для включения в поток фокусаДополнительные улучшения обычно включают явные подписи:
map.getContainer().setAttribute('aria-label', 'Интерактивная карта');
При клике вне карты или переключении вкладок браузера фокус автоматически снимается, и клавиатурные события больше не обрабатываются. Повторное включение управления требует возврата фокуса на контейнер:
window.addEventListener('load', () => {
map.getContainer().focus();
});
В сложных интерфейсах с несколькими интерактивными областями управление фокусом становится ключевым элементом логики взаимодействия.
Коды клавиш могут различаться:
+ может приходить как 187 или как
=- может быть 189 или
underscore в некоторых раскладкахpreventDefault для предотвращения прокрутки страницыLeaflet нормализует часть этих различий, но при кастомной обработке требуется учитывать кроссбраузерные нюансы:
map.getContainer().addEventListener('keydown', function (e) {
if (e.key === '+' || e.keyCode === 187) {
map.zoomIn();
e.preventDefault();
}
});
При активной карте клавиши стрелок могут конфликтовать со скроллом
страницы. Leaflet предотвращает это, вызывая
preventDefault() внутри обработчика, если событие признано
относящимся к управлению картой.
При отключённом стандартном обработчике такая защита отсутствует и должна реализовываться вручную.
map.getContainer().addEventListener('keydown', function (e) {
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
e.preventDefault();
map.panBy(/* ... */);
}
});
Клавиатурная навигация взаимодействует с:
L.Control.Zoom)Все эти механизмы используют единый интерфейс изменения состояния
карты (setView, panBy, zoomIn,
zoomOut), что обеспечивает согласованное поведение
независимо от источника ввода.