Обнаружение пальца проведите по JavaScript на iPhone и Android

Как вы можете обнаружить, что пользователь провел пальцем в каком-то направлении по веб-странице с помощью JavaScript?

Мне было интересно, есть ли одно решение, которое будет работать на сайтах как на iPhone, так и на Android-телефоне.

Ответ 1

Простой ванильный пример кода JS:

document.addEventListener('touchstart', handleTouchStart, false);        
document.addEventListener('touchmove', handleTouchMove, false);

var xDown = null;                                                        
var yDown = null;

function getTouches(evt) {
  return evt.touches ||             // browser API
         evt.originalEvent.touches; // jQuery
}                                                     

function handleTouchStart(evt) {
    const firstTouch = getTouches(evt)[0];                                      
    xDown = firstTouch.clientX;                                      
    yDown = firstTouch.clientY;                                      
};                                                

function handleTouchMove(evt) {
    if ( ! xDown || ! yDown ) {
        return;
    }

    var xUp = evt.touches[0].clientX;                                    
    var yUp = evt.touches[0].clientY;

    var xDiff = xDown - xUp;
    var yDiff = yDown - yUp;

    if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
        if ( xDiff > 0 ) {
            /* left swipe */ 
        } else {
            /* right swipe */
        }                       
    } else {
        if ( yDiff > 0 ) {
            /* up swipe */ 
        } else { 
            /* down swipe */
        }                                                                 
    }
    /* reset values */
    xDown = null;
    yDown = null;                                             
};

Проверено в Android.

Ответ 3

Основываясь на ответе @givanse, вы можете сделать это с помощью classes:

class Swipe {
    constructor(element) {
        this.xDown = null;
        this.yDown = null;
        this.element = typeof(element) === 'string' ? document.querySelector(element) : element;

        this.element.addEventListener('touchstart', function(evt) {
            this.xDown = evt.touches[0].clientX;
            this.yDown = evt.touches[0].clientY;
        }.bind(this), false);

    }

    onLeft(callback) {
        this.onLeft = callback;

        return this;
    }

    onRight(callback) {
        this.onRight = callback;

        return this;
    }

    onUp(callback) {
        this.onUp = callback;

        return this;
    }

    onDown(callback) {
        this.onDown = callback;

        return this;
    }

    handleTouchMove(evt) {
        if ( ! this.xDown || ! this.yDown ) {
            return;
        }

        var xUp = evt.touches[0].clientX;
        var yUp = evt.touches[0].clientY;

        this.xDiff = this.xDown - xUp;
        this.yDiff = this.yDown - yUp;

        if ( Math.abs( this.xDiff ) > Math.abs( this.yDiff ) ) { // Most significant.
            if ( this.xDiff > 0 ) {
                this.onLeft();
            } else {
                this.onRight();
            }
        } else {
            if ( this.yDiff > 0 ) {
                this.onUp();
            } else {
                this.onDown();
            }
        }

        // Reset values.
        this.xDown = null;
        this.yDown = null;
    }

    run() {
        this.element.addEventListener('touchmove', function(evt) {
            this.handleTouchMove(evt).bind(this);
        }.bind(this), false);
    }
}

Вы можете использовать его следующим образом:

// Use class to get element by string.
var swiper = new Swipe('#my-element');
swiper.onLeft(function() { alert('You swiped left.') });
swiper.run();

// Get the element yourself.
var swiper = new Swipe(document.getElementById('#my-element'));
swiper.onLeft(function() { alert('You swiped left.') });
swiper.run();

// One-liner.
(new Swipe('#my-element')).onLeft(function() { alert('You swiped left.') }).run();

Ответ 5

что я использовал раньше, вам нужно обнаружить событие mousedown, записать его местоположение x, y (в зависимости от того, что имеет значение), затем обнаружить событие mouseup и вычесть два значения.

Ответ 6

jQuery Mobile также включает поддержку прокрутки: http://api.jquerymobile.com/swipe/

Пример

$("#divId").on("swipe", function(event) {
    alert("It a swipe!");
});

