Course: JavaScript

Progress (0%)

  1. Foundation

  2. Numbers

  3. Strings

  4. Conditions

  5. Loops

  6. Arrays

  7. Functions

  8. Objects

  9. Exceptions

  10. HTML DOM

  11. CSSOM

  12. Events

  13. Drag and Drop

  14. opt Touch Events

  15. Misc

  16. Project: Analog Clock

JavaScript TouchList Interface

Chapter 76 15 mins

Learning outcomes:

  1. What is the TouchList interface
  2. The touches object
  3. The changedTouches object
  4. The targetTouches object

Introduction

In the last chapter, JavaScript Touch Events — Basics, we covered the basics of working with touch events in JavaScript through the help of numerous practical examples. There we came across the three different TouchList interfaces present on a TouchEvent object, namely touches, changedTouches and targetTouches.

Now in this chapter, our aim is to unravel the purpose of each of these three objects by drawing the exact difference between them and that through the help of numerous examples, as before.

So, let's get going...

Understanding TouchList

When we interact with an HTML document via a mouse pointer, some kind of mouse event is dispatched. Each such event is an instance of MouseEvent which contains properties such as clientX / clientY to represent the co-ordinates of the location of the mouse pointer right at the instance when the event occcured.

The same doesn't apply to a touch event. The reason is because devices typically support a feature called multi-touch which basically means that multiple fingers can interact with the screen simultaneously.

This means that there is absolutely no sense in providing properties such as clientX / clientY directly on a TouchEvent object.

Rather, it's necessary to provide a list of all the concerned touch points, each of which then contains these properties.

This is exactly the intuition behind TouchList — it's an interface meant to hold multiple touch points.

Each element in a TouchList object is a Touch instance that contains information regarding the underlying touch point.

A TouchList object has a length property to our use holding the total number of elements in it. It also provides an iterator setup to allow for quick iteration over all the respective touch points.

However, as with many list interfaces in JavaScript, it doesn't inherit from the Array interface and likewise doesn't have many of the useful array methods such as forEach(), slice() and so on.

There are a total of three different kinds of TouchList instances — touches, changedTouches and targetTouches.

Let's now see each of these instances one-by-one.

The touches object

Although we have seen and worked with touches for a quite a while in the previous chapter, let's review it once again.

In simple terms:

touches is a TouchList instance representing all the touch points that are currently in contact with the touch surface.

It's useful when we want to determine the total number of points on the touch surface. Such a program was created in the previous chapter.

With the definition in mind, let's consider some examples to help us understand how touches works.

First, let's see the touches object upon the touchstart event.

Consider the following code where we simply output the length of the touches object on touchstart:

var touchRegionElement = document.getElementById('touch-region');
var outputElement = document.getElementById('output');

touchRegionElement.addEventListener('touchstart', function(e) {
   e.preventDefault();
   outputElement.innerText = e.touches.length;
});

Live Example

If we tap over the #touch-region element here, the touchstart event fires with touches holding all the touch points currently in contact with the touch surface including the one that just fired the event.

The reason of calling e.preventDefault() in the code above is to make sure that while interacting with the program, no kind of default browser action happens on the device, such as reloading the page when swipped down across the page.

Simple so far.

Now let's consider the touchmove event with the same setup as before:

var touchRegionElement = document.getElementById('touch-region');
var outputElement = document.getElementById('output');

touchRegionElement.addEventListener('touchmove', function(e) {
   e.preventDefault();
   outputElement.innerText = e.touches.length;
});

Live Example

As we move the touch point over the whole document after initiating a touchstart event inside #touch-point, touches once again represents a list of all touch points currently in contact with the surface.

Pretty intuitive, even in this case.

Now let's consider touches on the touchend event:

var touchRegionElement = document.getElementById('touch-region');
var outputElement = document.getElementById('output');

touchRegionElement.addEventListener('touchend', function(e) {
   e.preventDefault();
   outputElement.innerText = e.touches.length;
});

Live Example

Here comes the catch: when we remove the touch point from the surface, touchend fires, and since the touch point is no longer in contact with the surface, we can't obtain information (such as at what position it left) via the touches object.

This is the main problem with touches — it just doesn't provide us with this crucial information about the recently removed touch point. For that, we ought to refer to the changedTouches object.

The changedTouches object

As the name might suggest, changedTouches is meant to hold all the touch points whose state has changed since the last event.

Defining it simply:

changedTouches is a TouchList instance representing all the touch points that fired the current event.

Let's see some examples.

First for changedTouches on the touchstart event:

<div id="touch-region"></div>

