Клавиатурные события

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

Поддержка клавиатуры является важной частью доступности веб-приложений. Leaflet содержит встроенную систему обработки нажатий клавиш, благодаря которой пользователь может взаимодействовать с картой через стандартные элементы управления.


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

По умолчанию клавиатурное управление активировано.

const map = L.map('map', {
    keyboard: true
});

Параметр keyboard определяет, будет ли карта реагировать на нажатия клавиш.

Если необходимо полностью отключить такую возможность:

const map = L.map('map', {
    keyboard: false
});

Или после создания карты:

map.keyboard.disable();

Повторное включение:

map.keyboard.enable();

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

После получения фокуса карта начинает реагировать на ряд клавиш.

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

Стрелки клавиатуры перемещают карту:

Клавиша Действие
Сдвиг влево
Сдвиг вправо
Сдвиг вверх
Сдвиг вниз

Пример:

Карта смещается к северу.

Карта смещается к югу.


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

Для изменения масштаба используются клавиши:

+
-

или

=
-

В зависимости от раскладки клавиатуры и браузера.


Получение фокуса картой

Карта начинает обрабатывать клавиатурные события только после получения фокуса.

Leaflet автоматически назначает контейнеру карты атрибут tabindex.

Пример HTML:

<div id="map"></div>

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

Проверить элемент контейнера:

const container = map.getContainer();

console.log(container.tabIndex);

Доступ к DOM-элементу карты

Для работы со стандартными клавиатурными событиями браузера часто требуется ссылка на контейнер карты.

const mapContainer = map.getContainer();

После этого можно использовать обычные обработчики JavaScript.

mapContainer.addEventListener('keydown', function(event) {
    console.log(event.key);
});

Событие keydown

Событие keydown возникает в момент нажатия клавиши.

Пример регистрации:

map.getContainer().addEventListener(
    'keydown',
    function(event) {
        console.log('Нажата клавиша:', event.key);
    }
);

При нажатии стрелки вверх:

Нажата клавиша: ArrowUp

Событие keyup

Событие keyup вызывается после отпускания клавиши.

map.getContainer().addEventListener(
    'keyup',
    function(event) {
        console.log('Отпущена:', event.key);
    }
);

Применяется для завершения операций перемещения, рисования или навигации.


Определение конкретной клавиши

Современный способ проверки основан на свойстве key.

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === 'Enter') {
            console.log('Enter');
        }

    }
);

Другие популярные значения:

event.key === 'Escape'
event.key === 'ArrowLeft'
event.key === 'ArrowRight'
event.key === 'ArrowUp'
event.key === 'ArrowDown'
event.key === ' '
event.key === '+'
event.key === '-'

Использование свойства code

Свойство code описывает физическую клавишу независимо от раскладки.

map.getContainer().addEventListener(
    'keydown',
    function(event) {
        console.log(event.code);
    }
);

Примеры:

KeyA
KeyW
KeyD
KeyS
ArrowLeft
ArrowRight

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


Перемещение карты клавишами WASD

Часто вместо стрелок используются игровые клавиши.

const step = 100;

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.code === 'KeyW') {
            map.panBy([0, -step]);
        }

        if (event.code === 'KeyS') {
            map.panBy([0, step]);
        }

        if (event.code === 'KeyA') {
            map.panBy([-step, 0]);
        }

        if (event.code === 'KeyD') {
            map.panBy([step, 0]);
        }

    }
);

Метод panBy() перемещает карту на указанное количество пикселей.


Управление масштабом с клавиатуры

Масштабирование можно реализовать самостоятельно.

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === '+') {
            map.zoomIn();
        }

        if (event.key === '-') {
            map.zoomOut();
        }

    }
);

Используемые методы:

map.zoomIn();
map.zoomOut();

Изменение масштаба на фиксированное значение

Метод setZoom() позволяет задавать точный уровень.

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === '1') {
            map.setZoom(5);
        }

        if (event.key === '2') {
            map.setZoom(10);
        }

        if (event.key === '3') {
            map.setZoom(15);
        }

    }
);

Центрирование карты по нажатию клавиши

Клавиатурные команды могут быстро перемещать карту к заранее известным координатам.

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === 'h') {
            map.setView([51.505, -0.09], 13);
        }

    }
);