Ответ 7

Я нашел блестящий ответ @givanse самым надежным и совместимым в нескольких мобильных браузерах для регистрации действий салфетки.

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

event.touches не будет существовать, если используется jQuery и результат undefined и должен быть заменен на event.originalEvent.touches. Без jQuery, event.touches должно работать нормально.

Таким образом, решение становится,

document.addEventListener('touchstart', handleTouchStart, false);        
document.addEventListener('touchmove', handleTouchMove, false);

var xDown = null;                                                        
var yDown = null;                                                        

function handleTouchStart(evt) {                                         
    xDown = evt.originalEvent.touches[0].clientX;                                      
    yDown = evt.originalEvent.touches[0].clientY;                                      
};                                                

function handleTouchMove(evt) {
    if ( ! xDown || ! yDown ) {
        return;
    }

    var xUp = evt.originalEvent.touches[0].clientX;                                    
    var yUp = evt.originalEvent.touches[0].clientY;

    var xDiff = xDown - xUp;
    var yDiff = yDown - yUp;

    if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
        if ( xDiff > 0 ) {
            /* left swipe */ 
        } else {
            /* right swipe */
        }                       
    } else {
        if ( yDiff > 0 ) {
            /* up swipe */ 
        } else { 
            /* down swipe */
        }                                                                 
    }
    /* reset values */
    xDown = null;
    yDown = null;                                             
};

Протестировано:

  • Android: Chrome, UC Browser
  • iOS: Safari, Chrome, браузер UC

Ответ 8

Я объединил несколько ответов здесь в сценарий, который использует CustomEvent для запуска свипированных событий в DOM. Добавьте скрипт 0.7k swiped -events.min.js на свою страницу и прослушайте события swiped:

наотмашь левый

document.addEventListener('swiped-left', function(e) {
    console.log(e.target); // the element that was swiped
});

наотмашь правой

document.addEventListener('swiped-right', function(e) {
    console.log(e.target); // the element that was swiped
});

прокатывается вверх

document.addEventListener('swiped-up', function(e) {
    console.log(e.target); // the element that was swiped
});

стащили вниз

document.addEventListener('swiped-down', function(e) {
    console.log(e.target); // the element that was swiped
});

Вы также можете прикрепить непосредственно к элементу:

document.getElementById('myBox').addEventListener('swiped-down', function(e) {
    console.log(e.target); // the element that was swiped
});

Необязательный конфиг

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

<div data-swipe-threshold="10"
     data-swipe-timeout="1000"
     data-swipe-ignore="false">
        Swiper, get swiping!
</div>

Исходный код доступен на Github

Ответ 9

Я переупаковал TouchWipe как короткий плагин jquery: detectSwipe

Ответ 10

Некоторая мода ответа на ответ (не могу комментировать...), чтобы иметь дело с короткими стрелками

document.addEventListener('touchstart', handleTouchStart, false);        
document.addEventListener('touchmove', handleTouchMove, false);
var xDown = null;                                                        
var yDown = null;                                                        
function handleTouchStart(evt) {                                         
    xDown = evt.touches[0].clientX;                                      
    yDown = evt.touches[0].clientY;                                      
};                                                
function handleTouchMove(evt) {
    if ( ! xDown || ! yDown ) {
        return;
    }

    var xUp = evt.touches[0].clientX;                                    
    var yUp = evt.touches[0].clientY;

    var xDiff = xDown - xUp;
    var yDiff = yDown - yUp;
    if(Math.abs( xDiff )+Math.abs( yDiff )>150){ //to deal with to short swipes

    if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
        if ( xDiff > 0 ) {/* left swipe */ 
            alert('left!');
        } else {/* right swipe */
            alert('right!');
        }                       
    } else {
        if ( yDiff > 0 ) {/* up swipe */
            alert('Up!'); 
        } else { /* down swipe */
            alert('Down!');
        }                                                                 
    }
    /* reset values */
    xDown = null;
    yDown = null;
    }
};

Ответ 11

trashold, тайм-аут, swipeBlockElems add.

