Introduction
Amongst the most difficult concepts involved in building a slider powered by JavaScript is giving touch interaction to it i.e. enabling it to respond to swipe gestures.
Given the browser compatibility tables for touch events, the ease of understanding their functionality, coupled with ideas such as detecting the swipe speed and swipe direction, it turns out that giving touch interaction to a slider can be a daunting task, at least for beginners.
Experienced programmers out there with solid CSS and JavaScript skills, especially in JavaScript Touch Events, however, might not have that of a difficult time in implementing touch-interactive sliders.
In this chapter, we aim to figure out how to implement a touch-interactive slider by listening to touch events on our slider and determining whether a given gesture is a swipe, whereby we perform a navigation if it is.
So, let's get going.
Detecting a swipe
Before we can turn ourselves to the glyphs of code, we first ought to understand what exactly is a swipe and how to detect it using JavaScript.
This topic has been very nicely covered in our JavaScript Touch Events — Basics chapter, specifically in the section Swipe gestures.
We recommend that if you're unfamiliar with touch events in JavaScript, then you must read the whole chapter in order to be well-prepared to follow along the code snippet of this chapter. The swipe detection code that we'll use here will be quite similar to the one shown in the link above.
So assuming that at this point, you have a profound knowledge of working with touch events and detecting swipe gestures in JavaScript, it's time to start implementing a touch-interactive slider.
Note that at this stage, we don't want to build a highly touch-interactive slider, one where as we move our finger across the touch screen, the slider moves with it. That requires even more rigorous coding, which we'll surely accomplish in the next chapter.
For now, we want to keep everything superbly simple. That is, we just want to build a slider than can detect a swipe gesture when we end a touch interaction with the screen and then perform a navigation based on the outcome of the check.
The first step in doing so is to listen to the touchstart
and touchend
events on the .slider_slides-cont_wrapper
element.
.slider_slides-cont_wrapper
as the target of the events because it has already been selected in the slidesContWrapperElement
variable in our code — otherwise, we could've also gone with .slider_slides-cont
or even .slider
(at least in this case).In the code below, we accomplish this idea:
/* ... */
function navigateSlider() { /* ... */}
slidesContWrapperElement.addEventListener('touchstart', function(e) {});
slidesContWrapperElement.addEventListener('touchend', function(e) {});
/* ... */
Both the touch handlers are set up right after the navigateSlider()
function's definition. Technically, they could be set anywhere in the code.
With the touch handlers set up, the next step is to fill them up with some code to detect a swipe gesture.
Essentially two things are needed in determining whether a touch gesture is a swipe or not. They are:
- The change in the x and y co-ordinates of the touch point between the beginning and end of the touch gesture.
- The time duration of the touch gesture.
To obtain each of these pieces of information, we need to start off right upon the touchstart
event and determine their initial readings i.e. the x and y co-ordinates at that point and the time at that point.
This is done below:
var initialX, initialY, initialTime;
slidesContWrapperElement.addEventListener('touchstart', function(e) {
initialX = e.touches[0].clientX;
initialY = e.touches[0].clientY;
initialTime = new Date();
});
As the names suggest, the initialX
, initialY
and initialTime
variables hold the initial x co-ordinate, the initial y co-ordinate and the inital time, respectively, right when the touchstart
event occurs.
The reason of making these variables global is simply because we'll need them later on in the touchend
event's handler. If they were local variables, they would've disappeared as soon as the touchstart
handler exited.
Alright, so this is it for the touchstart
handler. The initial readings have been taken and now it's time to head over to the handler of touchend
.
Upon the touchend
event, we need to determine the change in all of the three readings taken above.
Let's get done with this first and then proceed with other concerns:
slidesContWrapperElement.addEventListener('touchend', function(e) {
var deltaX = e.changedTouches[0].clientX - initialX;
var deltaY = e.changedTouches[0].clientY - initialY;
var deltaTime = new Date() - initialTime;
});
Once again, as the names suggest, the variables deltaX
, deltaY
and deltaTime
represent the change in the x co-ordinate, the change in the y co-ordinate and the change in the time upon touchend
, respectively.
With the changes recorded, now we are only left with processing them in order to determine whether they really constitute a swipe gesture or not.
But what exactly is our definition of a swipe gesture?
Note that the values here are just randomly-chosen values that resonate well with our swipe detection code. If you want to, you can obviously scale them up or down.
For instance, instead of going with a time threshold of 400ms, you can scale this up to 400ms, 900ms or even 1s.
The definition given above simply translates to the following:
A swipe gesture is a touch interaction with Math.abs(deltaX) > 40
, Math.abs(deltaY) < 150
and deltaTime < 400
.
But this still doesn't help us in figuring out the direction of the swipe.
How to figure out the direction of the swipe?
Well, it's really simple: instead of applying Math.abs()
on deltaX
and then comparing the resulting absolute value with 40
, we could directly compare deltaX
with 40
or -40
.
That is, if deltaX > 40
, it means that the swipe was towards the right.
This is because in a swipe-right gesture, we start off from the left side of the touch surface with a lower clientX
value and then end up at a higher clientX
value on the right side. Subtracting a lower value from a higher value always gives a positive result.
Similarly, if deltaX < -40
it means that the swipe was towards the right.
Once again, this is because in a swipe-left gesture, we start off from the right side of the touch surface with a higher clientX
value and then end up at a lower clientX
value on the left side. Subtracting a higher value from a lower value always gives a negative result.
So to restate it:
deltaX > 40
, Math.abs(deltaY) < 150
and deltaTime < 400
.Similarly, a swipe-left gesture is a touch interaction with
deltaX < -40
, Math.abs(deltaY) < 150
and deltaTime < 400
.Let's take this idea into our touchend
handler.
Consider the code below:
slidesContWrapperElement.addEventListener('touchend', function(e) {
var deltaX = e.changedTouches[0].clientX - initialX;
var deltaY = Math.abs(e.changedTouches[0].clientY - initialY);
var deltaTime = new Date() - initialTime;
if (deltaTime < 400 && deltaY < 150) {
if (deltaX > 40) {
// Swipe-right gesture.
}
else if (deltaX < -40) {
// Swipe-left gesture.
}
}
});
The first if
statement in line 6 makes sure that both the conditions for a swipe gesture (i.e. swipe-left or swipe-right) are met.
If they are indeed met, another set of conditionals, from lines 7 - 12, determines the direction of the swipe and makes sure that the change in the x co-ordinate is beyond the given threshold.
Simple.
We are nearing the end of this chapter with just one thing left — calling navigateSlider()
function within the nested if
conditionals above. That's what we do up next.
Final steps
Let's think for a moment what would we need to do if a given swipe gesture is detected.
First, for the swipe-right gesture.
A swipe-right gesture means that we begin at the left side on the touch surface and go towards the right. Visually, this also means that we are trying to slide in something from the left side.
Hence, a swipe-right gesture is the equivalent of pressing the ← Previous button, i.e. decrementing newIndex
and then calling navigateSlider()
.
Now, let's consider the swipe-left gesture.
A swipe-left gesture means that we begin at the right side on the touch surface and go towards the left. Visually, this means that we are trying to slide in something from the right side.
Hence, a swipe-right gesture is the equivalent of pressing the Next → button, i.e. incrementing newIndex
and then calling navigateSlider()
.
Summing up both these ideas, below we write the final statements in our touchend
handler:
slidesContWrapperElement.addEventListener('touchend', function(e) {
var deltaX = e.changedTouches[0].clientX - initialX;
var deltaY = Math.abs(e.changedTouches[0].clientY - initialY);
var deltaTime = new Date() - initialTime;
if (deltaTime < 400 && deltaY < 150) {
if (deltaX > 40) {
// Swipe-right gesture.
newIndex--;
navigateSlider();
}
else if (deltaX < -40) {
// Swipe-left gesture.
newIndex++;
navigateSlider();
}
}
});
Time to try out the slider:
Voila! We just made a touch-interactive slider.