После нажатия клавиши карта перемещается к заданной точке.


Переключение между наборами данных

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

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === '1') {
            map.addLayer(citiesLayer);
            map.removeLayer(roadsLayer);
        }

        if (event.key === '2') {
            map.addLayer(roadsLayer);
            map.removeLayer(citiesLayer);
        }

    }
);

Такой подход удобен для GIS-приложений.


Создание маркера клавишей Enter

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === 'Enter') {

            const center = map.getCenter();

            L.marker(center).addTo(map);
        }

    }
);

Маркер создаётся в центре текущего вида карты.


Удаление объектов клавишей Delete

let selectedMarker;

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (
            event.key === 'Delete' &&
            selectedMarker
        ) {

            map.removeLayer(selectedMarker);
            selectedMarker = null;

        }

    }
);

Подобная схема часто применяется в редакторах карт.


Использование Escape для отмены действия

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === 'Escape') {

            drawingMode = false;

            console.log('Режим рисования отключён');

        }

    }
);

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


Обработка комбинаций клавиш

Ctrl + S

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (
            event.ctrlKey &&
            event.key === 's'
        ) {

            event.preventDefault();

            saveProject();
        }

    }
);

Свойство ctrlKey показывает состояние клавиши Ctrl.


Shift + стрелка

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (
            event.shiftKey &&
            event.key === 'ArrowRight'
        ) {

            map.panBy([300, 0]);
        }

    }
);

Такой механизм позволяет реализовать ускоренное перемещение карты.


Alt + клавиша

if (
    event.altKey &&
    event.key === 'm'
) {
    console.log('Специальный режим');
}

Предотвращение стандартного поведения браузера

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

Например:

event.preventDefault();

Пример:

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === ' ') {

            event.preventDefault();

            console.log('Пробел обработан');

        }

    }
);

Без этого страница может прокручиваться вниз.


Остановка всплытия события

Для предотвращения передачи события другим элементам используется:

event.stopPropagation();

Пример:

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        event.stopPropagation();

    }
);

Непрерывное перемещение при удержании клавиши

При удержании клавиши событие keydown вызывается многократно.

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === 'ArrowRight') {
            map.panBy([20, 0]);
        }

    }
);

Однако скорость зависит от настроек операционной системы.

Для полного контроля обычно применяется собственный цикл анимации.


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

Создание объекта состояния:

const keys = {};

Запоминание нажатий:

document.addEventListener(
    'keydown',
    function(event) {
        keys[event.code] = true;
    }
);

Фиксация отпускания:

document.addEventListener(
    'keyup',
    function(event) {
        keys[event.code] = false;
    }
);

Использование:

if (keys.KeyW) {
    map.panBy([0, -5]);
}

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


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

Пример переключения между объектами.

const markers = [
    marker1,
    marker2,
    marker3
];

let currentIndex = 0;

Обработчик:

map.getContainer().addEventListener(
    'keydown',
    function(event) {

        if (event.key === 'Tab') {

            event.preventDefault();

            currentIndex++;

            if (currentIndex >= markers.length) {
                currentIndex = 0;
            }

            map.panTo(
                markers[currentIndex].getLatLng()
            );
        }

    }
);

Карта автоматически перемещается к выбранному объекту.


Клавиатурные события и доступность

При разработке интерфейсов рекомендуется соблюдать несколько правил:

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

Практический пример комплексного управления

const container = map.getContainer();

container.addEventListener(
    'keydown',
    function(event) {

        switch(event.key) {

            case 'ArrowUp':
                map.panBy([0, -100]);
                break;

            case 'ArrowDown':
                map.panBy([0, 100]);
                break;

            case 'ArrowLeft':
                map.panBy([-100, 0]);
                break;

            case 'ArrowRight':
                map.panBy([100, 0]);
                break;

            case '+':
                map.zoomIn();
                break;

            case '-':
                map.zoomOut();
                break;

            case 'Home':
                map.setView(
                    [51.505, -0.09],
                    13
                );
                break;

            case 'Enter':

                L.marker(
                    map.getCenter()
                ).addTo(map);

                break;
        }

    }
);

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