iPad Touch Events: an Idiot’s Guide

This blog is the result of a surprisingly useful tracer bullet we undertook looking into introducing iPad support and Touch functionality.  An initial comment would be to note how easy I found implementing this functionality and responding to the Touch events.

The investigation was carried out using two main approaches.

The first approach was to implement the functionality in the most basic possible way, ensuring maximum flexibility.

This involved hooking into the core JavaScript functions.  This is done the same way as hooking up to a JavaScript click method, so the html to create a coloured div that responds to click events is simply:

<div id="box" style="height:225px;width:225px;background:red;position:absolute;" ontouchmove="touchMove(event)" ontouchstart="touchStart(event)"></div>

Then, all that’s needed is to declare the two functions in JavaScript functions as shown in the following example:

function touchStart( e ) {
var box = document.getElementById("box");
box.style.background = "green";
e.preventDefault();
return false;
}

function touchMove( e ) {
var targetEvent =  e.touches.item(0);
var box = document.getElementById("box");
box.style.background = "yellow";
box.style.left = targetEvent.clientX + "px";
box.style.top= targetEvent.clientY + "px";
e.preventDefault();
return false;
}

Note that the e.preventDefault(); command prevents the event from propagating to the browser and e.g. causing page scrolling.

A more comprehensive example that this was based upon can be found at: http://gregmurray.org/ipad/touch-events.html

So, I don’t know about you guys but I think that was a lot easier than I expected!  I know the above example is only very basic, but this just starts to show how you can easily start to interact with Touch events, and hence start  to provide a better iPad user experience – and you shouldn’t be afraid to do so!

The second approach I took was to adapt the previous approach so as to use an external library.  I looked at several libraries available online and chose Hammer.js – the reasons I selected this library were that it is completely standalone, implements a wide variety of functionality by default and is simple to use.

The final example I built used Hammer and JQuery.  The HTML needed for this touchable box has only slightly changed slightly:

<div id="box" style="left:200px;height:225px;width:225px;background:red;position:absolute;" ></div>

Note that we are not connecting the ontouchmove and ontouchstart events ourselves – instead the Hammer code will do this for us.

The JavaScript required to attach to these events is simply as follows:

var el = document.getElementById('box');
var hammer = new Hammer(el, {
drag_min_distance: 50,
drag_horizontal: true,
drag_vertical: true,
transform: true,
scale_treshold: 0.1,
hold: true,
hold_timeout: 400,
swipe: true,
swipe_time: 200, // ms
swipe_min_distance: 20, // pixels
prevent_default: true
});

As you can see, Hammer provides many variables in this declaration, allowing us to simply determine things such as swipe time and how long the object must be held before the hold event is triggered.  This is a very easy-to-use way to tweak the functionality as required.

We then attach simple handlers to the events when they are called:

hammer.onhold = function (ev) {
var width = $('#box').width();
width = width * (0.85);
$('#box').width(width);
var height = $('#box').height();
height = height * (0.85);
$('#box').height(height);
};

In the full example (see the bottom of this article), this results in a red box on the screen that can be dragged, swiped, tapped, held and scaled using two fingers – all of which are implemented in the same manner as above!

So, in summary, hopefully you have all gained a basic introduction to how we can support Touch events with the iPad – and hopefully you were also surprised at the ease with which this can be achieved!

Full Example Code:

<html>
<head>
<script src=”http://code.jquery.com/jquery-1.7.2.min.js”></script&gt;
<script src=”http://eightmedia.github.com/hammer.js/hammer.js”></script&gt;

<script type=”text/javascript”>

