Использование событий касания
=============================

На сегодняшний день бо́льшая часть содержимого в вебе рассчитана на работу с использованием клавиатуры и мыши. Тем не менее, всё больше появляется устройств с сенсорным экраном (особенно мобильных) и веб-приложения могут либо напрямую обрабатывать сенсорный ввод с помощью `Событий касаний`, либо интерпретировать события мыши. Недостатком использования событий мыши является то, что они не поддерживают одновременный ввод, тогда как события касаний поддерживают несколько одновременных прикосновений (возможно в разных местах сенсорной поверхности), повышая тем самым удобство работы с интерфейсом.

Интерфейсы событий касания поддерживают взаимодействие с приложением с помощью одного или нескольких одновременных прикосновений, такие как жест двумя пальцами. Взаимодействие с помощью нескольких одновременных прикосновений начинается, когда палец (или стилус) впервые касается контактной поверхности. Другие пальцы могут последовательно касаться поверхности и, если нужно, перемещаться по ней. Взаимодействие заканчивается, когда пальцы убираются с поверхности. На протяжении этого взаимодействия приложение получает события касания на начальной стадии, стадии перемещения и стадии завершения. Приложение может применять собственную семантику к сенсорному вводу.

Интерфейсы
----------

События касаний включают три интерфейса `Touch`, `TouchEvent` и `TouchList`, а также следующие типы событий

* `touchstart (en-US)` - вызывается в момент касания сенсорной поверхности
* `touchmove (en-US)` - вызывается при перемещении по сенсорной поверхности
* `touchend (en-US)` - вызывается, если убрали палец
* `touchcancel (en-US)` - вызывается в момент прерывания события (например, создано слишком много точек касания).

Интерфейс `Touch` представляет собой одну точка контакта с сенсорной поверхностью. Точка контакта обычно называется точкой касания или просто касанием. Касание обычно генерируется пальцем или стилусом на сенсорной поверхности. Свойства точки касания включают уникальный идентификатор, целевой элемент точки касания, а также координаты X и Y точки касания относительно области видимости, страницы или экрана.

Интерфейс `TouchList` представляет список точек контакта с сенсорной поверхностью, по одной точке касания на каждый контакт с поверхностью. Таким образом, если пользователь активировал сенсорную поверхность одним пальцем, список будет содержать один элемент, а если пользователь прикоснулся к поверхности тремя пальцами, в списке будет три элемента.

Интерфейс `TouchEvent` представляет событие, которое отправляется, когда меняется состояние контактов с сенсорной поверхностью. Изменения состояния включают начальный контакт с сенсорной поверхностью, перемещение точки касания при сохранении контакта с поверхностью, отпускание точки касания и прерывание события касания. Атрибуты интерфейса включают состояние нескольких клавиш-модификаторов (например, клавиши `Shift`) и следующий список данных:

* `touches` - список всех точек касания, находящихся в данный момент на экране
* `targetTouches` (en-US) - список точек касания на целевом DOM-элементе
* `changedTouches` - список точек касания, элементы которых зависят от типа связанного события:
    + Для события `touchstart (en-US)` - список точек касания, которые стали активными во время события
    + Для события `touchmove (en-US)` - список точек касания, которые изменились с последнего события
    + Для события `touchend (en-US)` - список точек касания, которые были удалены с поверхности (то есть, набор точек касания, соответствующих пальцам, которые больше не касаются поверхности)

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

От интерфейсов к жестам
-----------------------

При определении семантики жеста, приложение может учитывать различные факторы. Например, расстояние, которое прошла точка от начала до конца касания. Другим возможным фактором может быть время, например, количество времени между началом касания и завершением, или количество времени между двумя последовательными касаниями, предназначенными для создания жеста двойного нажатия. Направленность свайпа (например, слева направо, справа налево и т.д) является ещё одним фактором.

Списки касаний, которые использует приложение, зависят от семантики его жестов. Например, если приложение поддерживает однократное касание (тап) одного элемента, будет использоваться список `targetTouches` (en-US) в обработчике события `touchstart (en-US)` для обработки точки касания в свойственной приложению манере. Если приложение поддерживает свайп двумя пальцами для любых двух точек касания, оно будет использовать список `changedTouches` в обработчике `touchmove (en-US)` для того, чтобы определить, были ли перемещены эти две точки касания, а затем реализовать семантику этого жеста в свойственной приложению манере.

Когда есть только одна активная точка касания, браузер обычно отправляет эмулированные события и мыши и клика. Мультитач-действия, включающие две и больше активных точек касания, обычно генерируют только события касания. Чтобы предотвратить отправку эмулированных событий мыши, используйте метод `preventDefault()` в обработчиках событий касания. Дополнительную информацию о взаимодействии между событиями мыши и событиями касаний можно найти в статье `Поддержка TouchEvent и MouseEvent` (en-US).

