Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A simple swipe detection on vanilla js
var touchstartX = 0;
var touchstartY = 0;
var touchendX = 0;
var touchendY = 0;
var gesuredZone = document.getElementById('gesuredZone');
gesuredZone.addEventListener('touchstart', function(event) {
touchstartX = event.screenX;
touchstartY = event.screenY;
}, false);
gesuredZone.addEventListener('touchend', function(event) {
touchendX = event.screenX;
touchendY = event.screenY;
handleGesure();
}, false);
function handleGesure() {
var swiped = 'swiped: ';
if (touchendX < touchstartX) {
alert(swiped + 'left!');
}
if (touchendX > touchstartX) {
alert(swiped + 'right!');
}
if (touchendY < touchstartY) {
alert(swiped + 'down!');
}
if (touchendY > touchstartY) {
alert(swiped + 'left!');
}
if (touchendY == touchstartY) {
alert('tap!');
}
}
@vokeio

This comment has been minimized.

Copy link

commented Oct 31, 2016

Hello,

This api event.screen does not work any more.

Change to e.changedTouches[0].screenY; and e.changedTouches[0].screenX;

Also line 31 should say up.

@angeenes

This comment has been minimized.

Copy link

commented Nov 15, 2016

Actually, in this script, it should be : event.changedTouches[0].screenY; and event.changedTouches[0].screenX;

@prochac

This comment has been minimized.

Copy link

commented Dec 26, 2016

THX
with some errors, but still better than jQuery

@cclifford3

This comment has been minimized.

Copy link

commented Jun 14, 2017

@SleepWalker also line 31 should be the 'up' direction

@DZuz14

This comment has been minimized.

Copy link

commented Aug 20, 2017

Useless.

@alextrastero

This comment has been minimized.

Copy link

commented Nov 12, 2017

Worked for me thanks! :)

@mocon

This comment has been minimized.

Copy link

commented Dec 5, 2017

Thanks! I made some small tweaks to this, based on the comments above:

let touchstartX = 0;
let touchstartY = 0;
let touchendX = 0;
let touchendY = 0;

const gestureZone = document.getElementById('gestureZone');

gestureZone.addEventListener('touchstart', function(event) {
    touchstartX = event.changedTouches[0].screenX;
    touchstartY = event.changedTouches[0].screenY;
}, false);

gestureZone.addEventListener('touchend', function(event) {
    touchendX = event.changedTouches[0].screenX;
    touchendY = event.changedTouches[0].screenY;
    handleGesture();
}, false); 

function handleGesture() {
    if (touchendX <= touchstartX) {
        console.log('Swiped left');
    }
    
    if (touchendX >= touchstartX) {
        console.log('Swiped right');
    }
    
    if (touchendY <= touchstartY) {
        console.log('Swiped up');
    }
    
    if (touchendY >= touchstartY) {
        console.log('Swiped down');
    }
    
    if (touchendY === touchstartY) {
        console.log('Tap');
    }
}
@Demven

This comment has been minimized.

Copy link

commented Dec 7, 2017

Thank you, it was very helpful!

@AmicoJoules

This comment has been minimized.

Copy link

commented Dec 18, 2017

Thx!

@peterver

This comment has been minimized.

Copy link

commented Jan 29, 2018