$(document).ready(function () {

var logDetailsDiv = document.getElementById(“logDetails”);

var el = document.getElementById(‘box’);

var hammer = new Hammer(el, {
drag_min_distance: 50,
drag_horizontal: true,
drag_vertical: true,
transform: true,
scale_treshold: 0.1,
hold: true,
hold_timeout: 400,
swipe: true,
swipe_time: 200, // ms
swipe_min_distance: 20, // pixels
prevent_default: true
});

var drag = {};
var container_size = el.getBoundingClientRect();
var drag_el;
var drag_el_size = {};
var drag_timer;
var drag_pos = {};
var zIndex = 10;

var touchOffsetx = 0;
var touchOffsety = 0;

hammer.ontap = function (ev) {
var touches = ev.originalEvent.touches || [ev.originalEvent];
for (var t = 0; t < ev.touches.length; t++) {
var el = touches[t].target;
if (el.className.search(‘box’) > -1) {
el.style.zIndex = zIndex++;
}
}
};

hammer.ondrag = function (ev) {
drag = [];
var touches = ev.originalEvent.touches || [ev.originalEvent];
for (var t = 0; t < touches.length; t++) {
var el = touches[t].target;

if (el && el.className.search(‘box’) > -1) {
var offsetwidth = $(‘#box’).width();
var offsetheight = $(‘#box’).width();
log(offsetwidth + “:” + offsetheight)
drag.push({
el: el,
size: { width: offsetwidth, height: offsetheight },
pos: ev.touches[t]
});
}
}
};

setInterval(watchDrag, 10);

function watchDrag() {
if (!drag.length) {
return;
}

for (var d = 0; d < drag.length; d++) {
var left = drag[d].pos.x – (drag[d].size.width / 2) – touchOffsetx;
var top = drag[d].pos.y – (drag[d].size.height / 2);

if (left < 0) {
left = 0;
}
if (top < 0) {
top = 0;
}

drag[d].el.style.left = left + ‘px’;
drag[d].el.style.top = top + ‘px’;
}
}

hammer.onswipe = function (ev) {
if (ev.direction == ‘right’) {
log(“swipeRight” + $(‘#cont’).width() + ‘px’);
$(‘#box’).attr(“Left”, $(‘#cont’).width() + ‘px’);
}
if (ev.direction == ‘left’) {
log(“swipeLeft” + $(‘#cont’).width() + ‘px’);
$(‘#box’).attr(“Left”, ’0′ + ‘px’);
}

}
hammer.ondoubletap = function (ev) {
var width = $(‘#box’).width();
log(“touchOffset =” + width);

width = width * (1.2);
$(‘#box’).width(width);

var height = $(‘#box’).height();
log(“touchOffset =” + width);

height = height * (1.2);
$(‘#box’).height(height);
};

hammer.onhold = function (ev) {
var width = $(‘#box’).width();
log(“touchOffset =” + width);

width = width * (0.85);
$(‘#box’).width(width);

var height = $(‘#box’).height();
log(“touchOffset =” + width);

height = height * (0.85);
$(‘#box’).height(height);

};

hammer.ontransformstart = function (ev) { };
var oldScale = 0.0;
hammer.ontransform = function (ev) {

var width = $(‘#box’).width();
var height = $(‘#box’).height();
var scale = 1 + ev.scale – oldScale;
log(“scale =” + scale);

width = width * (scale);
$(‘#box’).width(width);

height = height * (scale);
$(‘#box’).height(height);
oldScale = ev.scale;
};

hammer.ontransformend = function (ev) {

};
});

function log(text) {
document.getElementById(“log”).innerHTML = text;
}
</script>
</head>
<body>
<div id=”cont” style=”height:250px”>
<div id=”log”> log me</div>
<div id=”logDetails”></div>
<div id=”box” style=”left:200px;height:225px;width:225px;background:red;position:absolute;” ></div>
</div>
</body>
</html>

About these ads
This entry was posted in Development, Web Stuff. Bookmark the permalink.

2 Responses to iPad Touch Events: an Idiot’s Guide

  1. Paul says:

    I’ve been looking hard at hammer.js. You put things in such simple terms. Thanks so much, because it was sort of overwhelming me!

  2. Pastelka says:

    Yes i’m an idiot, thank you :)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s