document.addEventListener('touchstart', handleTouchStart, false);
document.addEventListener('touchmove', handleTouchMove, false);
document.addEventListener('touchend', handleTouchEnd, false);     

const SWIPE_BLOCK_ELEMS = [
  'swipBlock',
  'handle',
  'drag-ruble'
]

let xDown = null;
let yDown = null; 
let xDiff = null;
let yDiff = null;
let timeDown = null;
const  TIME_TRASHOLD = 200;
const  DIFF_TRASHOLD = 130;

function handleTouchEnd() {

let timeDiff = Date.now() - timeDown; 
if (Math.abs(xDiff) > Math.abs(yDiff)) { /*most significant*/
  if (Math.abs(xDiff) > DIFF_TRASHOLD && timeDiff < TIME_TRASHOLD) {
    if (xDiff > 0) {
      // console.log(xDiff, TIME_TRASHOLD, DIFF_TRASHOLD)
      SWIPE_LEFT(LEFT) /* left swipe */
    } else {
      // console.log(xDiff)
      SWIPE_RIGHT(RIGHT) /* right swipe */
    }
  } else {
    console.log('swipeX trashhold')
  }
} else {
  if (Math.abs(yDiff) > DIFF_TRASHOLD && timeDiff < TIME_TRASHOLD) {
    if (yDiff > 0) {
      /* up swipe */
    } else {
      /* down swipe */
    }
  } else {
    console.log('swipeY trashhold')
  }
 }
 /* reset values */
 xDown = null;
 yDown = null;
 timeDown = null; 
}
function containsClassName (evntarget , classArr) {
 for (var i = classArr.length - 1; i >= 0; i--) {
   if( evntarget.classList.contains(classArr[i]) ) {
      return true;
    }
  }
}
function handleTouchStart(evt) {
  let touchStartTarget = evt.target;
  if( containsClassName(touchStartTarget, SWIPE_BLOCK_ELEMS) ) {
    return;
  }
  timeDown = Date.now()
  xDown = evt.touches[0].clientX;
  yDown = evt.touches[0].clientY;
  xDiff = 0;
  yDiff = 0;

}

function handleTouchMove(evt) {
  if (!xDown || !yDown) {
    return;
  }

  var xUp = evt.touches[0].clientX;
  var yUp = evt.touches[0].clientY;


  xDiff = xDown - xUp;
  yDiff = yDown - yUp;
}

Ответ 12

Если кто-то пытается использовать jQuery Mobile на Android и имеет проблемы с обнаружением прокрутки JQM

(у меня были некоторые на Xperia Z1, Galaxy S3, Nexus 4 и некоторые телефоны Wiko), это может быть полезно:

 //Fix swipe gesture on android
    if(android){ //Your own device detection here
        $.event.special.swipe.verticalDistanceThreshold = 500
        $.event.special.swipe.horizontalDistanceThreshold = 10
    }

Прокрутка на андроиде не была обнаружена, если она не была очень длинной, точной и быстрой салфетки.

С этими двумя строками он работает правильно

Ответ 13

У меня были проблемы с обработчиком touchhend, который стрелял непрерывно, когда пользователь тащил палец. Я не знаю, что из-за того, что я делаю неправильно или нет, но я переработал это, чтобы накапливать движения с помощью touchmove и прикосновение фактически срабатывает обратный вызов.

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

И порог, когда короткий салфетка не срабатывает. Прикоснитесь к ноль счетчиков каждый раз.

Вы можете изменить target_node на лету. Включить при создании необязательно.

/** Usage: */
touchevent = new Modules.TouchEventClass(callback, target_node);
touchevent.enable();
touchevent.disable();

