A jQuery Plugin for Touch Swiping – Part 1 of 2

Share this article

This article will explain the steps to create a jQuery plugin that detects the horizontal swiping motion on touch devices such as the iPhone and Android-based devices. This article is the first in a two-part series. In this article, we will be creating an image carousel that can respond to the user’s input and change the position of the carousel accordingly. The second article will extend the plugin by adding swipe detection.

HTML & CSS

Before we go on to the JavaScript, let’s take a look at the HTML and CSS for the image carousel which will be used to demonstrate the Swiper plugin. The HTML is shown below.
<div style="width: 330px; height: 200px;">
  <div id="target">
    <div>
      <div><img alt="" src="rexy.jpg" /></div>
      <div><img alt="" src="xena.jpg" /></div>
      <div><img alt="" src="xenaagain.jpg" /></div>
      <div><img alt="" src="rexyagain.jpg" /></div>
    </div>
  </div>
</div>
Similarly, the carousel’s CSS is shown below.
img { /*100% width to scale the height proportionately*/
  width: 100%;
  margin: 0;
}

.frame {
  width: 100%;
  height: 100%;
  border: 1px solid #ccc;
  overflow: hidden;
  position: relative;
}

.pictures {
  position: absolute;
  width: 400%; /*change accordingly*/
  left: 0%;
}

.pictures:after {
  content: "\0020";
  display: none;
  height: 0;
}

.pictures .pic {
  width: 25%; /*change with respect to .pictures*/
  float: left;
}
The inner container (.pictures) is set to 400% to contain four images. Each image’s container (.pic) is set to 25% so that the images end up at a width of 330 pixels. If you change the number of images or use absolute values instead of percentages, you’d want to change the width value of the .pictures and .pic elements accordingly. The images are made to line up horizontally by floating to the left. The frame (.frame) is made to show only one image at a time. With this setup, we can then “slide” the carousel by changing the left property of the .pictures <div> element.

JavaScript

Here is the skeleton of the plugin:
(function ($) {
  'use strict';

  var Swiper = function (el, callbacks) {
  }

  $.fn.swiper = function (callbacks) {
    if (typeof callbacks.swiping !== 'function') {
      throw '"swiping" callback must be defined.';
    }

    this.each(function () {
      var tis = $(this),
        swiper = tis.data('swiper');

      if (!swiper) { //i.e. plugin not invoked on the element yet
        tis.data('swiper', (swiper = new Swiper(this, callbacks)));
      }
    });
  };
}(jQuery));
This listing is boilerplate code for creating a jQuery plugin. The bulk of the complexity is handled by the internal class Swiper, whose methods are not yet defined. Swiper is responsible for reading the events produced by the browser and invoking the callback. The plugin is defined in a closure so that the Swiper class will not be mistakenly overridden by external code. The plugin is also prevented from binding to an element more than one time by associating the instantiated Swiper class with the swiper data attribute.
var Swiper = function (el, callbacks) {
  var tis = this;
  this.el = el;
  this.cbs = callbacks;
  this.points = [0, 0];

  //perform binding
  this.el.addEventListener('touchstart', function (evt) {
    tis.start(evt);
  });
  this.el.addEventListener('touchmove', function (evt) {
    evt.preventDefault();
    tis.move(evt);
  });
};
In the above listing, the Swiper
constructor instantiates the object’s properties and event handlers. The points property is a two-celled array that stores the starting position of the finger in the first cell, and the ending position in the second cell. We will see the usage of this array in subsequent listings. Its values are both initially zero. The constructor binds the touchstart and touchmove events, and proxies the events to the corresponding methods in the Swiper class. The touchstart binding initializes the points array with the initial position of the finger. The touchmove binding gives us the movement of the finger, which we will pass to the callback function to offset the carousel accordingly.
Swiper.prototype.start = function (evt) {
  if (evt.targetTouches && evt.targetTouches.length === 1) {
    if (evt.targetTouches[0].offsetX) {
      this.points[0] = evt.targetTouches[0].offsetX;
    } else if (evt.targetTouches[0].layerX) {
      this.points[0] = evt.targetTouches[0].layerX;
    } else {
      this.points[0] = evt.targetTouches[0].pageX;
    }
    //make initial contact with 0 difference
    this.points[1] = this.points[0];
  }
};
The listing above shows the start() method, which takes the event and reads the set of touches generated on screen. In devices with multi-touch capability, which means nearly all modern smartphones and tablets, this property is an array storing the locations of all contact points with the screen. In this implementation, we are keeping track of one contact point as we are tracking a single swipe gesture which is done using one finger. We are checking for the different properties of the touch event to accommodate the different implementations of the touch behaviour on different devices. This used to be required to make it work for different devices. Today, however, the devices that I have tested all generate the pageX property. Since we are checking only for a horizontal swipe gesture, we ignore the pageY property. We also set the cells of the points property to the same value so that the initial difference between the starting and ending points is zero. The function binding for the touchmove event and other helper methods are listed below.
Swiper.prototype.diff = function () {
  return this.points[1] - this.points[0];
};