<div><code>touches.length</code>: <span id="output1">0</span></div>
<div><code>changedTouches.length</code>: <span id="output2">0</span></div>
var touchRegionElement = document.getElementById('touch-region');
var output1Element = document.getElementById('output1');
var output2Element = document.getElementById('output2');

touchRegionElement.addEventListener('touchstart', function(e) {
   e.preventDefault();
   output1Element.innerText = e.touches.length;
   output2Element.innerText = e.changedTouches.length;
});

Live Example

To truly interact with this program, your environment must have multi-touch support. If you're using Developer Tool's touch emulation, then it'll be hard to interact with this program.

For instance, if we tap on the surface with one touch point, a touchstart event fires. Assuming that this touch point is still there on the surface (regardless of whether it has moved or not), if we tap with another touch point, touchstart will fire once again.

In this event, touches will contain two Touch objects, however changedTouches will contain only one i.e. the second touch point that caused this touchstart event.

Next up, let's consider changedTouches on the touchmove event with the same setup as before:

var touchRegionElement = document.getElementById('touch-region');
var output1Element = document.getElementById('output1');
var output2Element = document.getElementById('output2');

touchRegionElement.addEventListener('touchmove', function(e) {
   e.preventDefault();
   output1Element.innerText = e.touches.length;
   output2Element.innerText = e.changedTouches.length;
});

Live Example

If we place two touch points on the #touch-region element and then move only one touch point while keeping the other still, a touchmove event will fire where changedTouches will hold the moved touch point. In contrast, touches will contain both the touch points.

Hence, changedTouches allows us to determine which touch points have moved upon the current touchmove event.

Let's now consider changedTouches on touchend:

var touchRegionElement = document.getElementById('touch-region');
var output1Element = document.getElementById('output1');
var output2Element = document.getElementById('output2');

touchRegionElement.addEventListener('touchend', function(e) {
   e.preventDefault();
   output1Element.innerText = e.touches.length;
   output2Element.innerText = e.changedTouches.length;
});

Live Example

The event where almost all touch-driven programs use changedTouches is perhaps touchend. It's what allows us to obtain information regarding the touch point that just exited the touch surface. This could then be used to, let's say, perform an array of different computations.

Here's a simple task:

Write a program listening to touch events over the entire document window and then outputting the x and y coordinates of the location where a touch point leaves the surface.

The output should be made inside the <div> element as shown below

<div id="co-ordinates"></div>

in the format (x, y), where x is the x co-ordinate and y is the y co-ordinate.

var coordinatesElement = document.getElementById('co-ordinates');

window.addEventListener('touchend', function(e) {
   coordinatesElement.innerText = '(' +
      e.changedTouches[0].clientX +
      ', ' +
      e.changedTouches[0].clientX +
      ')';
});

Live Example

To summarize it all:

  1. On touchstart, changedTouches holds all touch points that came into contact with the touch surface to cause the event.
  2. On touchmove, changedTouches holds all touch points that moved past their previous position to cause the event.
  3. On touchend, changedTouches holds all touch points that exited the touch surface to cause the event.

The targetTouches object

It won't be wrong to say that of all three TouchList instances on a TouchEvent object, targetTouches is the least useful.

Let's see what exactly is it.

targetTouches is a TouchList instance representing all the touch points that are currently in contact with the surface and have the same target as that of the current event.

The main part here is the ending of the definition i.e. 'and have the same target as that of the current event.'

Didn't understand this?

Well, let's see an example.

Take a look at the following HTML and JavaScript:

<div id="touch-region"></div>

<div><code>targetTouches.length</code>: <span id="output1">0</span></div>
<div>Target element: <span id="output2">-</span></div>
var touchRegionElement = document.getElementById('touch-region');
var output1Element = document.getElementById('output1');
var output2Element = document.getElementById('output2');

window.addEventListener('touchstart', function(e) {
   e.preventDefault();
   output1Element.innerText = e.targetTouches.length;
   output2Element.innerText = e.target.nodeName;
});

Live Example

If we tap over the #touch-region element with one touch point and then tap outside it with another one, somewhere on the document, at this point, touchstart will fire with targetTouches holding one single element which is the touch point outside #touch-region.

Now with both the touch points still on the surface, if we tap with another touch point over #touch-region (where there is already one touch point), touchstart will fire again, this time with targetTouches holding two elements.

That's because at this point, there will be a total two of touch points having #touch-region (which is the target of the current touchstart event) as their target.

So this is how targetTouches works on touchstart.

A similar description applies to touchmove.

Upon touchend, targetTouches contains all those points that have the same target as the point that caused the current event.