Table of Contents
In our web applications, you and I probably haven't done a whole lot of special work to handle touch-based input. Because touch is often treated as a mouse gesture, a lot of things just work for free. With that said, this doesn't mean we can't do a little extra to make our web content a bit more touch optimized. In this tutorial, the little extra is around detecting the direction of a touch swipe that we can then react to. We are going to do all of this using pure 100% grass-fed JavaScript. No 3rd party libraries will be necessary!
Onwards!
Before we look at the code and how everything works, let's start with an example. If you are on a touch-optimized device, swipe your fingers up/down/left/right in the yellow region below:
Swipe around in the yellow region above!
As you are swiping, you will see the direction of your swipe getting displayed. This is all made possible thanks to the following code:
myElement.addEventListener("touchstart", startTouch, false); myElement.addEventListener("touchmove", moveTouch, false); // Swipe Up / Down / Left / Right var initialX = null; var initialY = null; function startTouch(e) { initialX = e.touches[0].clientX; initialY = e.touches[0].clientY; }; function moveTouch(e) { if (initialX === null) { return; } if (initialY === null) { return; } var currentX = e.touches[0].clientX; var currentY = e.touches[0].clientY; var diffX = initialX - currentX; var diffY = initialY - currentY; if (Math.abs(diffX) > Math.abs(diffY)) { // sliding horizontally if (diffX > 0) { // swiped left console.log("swiped left"); } else { // swiped right console.log("swiped right"); } } else { // sliding vertically if (diffY > 0) { // swiped up console.log("swiped up"); } else { // swiped down console.log("swiped down"); } } initialX = null; initialY = null; e.preventDefault(); };
To use this code in your application, there are just two things you need to do:
That's all there is to detecting the direction of a swipe gesture and doing something special. If you are running into some issues, you can view the source for a standalone version here.
If all you wanted was the JavaScript to detect the direction of a swipe, then you are done. You don't have to read on. For the most part, if you are even remotely interested in understanding how this code works, I encourage you to at least skim through the explanation. The more you know about how this code works, the more easily you will be able to adapt it to your needs.
Before we look at individual lines of code, let's take a step back and talk about what our code is doing. First, we have our touch device:
When we are performing a swipe gesture, there are two stages. The first stage is the initial touch where our finger makes contact with the touch screen surface:
The second stage is where our fingers move across the screen from the point of the initial touch:
In this example, we can tell that the swipe was cleary in the down direction. How are we able to detect the direction of the swipe? We do a comparison! We know that our swipe begins at the position of the initial touch. The direction you swipe from there is relative to the initial position, so we can compare the positions to see what direction the swipe goes:
This seems like it logically makes sense, right? Well, our code is nothing more than this logic translated into JavaScript. Now that you know all of this, looking at our JavaScript will be much easier.
Let's start at the top:
myElement.addEventListener("touchstart", startTouch, false); myElement.addEventListener("touchmove", moveTouch, false);
There are two touch-specific events that we need to listen for. The first one is the touchstart event that is fired the moment your finger makes contact with a touch surface. The second one is the touchmove event that fires (and keeps firing) as your finger moves across your touch surface. Now, what exactly is a touch surface? It is any DOM element that we want to listen for these touch events on. In our snippet, we reference that element simply as myElement, but be sure to update it to whatever element is appropriate for your needs. When these touch events are overheard on myElement, the appropriate event handling function gets called. We'll look at these functions next.
The first (and easiest) of these functions we will look at is startTouch:
var initialX = null; var initialY = null; function startTouch(e) { initialX = e.touches[0].clientX; initialY = e.touches[0].clientY; }
The startTouch function gets called when the touchstart event is fired. All it does is store our initial touch position in the appropriately named initialX and initialY variables. That's it.
The real action happens in the moveTouch function that gets called each time the touchmove event is fired:
function moveTouch(e) { if (initialX === null) { return; } if (initialY === null) { return; } var currentX = e.touches[0].clientX; var currentY = e.touches[0].clientY; var diffX = initialX - currentX; var diffY = initialY - currentY; if (Math.abs(diffX) > Math.abs(diffY)) { // sliding horizontally if (diffX > 0) { // swiped left console.log("swiped left"); } else { // swiped right console.log("swiped right"); } } else { // sliding vertically if (diffY > 0) { // swiped up console.log("swiped up"); } else { // swiped down console.log("swiped down"); } } initialX = null; initialY = null; e.preventDefault(); }
We are going to skip the first few lines of this function, for we'll get back to them in a little bit. Instead, we will jump to right here:
var currentX = e.touches[0].clientX; var currentY = e.touches[0].clientY; var diffX = initialX - currentX; var diffY = initialY - currentY;
What we are doing is storing the current touch position in the currentX and currentY variables. Once we've done that, we compare this position with the position we stored earlier when we touched our screen initially. We do this comparison by doing a subtraction, and the diffX and diffY variables store the result of comparing our original position with our current position.
This result is what we can analyze to see what direction our swipe is going in. We looked at the four cases earlier, and those four cases are represented in JavaScript with the following code:
if (Math.abs(diffX) > Math.abs(diffY)) { // sliding horizontally if (diffX > 0) { // swiped left console.log("swiped left"); } else { // swiped right console.log("swiped right"); } } else { // sliding vertically if (diffY > 0) { // swiped up console.log("swiped up"); } else { // swiped down console.log("swiped down"); } }
This code is pretty boring since we know exactly what it does, so let's move on to the next few lines of code along with the code we skipped earlier:
function moveTouch(e) { if (initialX === null) { return; } if (initialY === null) { return; } . . . initialX = null; initialY = null; . . . }
What these lines of code do is a bit strange. Let's unstrange-ify it. One of the things about the touchmove event is that it fires and keeps firing while your finger is moving. For our simple swipe detection logic, we don't really need to see where our finger is at every point of the swipe. We just need to know where it is immediately after the initial touch has been made. This means we just need one position value from the moveTouch function running after the touchmove event is fired! The way we ensure that is by setting the value for initialX and initialY to null immediately after checking the current swipe direction in our:
initialX = null; initialY = null;
How does this help? At the very beginning when the touchmove event is called, we exit the moveTouch function if the value for initialX and initialY is null:
if (initialX === null) { return; } if (initialY === null) { return; }
The first time this code runs is immediately after the touchstart event is fired and the initialX and initialY values have been set. The second time is after our moveTouch function has run once and is about to run again. Thanks to the two lines we saw earlier, these values are set to null. When null, these if statements kick in and keep the rest of the code from executing thanks to the return statement.
The last thing we will look at is this seemingly innocent call to preventDefault:
e.preventDefault();
We know that preventDefault ensures the default browser behavior isn't allowed to happen for whatever event we are dealing with. With the touchmove event, what this means is that the default browser gestures such as navigating the page, pulling down to refresh, etc. don't happen when you are touching inside the myElement region.
By listening to the swipe event, you can provide a more touch optimized experience for things like menus, content carousels, and more. The reason you do this is to help your UI meet users' natural expectations. Because of how prevalent touch interactions have become with the devices we use, we tend to naturally expect certain gesture to just work. This is much easier in the native world where the built-in controls provide gesture recognition and the right default behavior. As we've seen, the web doesn't have that luxury yet. It is up to us to provide that level of familiarity and go beyond the default assumption that touch events should mimic mouse events.
Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!
:: Copyright KIRUPA 2024 //--