Introduction to Touch events in JavaScript
Date created: Aug 1st, 2013
In this tutorial lets get touchy feely with JavaScript, by examining its touch related events and how they are used to detect and respond to touch and swipe events. With touch based devices ever growing in numbers, grasping these events is as essential as understanding the age old mouse events. Examples in this tutorial can be appreciated in both touch and non-touch enabled devices, with the later falling back to your trusted mouse instead. Ready to give those fingers a bit of a workout? Lets go!
JavaScript Touch Events
So lets dive right into it. The following lists the supported touch events in JavaScript:
Event Name | Description |
---|---|
touchstart | Triggers when the user makes contact with the touch surface and creates a touch point inside the element the event is bound to. |
touchmove | Triggers when the user moves the touch point across the touch surface. |
touchend | Triggers when the user removes a touch point from the surface. It fires regardless of whether the touch point is removed while inside the bound-to element, or outside, such as if the user's finger slides out of the element first or even off the edge of the screen. |
touchenter | Triggers when the touch point enters the bound-to element. This event does not bubble. |
touchleave | Triggers when the touch point leaves the bound-to element. This event does not bubble. |
touchcancel | Triggers when the touch point no longer registers on the touch surface. This can occur if the user has moved the touch point outside the browser UI or into a plugin, for example, or if an alert modal pops up. |
These events can be attached to any element on the page, and
is passed an event object containing details about the touch point, such as
its coordinates on the page. Use element.addEventListener()
to
attach the event(s), for example to the BODY of the page:
window.addEventListener('load', function(){ // on page load document.body.addEventListener('touchstart', function(e){ alert(e.changedTouches[0].pageX) // alert pageX coordinate of touch point }, false) }, false)
Here I've attached the "touchstart
" event to
document.body
once the page has loaded (you may want to do this
on DOMContentLoaded
instead). Inside the anonymous function for
touchstart
, we look at the changedTouches
object
of the Event object, which contains information on each touch point
initiated by that touch event on the touch surface. Here we're only interested in the first
touch point (ie: finger) that has made contact, specifically, its
pageX
coordinate on the page when the touch is made.
The Event object whenever a touch
event is fired holds a wealth of information about the touch action; you
already saw its
changedTouches
object, which contains information on touch points
changed since the last touch event . Lets take the above example a bit
further now, by bringing in the touchmove
and touchend
events to show the
distance traveled by a touch action from beginning to end on a DIV, from a
finger touching down on an object to lifting up.
Example (mouse simulation added for non touch devices):
Touch Me!
Status
Touch then move your finger to see the current state of the touch and the distance traveled. The HTML markup for the DIV consists simply of:
<div class="box" id="box1"> <h3> Touch Me! </h3> </div> <h3 id="statusdiv">Status</h3>
The script looks like this:
<script> window.addEventListener('load', function(){ var box1 = document.getElementById('box1') var statusdiv = document.getElementById('statusdiv') var startx = 0 var dist = 0 box1.addEventListener('touchstart', function(e){ var touchobj = e.changedTouches[0] // reference first touch point (ie: first finger) startx = parseInt(touchobj.clientX) // get x position of touch point relative to left edge of browser statusdiv.innerHTML = 'Status: touchstart
ClientX: ' + startx + 'px' e.preventDefault() }, false) box1.addEventListener('touchmove', function(e){ var touchobj = e.changedTouches[0] // reference first touch point for this event var dist = parseInt(touchobj.clientX) - startx statusdiv.innerHTML = 'Status: touchmove
Horizontal distance traveled: ' + dist + 'px' e.preventDefault() }, false) box1.addEventListener('touchend', function(e){ var touchobj = e.changedTouches[0] // reference first touch point for this event statusdiv.innerHTML = 'Status: touchend
Resting x coordinate: ' + touchobj.clientX + 'px' e.preventDefault() }, false) }, false) </script>
A few points worth mentioning here:
-
We call
event.preventDefault()
to prevent the default action associated with each event from occurring. In the case oftouchstart
andtouchend
for instance, if the bound-to element was a link, not suppressing the default action would cause the browser to navigate to the link, cutting short our custom sequence of actions. In the case oftouchmove
, callingevent.preventDefault()
stops the browser from scrolling the page when the user is moving his finger inside the bound-to element. -
Once again, we access the first element inside
event.changedTouches[]
for each of the touch events to reference the first touch point made to the element (there could be multiple fingers used), and examine theclientX
property to get the horizontal coordinate of the touch point relative to the left edge of the browser (not including any scroll offsets). This property is adequate for what we're trying to do here, which is simply to get the relative distance traveled while a touch is maintained on the element. -
To get the distance traveled between
touchstart
andtouchend
events, we define astartx
variable at thetouchstart
phase that gets the startingclientX
position of the touch. Then throughout thetouchmove
event, we get theclientX
position of the touch and subtract from it thestartx
value to get the distance traveled while the touch point is maintained. -
Notice how the
touchend
event is still fired and displays the final resting x coordinates even if your finger is outside the bound-to element at the time of lifting up your finger.
The object event.changedTouches[]
is just one
of numerous properties of the Event object that gets populated during touch
related events. It's high time to look at this object in detail now.
Event object during Touch
The
Event object is this mystical unicorn in JavaScript that contains
information on an event when it occurs, whether it's the URL of a link in an
onclick
event, the
keyCode of the key pressed in an onkeypress
event etc. With touch related events, the Event object is
populated with a slew of unique properties that give us insight into all
aspects of the touch point, from how many fingers (or toes for that matter
etc) touched down on the touch surface to their precise coordinates on the
screen.
Property | Description |
---|---|
altkey | Boolean indicating whether the alt key was pressed at time of touch event. |
changedTouches | A list of Touch objects representing each touch point
directly involved in this event. Specifically:
length property to get the number of Touch objects
inside changedTouches[] . |
ctrlKey | Boolean indicating whether the crtrl key was pressed at time of touch event. |
metaKey | Boolean indicating whether the meta key was pressed at time of touch event. |
shiftKey | Boolean indicating whether the shift key was pressed at time of touch event. |
targetTouches | A list of touch points currently making contact with the
touch surface AND started out from the same element that is the
target of this event.
For example, lets say you bind the You can use the |
touches | A list of Touch objects representing all touch points currently in contact with the touch surface, regardless of which element a touch point is on at the moment. |
type | The type of event that triggered the Event object, such
as touchstart , touchmove , etc. |
target | The target element of the touches associated with this event. |
So for example, during a touchstart
event, the Event
object's touches
property lets us access all touch points currently in
contact with touch surface in general
document.body.addEventListener('touchstart', function(e){ var touchlist = e.touches for (var i=0; i<touchlist.length; i++){ // loop through all touch points currently in contact with surface //do something with each Touch object (point) } }, false)
The Event object's three properties evt.changedTouches
,
evt.targetTouches
, and evt.touches
are all list objects containing a
list of Touch objects, one Touch object for each touch point made. It is
through a Touch object you get details about a specific touch point, such as
its coordinates on the screen, its unique identifier to help you identify
which touch point is which, and so on. You saw in the beginning some code
that accesses a Touch object contained inside evt.changedTouches
:
box1.addEventListener('touchstart', function(e){ var touchobj = e.changedTouches[0] // reference first touch point (ie: first finger) startx = parseInt(touchobj.clientX) // get x position of touch point relative to left edge of browser e.preventDefault() }, false)
Here e.changedTouches[0]
is a Touch object, with
clientX
being one property of the Touch object. Lets take a formal look at the Touch
object now:
Property | Description |
---|---|
identifier | An value to help uniquely identify each touch point
currently in contact with the touch surface. The value starts at 0 for
the first unique touch point on the surface, 1 for the second etc. This
value is maintained for each touch point until the user's finger is
lifted off the surface. Lets say the user puts two fingers down on an element. Each finger at this point is assigned a unique identifier. When you move the fingers, you can use each touch point's identifier to identify which touch point is which. |
screenX | The x coordinate of the touch point relative to the left edge of the user's screen. |
screenY | The y coordinate of the touch point relative to the top edge of the user's screen. |
clientX | The x coordinate of the touch point relative to the left edge of the viewport, not including scroll offsets. |
clientY | The y coordinate of the touch point relative to the top edge of the viewport, not including scroll offsets. |
pageX | The x coordinate of the touch point relative to the left edge of the viewport, including scroll offsets. |
pageY | The y coordinate of the touch point relative to the top edge of the viewport, including scroll offsets. |
radiusX | The radius of the ellipse which most closely defines the touching area (e.g. finger, stylus) along the x-axis. |
radiusY | The radius of the ellipse which most closely defines the touching area (e.g. finger, stylus) along the y-axis. |
rotationAngle | The angle (in degrees) that the ellipse described by
radiusX and radiusY is rotated clockwise about its center. |
force | Returns the force of the touch point in the form of an integer between 0 and 1, where 0 is no force as detected by the device, and 1, the highest. |
target | The target element of the touch point; in other words,
the element the touch point landed on, which may be different
from the element its corresponding touch event was originally bounded
to. In the following, this always returns the BODY element, while
Touch.target returns the element the finger actually touched down on, which
could be a DIV, a SPAN etc:document.body.addEventListener('touchstart', function(e){
|
The properties of the Touch object you'll most frequently be accessing are those relating to coordinates, to help you determine where, and with a little Math, in what direction and how fast a touch action is performed.
Lets rewind now back to the Event object and talk a bit more
about the Touches
, changedTouches
, and targetTouches
properties, to help
more clearly explain their differences:
-
Touches: A list of all touch points currently making contact with the touch surface.
-
changedTouches: A list of touch points involved in this event. For example, in a
touchmove
event,changedTouches
contains only a list of touch points that are currently moving, whereasTouches
would contain all touch points currently on the surface. -
targetTouches: A list of touch points currently making contact with the touch surface AND started out from the same element that is the target of this event. For example, lets say you bind the
touchstart
event to a DIV and place two fingers down on the surface.targetTouches
will only contain information on the finger(s) placed inside the DIV, and not any outside.
Andrei at Stackoverflow gave a very illuminating example that clarifies the subtle differences between these three properties:
- When I put a finger down, all three lists will have the same information. It will be in changedTouches because putting the finger down is what caused the event
- When I put a second finger down, touches will have two items, one for each finger. targetTouches will have two items only if the finger was placed in the same node as the first finger. changedTouches will have the information related to the second finger, because it’s what caused the event
- If I put two fingers down at exactly the same time, it’s possible to have two items in changedTouches, one for each finger
- If I move my fingers, the only list that will change is changedTouches and will contain information related to as many fingers as have moved (at least one).
- When I lift a finger, it will be removed from touches, targetTouches and will appear in changedTouches since it’s what caused the event
- Removing my last finger will leave touches and targetTouches empty, and changedTouches will contain information for the last finger
Moving an object using touch
Using touch to move a DIV horizontally or vertically across the screen is very simple. Take a look at the below, which moves a DIV horizontally across a track when touched and dragged:
Example (mouse simulation added for non touch devices):
<script> window.addEventListener('load', function(){ var box2 = document.getElementById('box2'), boxleft, // left position of moving box startx, // starting x coordinate of touch point dist = 0, // distance traveled by touch point touchobj = null // Touch object holder box2.addEventListener('touchstart', function(e){ touchobj = e.changedTouches[0] // reference first touch point boxleft = parseInt(box2.style.left) // get left position of box startx = parseInt(touchobj.clientX) // get x coord of touch point e.preventDefault() // prevent default click behavior }, false) box2.addEventListener('touchmove', function(e){ touchobj = e.changedTouches[0] // reference first touch point for this event var dist = parseInt(touchobj.clientX) - startx // calculate dist traveled by touch point // move box according to starting pos plus dist // with lower limit 0 and upper limit 380 so it doesn't move outside track: box2.style.left = ( (boxleft + dist > 380)? 380 : (boxleft + dist < 0)? 0 : boxleft + dist ) + 'px' e.preventDefault() }, false) }, false) </script> <div id="track" class="track"> <div id="box2" style="left:0; top:0">Drag Me</div> </div>
The outer #track
DIV is a relatively positioned element,
while the #box2
DIV contained inside is absolutely positioned.
We get #box2
DIV's initial left position and the x coordinate of the touch point at the
touchstart
event. Note I'm using touchobj.clientX
here; we could have easily
used touchobj.pageX
instead, it doesn't matter, since we're only using this
property to help ascertain the relative distance traveled by touch point.
During the touchmove
event, we calculate the distance
traveled by the moving touch point, by getting its current x coordinate and
subtracting from that the initial x coordinate. Then, to move the #box2
DIV,
we add that distance to the DIV's initial left position, throwing in a lower
and upper limit of 0 and 380px, so to prevent the DIV from moving outside
the parent DIV. And with that our DIV box now moves with our finger!
- Introduction to Touch events in JavaScript
- Detecting a swipe using touch
- Monitoring touch actions at every stage, swipe image gallery