/** 
*
*   Touch event module
*
*   @param method   set_target_mode
*   @param method   __touchstart
*   @param method   __touchmove
*   @param method   __touchend
*   @param method   enable
*   @param method   disable
*   @param function callback
*   @param node     target_node
*/
Modules.TouchEventClass = class {

    constructor(callback, target_node, enable=false) {

        /** callback function */
        this.callback = callback;

        this.xdown = null;
        this.ydown = null;
        this.enabled = false;
        this.target_node = null;

        /** move point counts [left, right, up, down] */
        this.counts = [];

        this.set_target_node(target_node);

        /** Enable on creation */
        if (enable === true) {
            this.enable();
        }

    }

    /** 
    *   Set or reset target node
    *
    *   @param string/node target_node
    *   @param string      enable (optional)
    */
    set_target_node(target_node, enable=false) {

        /** check if we're resetting target_node */
        if (this.target_node !== null) {

            /** remove old listener */
           this.disable();
        }

        /** Support string id of node */
        if (target_node.nodeName === undefined) {
            target_node = document.getElementById(target_node);
        }

        this.target_node = target_node;

        if (enable === true) {
            this.enable();
        }
    }

    /** enable listener */
    enable() {
        this.enabled = true;
        this.target_node.addEventListener("touchstart", this.__touchstart.bind(this));
        this.target_node.addEventListener("touchmove", this.__touchmove.bind(this));
        this.target_node.addEventListener("touchend", this.__touchend.bind(this));
    }

    /** disable listener */
    disable() {
        this.enabled = false;
        this.target_node.removeEventListener("touchstart", this.__touchstart);
        this.target_node.removeEventListener("touchmove", this.__touchmove);
        this.target_node.removeEventListener("touchend", this.__touchend);
    }

    /** Touchstart */
    __touchstart(event) {
        event.stopPropagation();
        this.xdown = event.touches[0].clientX;
        this.ydown = event.touches[0].clientY;

        /** reset count of moves in each direction, [left, right, up, down] */
        this.counts = [0, 0, 0, 0];
    }

    /** Touchend */
    __touchend(event) {
        let max_moves = Math.max(...this.counts);
        if (max_moves > 500) { // set this threshold appropriately
            /** swipe happened */
            let index = this.counts.indexOf(max_moves);
            if (index == 0) {
                this.callback("left");
            } else if (index == 1) {
                this.callback("right");
            } else if (index == 2) {
                this.callback("up");
            } else {
                this.callback("down");
            }
        }
    }

    /** Touchmove */
    __touchmove(event) {

        event.stopPropagation();
        if (! this.xdown || ! this.ydown) {
            return;
        }

        let xup = event.touches[0].clientX;
        let yup = event.touches[0].clientY;

        let xdiff = this.xdown - xup;
        let ydiff = this.ydown - yup;

        /** Check x or y has greater distance */
        if (Math.abs(xdiff) > Math.abs(ydiff)) {
            if (xdiff > 0) {
                this.counts[0] += Math.abs(xdiff);
            } else {
                this.counts[1] += Math.abs(xdiff);
            }
        } else {
            if (ydiff > 0) {
                this.counts[2] += Math.abs(ydiff);
            } else {
                this.counts[3] += Math.abs(ydiff);
            }
        }
    }
}

Ответ 14

Используется два:

jQuery mobile: работают в большинстве случаев, и особенно когда вы разрабатываете приложение, которое использует другой плагин jQuery, тогда лучше использовать для этого jQuery для мобильных устройств. Посетите его здесь: https://www.w3schools.com/jquerymobile/jquerymobile_events_touch.asp

Hammer Time! - одна из лучших, легких и быстрых javascript-библиотек. Посетите его здесь: https://hammerjs.github.io/

Ответ 15

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

Это ~ 450 байт после сжатия gzip, минификации, babel и т.д.

Я написал приведенный ниже класс на основе других ответов, он использует процентное смещение вместо пикселей и шаблон диспетчера событий, чтобы зацеплять/отцеплять вещи.

Используйте это так:

const dispatcher = new SwipeEventDispatcher(myElement);
dispatcher.on('SWIPE_RIGHT', () => { console.log('I swiped right!') })