Swiper.prototype.move = function (evt) {
  if (evt.targetTouches && evt.targetTouches.length === 1) {
    if (evt.targetTouches[0].offsetX) {
      this.points[1] = evt.targetTouches[0].offsetX;
    } else if (evt.targetTouches[0].layerX) {
      this.points[1] = evt.targetTouches[0].layerX;
    } else {
      this.points[1] = evt.targetTouches[0].pageX;
    }
    this.cbs.swiping(this.diff());
    this.points[0] = this.points[1];
  }
};
The diff() method simply calculates the difference between the last point (which changes as the user moves the finger) and the previous point. This is illustrated by the following figure.
image1
Illustration of the Distance “Dragged” by a Finger.
The move() method also checks through the different properties to get the right one for storing into the second cell of the points property. After storing the value, the callback function is invoked with the difference between the previous position and the new position of the finger. The callback function is responsible for changing the position of the carousel. This is explained below. After invoking the callback, the previous position’s value is replaced with the current position’s value. The next time the callback is invoked, the difference will be the displacement between the current position and the previous position instead of the starting position. This is required if we want the movement of the carousel to mirror that of the finger. Without this line, the carousel’s movement accumulates the difference and the result is a large displacement of images in response to a small movement of the finger, which is clearly undesirable for a smooth user experience. The listing below invokes the plugin.
var target = $('#target'),
  pictures = $('.pictures', target),
  MAX_LEFT = -990,
  MAX_RIGHT = 0,
  currPos = 0,
  cb = {
    swiping: function (displacement) {
      currPos += displacement;
      if (currPos > MAX_RIGHT) {
        currPos = MAX_RIGHT;
      } else if (currPos < MAX_LEFT) {
        currPos = MAX_LEFT;
      }
      pictures.css('left', currPos + 'px');
    }
  };

target.swiper(cb);
We get the element using its id. We also need a handle to the .pictures element within the target because the carousel’s positioning is changed by changing the left CSS property of this element. We set the left and right limit of the carousel’s position with the MAX_LEFT and MAX_RIGHT variables. These values have to change in relation to the carousel’s size. They are used so that the user does not scroll the carousel to empty spaces. The MAX_RIGHT variable determines how far right the finger can drag the carousel to hit the left-most image. Naturally, this value is 0. The MAX_LEFT variable limits how far left the finger can move the carousel. Since there are four images, to display the right-most one, the three images on the left have to be displaced. The values are derived like this: 330 (width of one image) * 3 = 990 We also have a variable, currPos, that stores the current position of the carousel. Alternatively, we can get the position of the carousel like so:
currPos = parseInt(pictures.css('left'));
The preferred approach is to use the variable. The only reason is that of performance – retrieving the left property of the element and converting it into an integer definitely consumes more processing power than accessing a variable’s value. This is cognizant of the fact that we are adding behavior on top of a browser’s interface, so it is important that we keep the plugin lean. The callback is specified as a property within a JSON literal. Why not simply pass it as a function? Well, this is to set the stage for part two of this series, where we will explain how to add swipe gesture detection to the plugin. A final note: on iOS devices (iPhones and iPads), there is a bouncing effect on the browser window when you scroll the carousel. This is apparent if the carousel is near the bottom or the top (as is the case here) of the page. To prevent that from happening, we call the preventDefault() method on the touchmove event. Incidentally, by calling the preventDefault() method, it prevents the event from bubbling up the DOM hierarchy, which in turn leads to better performance, especially apparent on slower devices such as the Nexus One. I’ve tested the plugin on the iPad 2 (iOS 6.0.1), Nexus One (Android 2.3.6), and Galaxy Note II (Android 4.1.2). If you have used any other devices/OS, feel free to let us know in the comments!

Frequently Asked Questions (FAQs) about jQuery Plugin for Touch Swiping

How Can I Implement jQuery Plugin for Touch Swiping in My Project?

To implement the jQuery plugin for touch swiping in your project, you first need to include the jQuery library in your HTML file. After that, you can include the jQuery touch swipe plugin. Once these are included, you can use the swipe function to detect swipe events on any element of your choice. You can then define what should happen when a swipe event is detected.

What Are the Different Types of Swipe Events That Can Be Detected?

The jQuery touch swipe plugin can detect four types of swipe events: swipe, swipeLeft, swipeRight, and swipeUp, swipeDown. Each of these events corresponds to the direction of the swipe. You can define different actions for each type of swipe event.

Can I Customize the Swipe Function?

Yes, the swipe function is highly customizable. You can set the swipe threshold (the minimum distance required for a swipe), the maximum time allowed for a swipe, and the swipe event target. You can also define what should happen when a swipe event is detected.

How Can I Test If the Swipe Function Is Working Correctly?

You can test the swipe function by using a touch-enabled device or an emulator. Simply swipe on the element where you have applied the swipe function and see if the defined action is performed.

Can I Use the jQuery Touch Swipe Plugin with Other jQuery Plugins?

Yes, the jQuery touch swipe plugin can be used in conjunction with other jQuery plugins. However, you need to ensure that there are no conflicts between the plugins.

Is the jQuery Touch Swipe Plugin Compatible with All Browsers?

The jQuery touch swipe plugin is compatible with most modern browsers. However, it may not work properly in older browsers that do not support touch events.

Can I Use the jQuery Touch Swipe Plugin in a Mobile App?

Yes, the jQuery touch swipe plugin can be used in mobile apps. It can detect touch events on both Android and iOS devices.

How Can I Debug Issues with the jQuery Touch Swipe Plugin?

You can debug issues with the jQuery touch swipe plugin by using the console log function. This will display any errors or issues in the browser’s console.

Can I Use the jQuery Touch Swipe Plugin for Multi-Touch Gestures?

The jQuery touch swipe plugin is primarily designed for single touch gestures. However, it can be extended to support multi-touch gestures with some additional coding.

How Can I Learn More About the jQuery Touch Swipe Plugin?

You can learn more about the jQuery touch swipe plugin by reading the documentation, looking at examples, and experimenting with the plugin on your own. You can also ask questions on forums and communities dedicated to jQuery and web development.

Chee How ChuaChee How Chua
View Author

Chee How is a technology enthusiast and is especially interested in all Web related stuff. He currently works as a Web developer in a company he co-founded, and writes JavaScript, Java and PHP on a day-to-day basis.

IntermediatejQueryplugins
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week