Многопальцевые жесты

Zepto.js — это лёгкая JavaScript-библиотека, предназначенная для работы с DOM и обработки событий, включая касания на мобильных устройствах. Одной из ключевых возможностей мобильного взаимодействия является работа с многопальцевыми жестами, такими как pinch (щипок), swipe (свайп), tap и drag с использованием нескольких касаний.


Основы работы с touch-событиями

Zepto реализует поддержку touch-событий через собственные абстракции поверх стандартных событий браузера:

  • touchstart — срабатывает при касании экрана.
  • touchmove — срабатывает при перемещении пальца по экрану.
  • touchend — срабатывает при отпускании пальца.
  • touchcancel — срабатывает, если событие касания прерывается системой.

Каждое touch-событие содержит массив touches, где хранятся все активные касания. Каждый элемент массива — это объект с координатами clientX и clientY, идентификатором identifier и другими параметрами.

$(element).on('touchstart', function(event) {
    var touches = event.touches;
    console.log('Количество пальцев:', touches.length);
    for (var i = 0; i < touches.length; i++) {
        console.log('Палец', i, 'X:', touches[i].clientX, 'Y:', touches[i].clientY);
    }
});

Определение жеста pinch (щипок)

Pinch используется для масштабирования элементов. Он требует как минимум два активных касания. Основная идея — вычисление расстояния между пальцами и отслеживание изменения этого расстояния:

var initialDistance = 0;

function getDistance(touches) {
    var dx = touches[0].clientX - touches[1].clientX;
    var dy = touches[0].clientY - touches[1].clientY;
    return Math.sqrt(dx*dx + dy*dy);
}

$(element).on('touchstart', function(e) {
    if (e.touches.length === 2) {
        initialDistance = getDistance(e.touches);
    }
});

$(element).on('touchmove', function(e) {
    if (e.touches.length === 2) {
        var currentDistance = getDistance(e.touches);
        var scale = currentDistance / initialDistance;
        $(element).css('transform', 'scale(' + scale + ')');
    }
});

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

  • e.touches.length проверяет количество пальцев.
  • getDistance вычисляет расстояние между двумя пальцами по теореме Пифагора.
  • Масштабирование происходит динамически, без задержек.

Обработка жестов swipe для нескольких пальцев

Swipe — это быстрое движение пальца в определённом направлении. В Zepto можно обработать многопальцевый свайп, отслеживая начальные и конечные координаты каждого касания:

$(element).on('touchstart', function(e) {
    var touches = e.touches;
    for (var i = 0; i < touches.length; i++) {
        $(this).data('startX' + touches[i].identifier, touches[i].clientX);
        $(this).data('startY' + touches[i].identifier, touches[i].clientY);
    }
});

$(element).on('touchend', function(e) {
    var changedTouches = e.changedTouches;
    for (var i = 0; i < changedTouches.length; i++) {
        var id = changedTouches[i].identifier;
        var startX = $(this).data('startX' + id);
        var startY = $(this).data('startY' + id);
        var deltaX = changedTouches[i].clientX - startX;
        var deltaY = changedTouches[i].clientY - startY;

        if (Math.abs(deltaX) > 50) {
            console.log('Swipe по X пальца', id, deltaX > 0 ? 'вправо' : 'влево');
        }
        if (Math.abs(deltaY) > 50) {
            console.log('Swipe по Y пальца', id, deltaY > 0 ? 'вниз' : 'вверх');
        }
    }
});

Особенности реализации:

  • Использование identifier позволяет отличать разные пальцы.
  • startX и startY сохраняются отдельно для каждого пальца.
  • Порог 50px обеспечивает фильтрацию случайных движений.

Многопальцевый drag

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

$(element).on('touchmove', function(e) {
    e.preventDefault(); // блокировка скролла страницы
    var touches = e.touches;
    for (var i = 0; i < touches.length; i++) {
        var id = touches[i].identifier;
        var startX = $(this).data('startX' + id) || touches[i].clientX;
        var startY = $(this).data('startY' + id) || touches[i].clientY;
        var deltaX = touches[i].clientX - startX;
        var deltaY = touches[i].clientY - startY;
        $(element).find('.finger-' + id).css({
            transform: 'translate(' + deltaX + 'px,' + deltaY + 'px)'
        });
    }
});

Важные моменты:

  • e.preventDefault() предотвращает нежелательный скролл при drag.
  • Каждому пальцу можно сопоставить отдельный элемент для визуализации.
  • Применение transform: translate() позволяет плавное перемещение без перерисовки layout.

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

Zepto расширяет стандартные события через $.fn.tap, $.fn.swipe и $.fn.pinch в некоторых модификациях и плагинах. Эти события упрощают работу с жестами:

$(element).on('pinch', function(e, scale) {
    $(this).css('transform', 'scale(' + scale + ')');
});

$(element).on('swipe', function(e, direction, fingers) {
    console.log('Свайп', direction, 'Пальцев:', fingers);
});

Преимущества:

  • Автоматическая обработка нескольких пальцев.
  • Удобные callback-функции с параметрами scale, direction, fingers.
  • Сокращение объёма кода по сравнению с ручной обработкой touchstart/touchmove/touchend.

Рекомендации по производительности

  1. Минимизировать изменения DOM во время touchmove. Использовать CSS-трансформации вместо изменения top/left.
  2. Ограничить количество активных касаний, если приложение не требует более двух пальцев.
  3. Использовать requestAnimationFrame для анимации drag или pinch, чтобы обеспечить плавность.
function animateTransform(element, transform) {
    requestAnimationFrame(function() {
        $(element).css('transform', transform);
    });
}

Заключение по функциональности

Zepto.js предоставляет гибкий инструмент для работы с многопальцевыми жестами, позволяя реализовать масштабирование, свайпы и drag с минимальным кодом. Благодаря использованию touchstart, touchmove и touchend в сочетании с идентификаторами пальцев и CSS-трансформациями достигается высокая производительность на мобильных устройствах.