export class SwipeEventDispatcher {
	constructor(element, options = {}) {
		this.evtMap = {
			SWIPE_LEFT: [],
			SWIPE_UP: [],
			SWIPE_DOWN: [],
			SWIPE_RIGHT: []
		};

		this.xDown = null;
		this.yDown = null;
		this.element = element;
		this.options = Object.assign({ triggerPercent: 0.3 }, options);

		element.addEventListener('touchstart', evt => this.handleTouchStart(evt), false);
		element.addEventListener('touchend', evt => this.handleTouchEnd(evt), false);
	}

	on(evt, cb) {
		this.evtMap[evt].push(cb);
	}

	off(evt, lcb) {
		this.evtMap[evt] = this.evtMap[evt].filter(cb => cb !== lcb);
	}

	trigger(evt, data) {
		this.evtMap[evt].map(handler => handler(data));
	}

	handleTouchStart(evt) {
		this.xDown = evt.touches[0].clientX;
		this.yDown = evt.touches[0].clientY;
	}

	handleTouchEnd(evt) {
		const deltaX = evt.changedTouches[0].clientX - this.xDown;
		const deltaY = evt.changedTouches[0].clientY - this.yDown;
		const distMoved = Math.abs(Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY);
		const activePct = distMoved / this.element.offsetWidth;

		if (activePct > this.options.triggerPercent) {
			if (Math.abs(deltaX) > Math.abs(deltaY)) {
				deltaX < 0 ? this.trigger('SWIPE_LEFT') : this.trigger('SWIPE_RIGHT');
			} else {
				deltaY > 0 ? this.trigger('SWIPE_UP') : this.trigger('SWIPE_DOWN');
			}
		}
	}
}

export default SwipeEventDispatcher;

Ответ 16

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

export default class Swipe {
    constructor(options) {
        this.xDown = null;
        this.yDown = null;

        this.options = options;

        this.handleTouchStart = this.handleTouchStart.bind(this);
        this.handleTouchMove = this.handleTouchMove.bind(this);

        document.addEventListener('touchstart', this.handleTouchStart, false);
        document.addEventListener('touchmove', this.handleTouchMove, false);

    }

    onLeft() {
        this.options.onLeft();
    }

    onRight() {
        this.options.onRight();
    }

    onUp() {
        this.options.onUp();
    }

    onDown() {
        this.options.onDown();
    }

    static getTouches(evt) {
        return evt.touches      // browser API

    }

    handleTouchStart(evt) {
        const firstTouch = Swipe.getTouches(evt)[0];
        this.xDown = firstTouch.clientX;
        this.yDown = firstTouch.clientY;
    }

    handleTouchMove(evt) {
        if ( ! this.xDown || ! this.yDown ) {
            return;
        }

        let xUp = evt.touches[0].clientX;
        let yUp = evt.touches[0].clientY;

        let xDiff = this.xDown - xUp;
        let yDiff = this.yDown - yUp;


        if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
            if ( xDiff > 0 && this.options.onLeft) {
                /* left swipe */
                this.onLeft();
            } else if (this.options.onRight) {
                /* right swipe */
                this.onRight();
            }
        } else {
            if ( yDiff > 0 && this.options.onUp) {
                /* up swipe */
                this.onUp();
            } else if (this.options.onDown){
                /* down swipe */
                this.onDown();
            }
        }

        /* reset values */
        this.xDown = null;
        this.yDown = null;
    }
}

После этого можете использовать его следующим образом:

let swiper = new Swipe({
                    onLeft() {
                        console.log('You swiped left.');
                    }
});

Это помогает избежать ошибок консоли, когда вы хотите вызывать только метод скажем "onLeft".

Ответ 17

Пример использования со смещением.

// at least 100 px are a swipe
// you can use the value relative to screen size: window.innerWidth * .1
const offset = 100;
let xDown, yDown

window.addEventListener('touchstart', e => {
  const firstTouch = getTouch(e);

  xDown = firstTouch.clientX;
  yDown = firstTouch.clientY;
});