Основные шаги
-------------

Этот раздел содержит пример базового использования приведённых выше интерфейсов. Более подробный пример можно найти в статье `События касаний (тач-события)`.

Назначьте обработчик событий для каждого типа события касания.


```js
// Назначение обработчика событий касания
someElement.addEventListener("touchstart", process_touchstart, false);
someElement.addEventListener("touchmove", process_touchmove, false);
someElement.addEventListener("touchcancel", process_touchcancel, false);
someElement.addEventListener("touchend", process_touchend, false);
```


Обработчик события, реализующий семантику жестов приложения
```

// Обработчик touchstart
function process_touchstart(ev) {
  // Используется данные события, чтобы вызвать соответствующие обработчики жестов
  switch (ev.touches.length) {
    case 1: handle_one_touch(ev); break;
    case 2: handle_two_touches(ev); break;
    case 3: handle_three_touches(ev); break;
    default: gesture_not_supported(ev); break;
  }
}
```


Доступ к атрибутам точки касания.


```js
// Создание обработчика события "touchstart"
someElement.addEventListener(
  "touchstart",
  function (ev) {
    // Перебор точек события, которые были активированы
    // для этого элемента и обработка каждого целевого элемента события
    for (var i = 0; i < ev.targetTouches.length; i++) {
      process\_target(ev.targetTouches[i].target);
    }
  },
  false,
);
```


Предотвращение эмуляции событий мыши


```js
// Обработчик события "touchmove"
function process\_touchmove(ev) {
  // Вызов "preventDefault()"
  ev.preventDefault();
}
```

Лучшие практики
---------------

Вот несколько моментов, которых следует придерживаться при работе с событиями касаний:

* Сводите к минимуму объём работы, выполняемой в обработчиках касаний
* Добавляйте обработчики точек касаний к определённому целевому элементу, а не ко всему документу или узлам, расположенным выше в дереве
* Добавляйте обработчики событий `touchmove (en-US)`, `touchend (en-US)` и `touchcancel (en-US)` внутрь `touchstart (en-US)`.
* Целевой элемент или узел для события касания должен быть достаточно большим, для касания пальцем. Если целевая область слишком мала, прикосновений к ней может привести к вызову событий для других прилегающих элементов.
Информация о совместимости с браузерами
---------------------------------------

Согласно данным о совместимости с браузерами, поддержка событий касания среди мобильных браузеров относительно неплохая. Десктопные браузеры немного отстают, хотя над этим уже ведётся работа.

Некоторые новые функции, связанные с областью касания (областью контакта между пользователем и сенсорной поверхностью) - находятся в процессе стандартизации. Новый функционал включает в себя радиусы эллипса по осям X и Y, которые наиболее точно описывают область контакта с сенсорной поверхностью. *Угол поворота* точки касания - градус, на который нужно повернуть упомянутый эллипс, чтобы соответствовать области контакта - также стандартизирован, как и степень давления в точке касания.

А что насчёт Событий Указателя?
-------------------------------

Внедрение новых механизмов ввода усложняет обработку всех возможных событий, таких как события клавиатуры, мыши, пера, касаний. Чтобы помочь решить эту проблему, стандарт "Pointer Events" определяет события и связанные с ними интерфейсы для обработки ввода с таких указывающих устройств, как мышь, перо, сенсорный экран и т.д. То есть, абстрактный *указатель* создаёт унифицированную модель ввода, которая может представлять точку контакта пальца, пера/стилуса или мыши. Подробнее в MDN-статье События указателя.

Модель событий указателя может упростить обработку разных способов ввода, поскольку указатель представляет ввод с любого устройства. В дополнение к этому, типы событий указателя очень похожи на типы событий мыши (например, `pointerdown` `pointerup`), таким образом, код для обработки событий указателя полностью совпадает с кодом обработки ввода с помощью мыши.

Статус реализации событий указателя в браузерах относительно высок, поскольку Chrome, Firefox, IE11 и Edge имеют полные реализации.

Примеры
-------

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

* `События касаний`
* Реализация кастомных жестов
* Введение в события касаний в JavaScript
* Добавление поддержки сенсорных экранов на сайта (простой способ)

Демонстрация событий касания:

* Paint Program (by Rick Byers)
* Touch/pointer tests and demos (by Patrick H. Lauke)
Сообщество
----------

* Группа сообщества Событий касания
* Mail list
* W3C #touchevents IRC channel
Связанные темы и источники
--------------------------

* Стандарт "Pointer Events"