I have a different approach for the handleGesture ( does not include the tap though ) that works with the dimensions of the element that the events are occuring on ( because let's face it, users do not swipe in a straight line most of the time, and we should account for this )

const { width, height } = dom_el.getBoundingClientRect();

const ratio_horizontal = (end.screenX - start.screenX) / width;
const ratio_vertical = (end.screenY - start.screenY) / height;

if (ratio_horizontal > ratio_vertical && ratio_horizontal > 0.25) {
    return console.log('swipe-right');
}
if (ratio_vertical > ratio_horizontal && ratio_vertical > 0.25) {
    return console.log('swipe-down');
}
if (ratio_horizontal < ratio_vertical && ratio_horizontal < -0.25) {
    return console.log('swipe-left');
}
if (ratio_vertical < ratio_horizontal && ratio_vertical < -0.25) {
    return console.log('swipe-up');
}

return false;
@IanRr

This comment has been minimized.

Copy link

commented Feb 8, 2018

@mocon heads up on your revisions if you haven't already noticed

Seems to me that including using touchendX <= touchstartX etc instead of touchendX < touchstartX etc in the handleGesture code means that any "tap" will also register every swipe event

@stephenjude

This comment has been minimized.

Copy link

commented Apr 14, 2018

@IanRr thanks for that correction. @mocon thanks for tweak
It works fine now

let touchstartX = 0;
let touchstartY = 0;
let touchendX = 0;
let touchendY = 0;

const gestureZone = document.getElementById('modalContent');

gestureZone.addEventListener('touchstart', function(event) {
    touchstartX = event.changedTouches[0].screenX;
    touchstartY = event.changedTouches[0].screenY;
}, false);

gestureZone.addEventListener('touchend', function(event) {
    touchendX = event.changedTouches[0].screenX;
    touchendY = event.changedTouches[0].screenY;
    handleGesture();
}, false); 

function handleGesture() {
    if (touchendX < touchstartX) {
        console.log('Swiped left');
    }
    
    if (touchendX > touchstartX) {
        console.log('Swiped right');
    }
    
    if (touchendY < touchstartY) {
        console.log('Swiped up');
    }
    
    if (touchendY > touchstartY) {
       console.log('Swiped down');
    }
    
    if (touchendY === touchstartY) {
       console.log('Tap');
    }
}
@c7x43t

This comment has been minimized.

Copy link

commented May 3, 2018

Small modification of @stephenjude using angles (45° for each of the 8 directions) to determine the direction and a treshold of 1px or 1% of page width:

let pageWidth = window.innerWidth || document.body.clientWidth;
let treshold = Math.max(1,Math.floor(0.01 * (pageWidth)));
let touchstartX = 0;
let touchstartY = 0;
let touchendX = 0;
let touchendY = 0;

const limit = Math.tan(45 * 1.5 / 180 * Math.PI);
const gestureZone = document.getElementById('modalContent');

gestureZone.addEventListener('touchstart', function(event) {
    touchstartX = event.changedTouches[0].screenX;
    touchstartY = event.changedTouches[0].screenY;
}, false);

gestureZone.addEventListener('touchend', function(event) {
    touchendX = event.changedTouches[0].screenX;
    touchendY = event.changedTouches[0].screenY;
    handleGesture(event);
}, false);

function handleGesture(e) {
    let x = touchendX - touchstartX;
    let y = touchendY - touchstartY;
    let xy = Math.abs(x / y);
    let yx = Math.abs(y / x);
    if (Math.abs(x) > treshold || Math.abs(y) > treshold) {
        if (yx <= limit) {
            if (x < 0) {
                console.log("left");
            } else {
                console.log("right");
            }
        }
        if (xy <= limit) {
            if (y < 0) {
                console.log("top");
            } else {
                console.log("bottom");
            }
        }
    } else {
        console.log("tap");
    }
}
@EskimoLemon

This comment has been minimized.

Copy link

commented Jun 6, 2018

Like !

@uxitten

This comment has been minimized.

Copy link

commented Aug 27, 2018

i add this script to npm

npm link:
https://www.npmjs.com/package/xwiper

github link:
https://github.com/uxitten/xwiper

@adsoft-solutions

This comment has been minimized.

Copy link

commented Sep 5, 2018

Hello , actually won't work on some Android Chrome newer versions... If someone could add browser interogation for Pointer Events and a solution for the it , would be our hero !

@alexPalita

This comment has been minimized.

Copy link

commented Sep 6, 2018

Idk... I tried to modify uxitten approach with Pointer Events ... If someone could write a more elegant version of this with pinch and multiple taps would be awesome ...

class Xwiper {
    constructor(element) {
        this.element = null;
        this.touchStartX = 0;
        this.touchStartY = 0;
        this.touchEndX = 0;
        this.touchEndY = 0;
        this.touchMovedX = 0;
        this.touchMovedY = 0;
        this.sensitive = 5;
        this.onSwipeLeftAgent = null;
        this.onSwipeRightAgent = null;
        this.onSwipeUpAgent = null;
        this.onSwipeDownAgent = null;
        this.onTapAgent = null;
        this.onTouchStart = this.onTouchStart.bind(this);
        this.onTouchEnd = this.onTouchEnd.bind(this);
        this.onPointerStart = this.onPointerStart.bind(this);
        this.onPointerMoved = this.onPointerMoved.bind(this);
        this.onPointerEnd = this.onPointerEnd.bind(this);
        this.onSwipeLeft = this.onSwipeLeft.bind(this);
        this.onSwipeRight = this.onSwipeRight.bind(this);
        this.onSwipeUp = this.onSwipeUp.bind(this);
        this.onSwipeDown = this.onSwipeDown.bind(this);
        this.onTap = this.onTap.bind(this);
        this.destroy = this.destroy.bind(this);
        this.handleGesture = this.handleGesture.bind(this);

        this.element = document.querySelector(element);
		if (window.PointerEvent) {
			this.element.addEventListener( 'pointerdown', this.onPointerStart,false);

			this.element.addEventListener( 'pointermove', this.onPointerMoved,false);
				
			this.element.addEventListener( 'pointercancel', this.onPointerEnd,false);
		} else {
			this.element.addEventListener('touchstart', this.onTouchStart ,false);
			this.element.addEventListener('touchend', this.onTouchEnd, false);	
		}
    }

    onTouchStart(event) {
        this.touchStartX = event.changedTouches[0].screenX;
        this.touchStartY = event.changedTouches[0].screenY;
    }

    onTouchEnd(event) {
        this.touchEndX = event.changedTouches[0].screenX;
        this.touchEndY = event.changedTouches[0].screenY;
        this.handleGesture();
    }

    onPointerStart(event) {
		switch ( event.pointerType ) {
			case 'mouse':
				//add code
			break;

			case 'touch':
				this.touchStartX = event.screenX;
				this.touchStartY = event.screenY;
			break;
			case 'pen':
				//add code
			break;
			default:
				//add code
			break;
			}
    }

    onPointerMoved(event) {
		switch ( event.pointerType ) {
			case 'mouse':
				//add code
			break;
			case 'touch':
				this.touchMovedX = event.screenX;
				this.touchMovedY = event.screenY;
			break;
			case 'pen':
				//add code
			break;
			default:
				//add code
			break;
		}
    }
    onPointerEnd(event) {
		switch ( event.pointerType ) {
			case 'mouse':
				//add code
			break;

			case 'touch':
				this.touchEndX = this.touchMovedX;
				this.touchEndY = this.touchMovedY;
			break;

			case 'pen':
				//add code
			break;

			default:
				//add code
			break;
		}
        this.handleGesture();
    }

    onSwipeLeft(func) {
        this.onSwipeLeftAgent = func;
    }
    onSwipeRight(func) {
        this.onSwipeRightAgent = func;
    }
    onSwipeUp(func) {
        this.onSwipeUpAgent = func;
    }
    onSwipeDown(func) {
        this.onSwipeDownAgent = func;
    }
    onTap(func) {
        this.onTapAgent = func;
    }

    destroy() {
        this.element.removeEventListener('touchstart', this.onTouchStart);
        this.element.removeEventListener('touchend', this.onTouchEnd);
        this.element.removeEventListener('pointerstart', this.onTouchStart);
        this.element.removeEventListener('pointermove', this.onTouchMove);
        this.element.removeEventListener('touchover', this.onTouchEnd);
    }

	handleGesture() {
        /**
         * swiped left
         */
        if (this.touchEndX + this.sensitive < this.touchStartX) {
            this.onSwipeLeftAgent &&
                this.onSwipeLeftAgent();
            return 'swiped left';
        }

        /**
         * swiped right
         */
        if (this.touchEndX - this.sensitive > this.touchStartX) {
            this.onSwipeRightAgent &&
                this.onSwipeRightAgent();
            return 'swiped right';
        }

        /**
         * swiped up
         */
        if (this.touchEndY + this.sensitive < this.touchStartY) {
            this.onSwipeUpAgent &&
                this.onSwipeUpAgent();
            return 'swiped up';
        }

        /**
         * swiped down
         */
        if (this.touchEndY - this.sensitive > this.touchStartY) {
            this.onSwipeDownAgent &&
                this.onSwipeDownAgent();
            return 'swiped down';
        }

        /**
         * tap
         */
        if (this.touchEndY === this.touchStartY) {
            this.onTapAgent &&
                this.onTapAgent();
            return 'tap';
        }
    }
}
@hperrin

This comment has been minimized.

Copy link

commented Sep 7, 2018

I took a shot at improving this too. I added multiple listeners support, long press, mouse support, velocity threshold, and customization. It's on NPM and GitHub:

https://www.npmjs.com/package/tinygesture
https://github.com/sciactive/tinygesture

Here's a demo:
https://sciactive.github.io/tinygesture/

Thank you @SleepWalker, @uxitten, @c7x43t.

@javierlog08

This comment has been minimized.

Copy link

commented Jan 6, 2019

Thank you so much.
Pretty usefull !~

@tlacaelelrl

This comment has been minimized.

Copy link

commented Apr 25, 2019

Here I leave you some code I use, some of it was initially based on the code listed here, then modified to adjust to my needs and new events.

TlakDev.EventHandler.prototype._defaults = {
	touch: {
		x: 0,
		y: 0
	},
	touchEnd: {
		x: 0,
		y: 0
	}
}
TlakDev.EventHandler.prototype.sendTouchEvent = function (event, element) {
	let t = this;
	switch(true){
		case ((Math.abs(t.touch.x) - Math.abs(t.touchEnd.x)) === 0) && ((Math.abs(t.touch.y) - Math.abs(t.touchEnd.y)) === 0):
			event.direction = "tap";
		break;
		case Math.abs(t.touch.x - t.touchEnd.x) > Math.abs(t.touch.y - t.touchEnd.y):
			/*left/right*/
			if(t.touch.x > t.touchEnd.x){
				event.direction = "left";
			} else {
				event.direction = "right";
			}
		break;
		default:
			/*up/down*/
			if(t.touch.y < t.touchEnd.y){
				event.direction = "down";
			} else {
				event.direction = "up";
			}
		break;
	}
	switch(true){
		case ((Math.abs(t.touch.x) - Math.abs(t.touchEnd.x)) === 0) && ((Math.abs(t.touch.y) - Math.abs(t.touchEnd.y)) === 0):
			event.directionPrecision = "tap";
		break;
		case t.touch.x > t.touchEnd.x:
			/*left*/
			if(t.touch.y > t.touchEnd.y){
				event.directionPrecision = "upLeft";
			} else {
				event.directionPrecision = "downLeft";
			}
		break;
		default:
			/*right*/
			if(t.touch.y > t.touchEnd.y){
				event.directionPrecision = "upRight";
			} else {
				event.directionPrecision = "downRight";
			}
		break;
	}
	/*
	 * Do whatever you need with the event/element
	 * The event contains 2 properties
	 * 1. direction  = tap|left|right|up|down
	 * 2. directionPrecision tap|upRight|upLeft|downRight|downLeft
	*/
}
TlakDev.EventHandler.prototype.setTouch = function (event) {
	let e = {};
	if(event.screenY){
		e.x = event.screenX;
		e.y = event.screenY;
	} else if(typeof event.touches !== "undefined" && event.touches.length > 0){
		e.x = event.touches[0].pageX;
		e.y = event.touches[0].pageY;
	} else if(typeof event.changedTouches !== "undefined" && event.changedTouches.length > 0) {
		e.x = event.changedTouches[0].pageX;
		e.y = event.changedTouches[0].pageY;
	} else {
		e.x = 0;
		e.y = 0;
	}
	return e;
}
/*
@param nodes is an array of javascript elements to which apply the events
*/
TlakDev.EventHandler.prototype.handleSwipes = function (nodes) {
	let t = this;
	nodes.forEach(function(element){
		element.addEventListener("touchstart", function (event) {
			let e = t.setTouch(event);
			t.touch = e;
		});
		element.addEventListener("touchend", function (event) {
			let e = t.setTouch(event);
			t.touchEnd = e;
			t.sendTouchEvent(event, element);
		});
	});
}
@evrenakar

This comment has been minimized.

Copy link

commented May 8, 2019

Function that only listen the y down event.

`
var swipe = document.getElementById('swipe');

  var touchstartY = 0;
  var touchendY = 0;

  swipe.addEventListener('touchstart', function(event) {
    touchstartY = event.changedTouches[0].screenY;
  }, false);

  swipe.addEventListener('touchend', function(event) {
    touchendY = event.changedTouches[0].screenY;
      handleSwipe();
  }, false); 

  function handleSwipe() {
      var swiped = 'swiped: ';
      if (touchendY > touchstartY) {
          alert(swiped + 'down!');
      }
  }

`

@karol2001965

This comment has been minimized.

Copy link

commented Jul 30, 2019

Thanks a lot ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.