window.addEventListener('touchend', e => {
  if (!xDown || !yDown) {
    return;
  }

  const {
    clientX: xUp,
    clientY: yUp
  } = getTouch(e);
  const xDiff = xDown - xUp;
  const yDiff = yDown - yUp;
  const xDiffAbs = Math.abs(xDown - xUp);
  const yDiffAbs = Math.abs(yDown - yUp);

  // at least <offset> are a swipe
  if (Math.max(xDiffAbs, yDiffAbs) < offset ) {
    return;
  }

  if (xDiffAbs > yDiffAbs) {
    if ( xDiff > 0 ) {
      console.log('left');
    } else {
      console.log('right');
    }
  } else {
    if ( yDiff > 0 ) {
      console.log('up');
    } else {
      console.log('down');
    }
  }
});

function getTouch (e) {
  return e.changedTouches[0]
}

Ответ 18

Простой ванильный пример JS для горизонтального смахивания:

let touchstartX = 0
let touchendX = 0

const slider = document.getElementById('slider')

function handleGesure() {
  if (touchendX < touchstartX) alert('swiped left!')
  if (touchendX > touchstartX) alert('swiped right!')
}

slider.addEventListener('touchstart', e => {
  touchstartX = e.changedTouches[0].screenX
})

slider.addEventListener('touchend', e => {
  touchendX = e.changedTouches[0].screenX
  handleGesure()
})

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

Ответ 19

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

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

См:

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

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

Не существует единого точного метода обнаружения удара или броска, хотя практически все обычно следуют основному принципу обнаружения движения через элемент с порогом расстояния и скорости или скорости. Вы могли бы просто сказать, что если в течение заданного времени происходит перемещение на 65% размера экрана в заданном направлении, то это будет скачком. Где именно вы рисуете линию и как вы ее рассчитываете, зависит от вас.

Кто-то может также взглянуть на него с точки зрения импульса в направлении и как далеко от экрана он был сдвинут, когда элемент отпущен. Это становится понятнее при использовании липких движений, когда элемент можно перетаскивать, а затем при отпускании он либо отскакивает назад, либо отлетает с экрана, как если бы резинка сломалась.

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

Android был бы очевидным выбором, хотя имеет противоположную проблему, он слишком сложный.

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

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

Лучший вариант - не делать это самостоятельно. Уже есть большое количество библиотек JavaScript для обнаружения простых жестов.

Ответ 20

Я хотел обнаруживать только левое и правое пролистывание, но вызывать действие только после окончания события касания, поэтому я слегка изменил ответ @givanse great для этого.

Зачем это делать? Если, например, во время считывания пользователь замечает, что он, наконец, не хочет его проводить, он может переместить палец в исходное положение (это делает очень популярное приложение для знакомств на телефоне;)), а затем событие "Проведите вправо" отменяется.

Поэтому, чтобы избежать события "проведите вправо" просто потому, что разница по горизонтали составляет 3 пикселя, я добавил пороговое значение, при котором событие отбрасывается: для того, чтобы событие "проходило вправо", пользователь должен провести по крайней мере 1/3 ширины браузера (конечно, вы можете изменить это).

Все эти мелкие детали улучшают пользовательский опыт. Вот код (Vanilla JS):

var xDown = null, yDown = null, xUp = null, yUp = null;
document.addEventListener('touchstart', touchstart, false);        
document.addEventListener('touchmove', touchmove, false);
document.addEventListener('touchend', touchend, false);
function touchstart(evt) { const firstTouch = (evt.touches || evt.originalEvent.touches)[0]; xDown = firstTouch.clientX; yDown = firstTouch.clientY; }
function touchmove(evt) { if (!xDown || !yDown ) return; xUp = evt.touches[0].clientX; yUp = evt.touches[0].clientY; }
function touchend(evt) { 
    var xDiff = xUp - xDown, yDiff = yUp - yDown;
    if ((Math.abs(xDiff) > Math.abs(yDiff)) && (Math.abs(xDiff) > 0.33 * document.body.clientWidth)) { 
        if (xDiff < 0) 
            document.getElementById('leftnav').click();
        else
            document.getElementById('rightnav').click();
    } 
    xDown = null, yDown = null;
}