HTML5 for the Mobile Web: Touch Events

POSTED BY RUADHAN - 15 AUG 2013

With the widespread adoption of touchscreen devices, HTML5 brings to the table, among many other things, a set of touch-based interaction events. Mouse-based events such as hover, mouse in, mouse out etc. aren’t able to adequately capture the range of interactions possible via touchscreen, so touch events are a welcome and necessary addition to the web developer's toolbox.

Use cases for the touch events API include gesture recognition, multi-touch, drag and drop, and any other touch-based interfaces.

The Touch Events API

We'll get some of the technical details of the API out of the way first, before moving on to some real examples. The API is defined in terms of Touches, TouchEvents, and TouchLists.

Each Touch describes a touch point, and has the following attributes:

Attribute Description
identifier unique numeric identifier
target the DOM element that is the event target of the touch, even if the touch has moved outside of this element
screenX horizontal coordinate relative to screen
screenY vertical coordinate relative to screen
clientX horizontal coordinate of point relative to viewport, excluding scroll offset
clientY vertical coordinate of point relative to viewport, excluding scroll offset
pageX horizontal coordinate of point relative to page, including scroll offset
pageY vertical coordinate of point relative to page, including scroll offset

The main touch events defined in the specification are outlined in the table below. The target of the event is the element in which the touch was detected, even if the touch has moved outside this element.

Event Description
touchstart triggered when a touch is detected
touchmove triggered when a touch movement is detected
touchend triggered when a touch is removed e.g. the user’s finger is removed from the touchscreen
touchcancel triggered when a touch is interrupted, e.g. if touch moves outside of the touch-capable area

Three lists of touches, TouchLists, are associated with each of the events. These are:

List Description
touches all current touches on the screen
targetTouches all current touches that started on the target element of the event
changedTouches all touches involved in the current event

Touch Events example

We’ll cover just the basics in this example. There are plenty of more complex examples to be found on the web already, such as the canvas fingerpaint demo by Paul Irish et al. Here we demonstrate simply how to capture and inspect a touch event. Of the available data from the API, we'll use only the touchstart event, and the pageX and pageY attributes.

First, some HTML. We define a touch-sensitive div to which we will attach an event listener. We also define a div at the top where we will display the screen coordinates of the most recent touch.

  <div id="coords"></div>
<div id="touchzone"></div>

Next we add some JavaScript to register the event listener, and add a handler function to do something with the touch data:

function init() {
// Get a reference to our touch-sensitive element
var touchzone = document.getElementById("touchzone");
// Add an event handler for the touchstart event
touchzone.addEventListener("touchstart", touchHandler, false);
}

So, here we’re simply identifying the touchzone div, attaching a listener for the touchstart event, and registering a handler function: touchHandler.

In the touchHandler function we grab the x and y coordinates of the touch, and write them to the coords div:

function touchHandler(event) {
// Get a reference to our coordinates div
var coords = document.getElementById("coords");
// Write the coordinates of the touch to the div
coords.innerHTML = 'x: ' + event.touches[0].pageX + ', y: ' + event.touches[0].pageY;
}

And now we’re ready to go. If you are viewing this page on a device which supports touch events, you should be able to see the screen coordinates of your touches below.

Live Demo - display touch coordinates

Click the area to the right to activate the live demo. Depending on your device, you should be able to see the the coordinates of your touch points.

(Note: this demo, and the other demos on this page, are listening for touch AND mouse events, and so they should also work on non-touch enabled devices).

 
x: 686, y: 2201

Display touches on screen

So now we know how to grab and display some basic touch data. Let's go one step further and display the touch position information visually, by displaying a dot on the screen at the point where it was touched.

There are a couple of extra things we need to do to get this working. For the display, we'll make use of another HTML5 feature: the canvas element. For now, all we need to say about canvas is that it facilitates drawing graphics in a web page without much difficulty.

To define the canvas element, we use the following (we've set the size, and added a border too):

  <canvas id="mycanvas" width="662" height="373" style="border: 1px solid #ccc">
Canvas element not supported<br />
</canvas>

We also need to modify the handler function from the last example, so that we now draw on this canvas element. To do this, we need to:

  1. Find the canvas element in the DOM

        var canvas = document.getElementById('mycanvas');
  2. Get the 2D drawing context from the canvas element; this provides the methods and properties we need to draw on the canvas
        var ctx = canvas.getContext("2d");
  3. Use the drawing context to draw something; we'll draw a small rectangle
        ctx.fillRect(event.touches[0].pageX-offset.left, event.touches[0].pageY-offset.top, 5, 5);

That's it! The full code is displayed below:

<!DOCTYPE html>
<html>
<head>
<title>HTML5 input </title>
<script>
 
function init() {
var touchzone = document.getElementById("mycanvas");
touchzone.addEventListener("touchstart", draw, false);
}
 
function draw() {
var canvas = document.getElementById('mycanvas');
 
if(canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.fillRect (event.touches[0].pageX, event.touches[0].pageY, 5, 5);
}
}
</script>
 
</head>
<body onload="init()">
<canvas id="mycanvas" width="500" height="500">
Canvas element not supported.
</canvas>
</body>
</html>

Touch the image below to activate the live demo, and then touch the area below to display your touches!

Touch coordinate and screen coordinate conversion

A short note on coordinates and element positions. There is a small trick - to do with coordinate frames - that was glossed over in the above example. The above example will work fine if the canvas element is the only element on the page, and it is aligned with the top left of the page. However, most of the time in your webapps the element that you are interested in will not benefit for the luxury of sitting in this top-leftmost position - more likely it will be embedded in the page some distance down and across. That is, it will be offset by a certain amount from the left of the viewport, and a certain amount from the top of the viewport. We can call these values offsetLeft and offsetTop respectively.

These values must be taken into account when we want to convert the reported touch event coordinates to usable screen coordinates. Incorporating the offset is quite simple; we use something like touch.pageX-offsetLeft, andtouch.pageY-offsetTop. So how do we get the offsets? To do this, I refer to the method outlined on the Quirskmode blog. The trick is to start with the element we are interested in, and to traverse up the DOM tree, accumulating the offset of each element from its parent until the top is reached. Then we have the total offset that we can use in our app.

A function to compute this offset looks like this:

function getOffset(obj) {
var offsetLeft = 0;
var offsetTop = 0;
do {
if (!isNaN(obj.offsetLeft)) {
offsetLeft += obj.offsetLeft;
}
if (!isNaN(obj.offsetTop)) {
offsetTop += obj.offsetTop;
}
} while(obj = obj.offsetParent );
return {left: offsetLeft, top: offsetTop};
}

From single touches to swipes and gestures: the touchmove event

In the last example we saw how we could visualise single touches as dots, using the canvas element and the touchstart event. Now we'll take a look at what we can do when we add the touchmove event into the mix. The touchstart event was useful to capture single point touches. But with touchmove we can capture swipes and other gestures.

The first thing we can try is to simply use the touchmove event in place of the touchstart event, and leave the rest of our code the same. So, each time the touchmove event is fired during a touch, we will draw a dot (small rectangle) at the point reported by the event. This should, in theory, trace out the entire touch as a path on the screen.

In our init function, we will have:

    canvas.addEventListener("touchmove", draw, false);

So we can now draw freeform shapes. However, because we are only drawing points, if we move too fast, then the result will be a broken path, as depicted in the image on the right.

If we want instead a nice continuous path, we need to be a little smarter. Instead of simply drawing a dot at the reported touch position, we draw a line between the last two touchpoints. This should fill the gaps we saw in the image above. We can achieve this with the code below:

      ctx.beginPath();
// Start at previous point
ctx.moveTo(lastPt.x, lastPt.y);
// Line to latest point
ctx.lineTo(e.touches[0].pageX, e.touches[0].pageY);
// Draw it!
ctx.stroke();
 
//Store latest touchpoint
lastPt = {x:e.touches[0].pageX, y:e.touches[0].pageY};

Finally, we don't want to continue the path we are drawing across separate touches where the finger has been lifted from the screen, or we will end up with all paths joined up - as shown in the image to the right, in which there are three separate paths that are incorrectly joined. For this, we need to figure out when the touch has ended, and to terminate the path we are drawing. Enter the touchend event!

First, we will register a handler function for thetouchend event. In this function, we need to perform any necessary actions that should occur at the end of the touch. In this case we are drawing the path of the touches on the screen, so for the touchendevent, we need to terminate the current path, and to ensure that it is not associated with the next touch that occurs.

So, to attach the handler:

  touchzone.addEventListener("touchend", endTouch, false);

In our example, whenever the touchmove event is triggered, we store the last point so that we can join up the last two points. So, to end the path of a touch, we simply forget about the last point by setting it to null:

  function endTouch(e) {
e.preventDefault();
lastPt=null;
}

The full code then for the example is:

<!DOCTYPE html>
<html>
<head>
<title>HTML5 Touch Tracing </title>
<script>
var canvas;
var ctx;
var lastPt=null;
 
function init() {
var touchzone = document.getElementById("mycanvas");
touchzone.addEventListener("touchmove", draw, false);
touchzone.addEventListener("touchend", end, false);
ctx = touchzone.getContext("2d");
}
 
function draw(e) {
e.preventDefault();
if(lastPt!=null) {
ctx.beginPath();
ctx.moveTo(lastPt.x, lastPt.y);
ctx.lineTo(e.touches[0].pageX, e.touches[0].pageY);
ctx.stroke();
}
lastPt = {x:e.touches[0].pageX, y:e.touches[0].pageY};
}
 
function end(e) {
e.preventDefault();
// Terminate touch path
lastPt=null;
}
</script>
</head>
<body onload="init()">
<canvas id="mycanvas" width="500" height="500">
Canvas element not supported.
</canvas>
</body>
</html>

Activate the touchmove example by touching the purple bumblebee, and draw something in the box below.

HTML5 multi-touch example

So, now we can handle single touches and swipes, what about mutliple simultaneous touch interactions, or, in the parlance of our times, multi-touch?

We can determine the number of touch events by checking the length of the list of touches, using e.touches.length. In the previous examples we assumed just one touch, and so we referenced touches[0] to get at the data for this touch. So, to add multi-touch support to our demo, we can iterate over the touches array, and perform an appropriate action for each of the touches in the array. This amounts to wrapping our previous code in a loop, and instead of storing the last point for a single touch, we store an array of the last points for all the registered touches.

Finally, to help the visualisation, we'll add a splash of colour with:

  var colours = ['red', 'green', 'blue', 'yellow', 'black'];

Then we can set the colour of a line with:

   ctx.strokeStyle = colours[id];

Maintaining the list of latest points is a little trickier when when want to know which touch path to terminate. For this we can make use of the identifier attribute of the touch object. We will maintain an associative array of the last points of all touches, keyed by the identifier attribute of the respective touch.

We define our associative array as an Object:

var lastPt = new Object();

We can get the identifier of a touch with:

  var id = e.touches[i].identifier;

And we can add new items into the array, using the touch identifier as the key, with:

lastPt[id] = {x:e.touches[i].pageX, y:e.touches[i].pageY};

Finally, we need to remove entries in the array when we detect the touchend event. To do this, we make use of thechangedTouches touchList. This array includes all the touches associated with the current event. So, when we detect the touchend event, we can iterate over this array, and remove the entries in the lastPt associative array that match the identifiers of the touches in the changeTouches array:

  function end(e) {
e.preventDefault();
for(var i=0;i<e.changedTouches.length;i++) {
var id = e.changedTouches[i].identifier;
delete lastPt[id];
}
}

The full code listing is below:

<!DOCTYPE html>
<html>
<head>
<title>HTML5 multi-touch</title>
<script>
var canvas;
var ctx;
var lastPt = new Object();
var colours = ['red', 'green', 'blue', 'yellow', 'black'];
 
function init() {
var touchzone = document.getElementById("mycanvas");
touchzone.addEventListener("touchmove", draw, false);
touchzone.addEventListener("touchend", end, false);
canvas = document.getElementById('mycanvas');
ctx = canvas.getContext("2d");
}
 
function draw(e) {
e.preventDefault();
 
//Iterate over all touches
for(var i=0;i<e.touches.length;i++) {
var id = e.touches[i].identifier;
if(lastPt[id]) {
ctx.beginPath();
ctx.moveTo(lastPt[id].x, lastPt[id].y);
ctx.lineTo(e.touches[i].pageX, e.touches[i].pageY);
ctx.strokeStyle = colours[id];
ctx.stroke();
 
}
// Store last point
lastPt[id] = {x:e.touches[i].pageX, y:e.touches[i].pageY};
}
}
 
function end(e) {
e.preventDefault();
for(var i=0;i<e.changedTouches.length;i++) {
var id = e.changedTouches[i].identifier;
// Terminate this touch
delete lastPt[id];
}
}
 
</script>
</head>
<body onload="init()">
<canvas id="mycanvas" width="500" height="500">
Canvas element not supported.
</canvas>
</body>
</html>

Touch the squiggly lines below to activate the live multitouch demo; then move multiple fingers around the screen at the same time!

Browser support and fallbacks

Touch events are widely supported among mobile devices. However, unless specifically targeting touch devices, a fallback should be implemented when touchevents are not supported. In these cases, the traditional click etc. events can be bound to, but as discussed below, care is needed when deciding which events to support instead of the touch events.

  Android iOS IE Mobile Opera Mobile Opera Classic Opera Mini Firefox Mobile Chrome for Android
Touch support                
(Sources: caniuse.comDeviceAtlasmobilehtml5.org)

Touch and mouse events

Since touch events may not be supported on a user's device - indeed, the user may not even be accessing your app on a touchscreen device - this contingency should be planned for. You may want to enable your app to support particular mouse events instead. Care should be taken here as there is not a one-to-one correspondance between mouse events and touch events, and the behaviour differences can be subtle. For a good overview of the issues involved take a look at the article Touch and Mouse by Chris Wilson and Paul Kinlan.

Best practices

Care should also be taken implementing touch events that the events don't interfere with typical browser behaviours such as scrolling and zooming - thus there is an argument for disabling these default browser behaviours if you are making use of touch events. Boris Smus outlines these and other potential pitfalls to look out for over on HTMLRocks.

Conclusion

In this article we've taken a look at the how the HTML5 Touch Events API enables touch interactions for your web apps. We saw how to access raw touch data, and how we can manage multi-touch interactions. While we worked through some examples to demonstrate how to access and display touches on the screen (with a little help from our friend, the canvas element), it's worth mentioning that there are open source libraries available which take care of the some of the lower level details for you, such as the very useful Hammer.js, a JavaScript library for multi-touch gestures. That's all for now, stay tuned for our follow up articles in our HTML5 series.

Update Live examples updated to work with mouse events as well as touch events for illustration purposes

Links and references

Download

The code examples in this article can be downloaded below.

Attachment Size
touch-demos.zip 2.06 KB

Html5 touch event的更多相关文章

  1. Touch Event

    转自:      http://hi.baidu.com/masaiui/item/971775e8b316238bc10d754b 参考: http://hedgehogking.com/?p=55 ...

  2. html5 touch事件实现触屏页面上下滑动(二)

    五一小长假哪都没去,睡了三天,今天晕晕沉沉的投入工作了,但还是做出了一点点效果 上周用html5的touch事件把简单的滑动做出来了,实现了持续页面上下滑动的效果,参考之前 的文章及代码html5 t ...

  3. html5 touch事件实现触屏页面上下滑动(一)

    最近做的做那个app的项目由于用overflow:hidden导致了很多问题,于是决定研究下html5的touch事件.想找个全面点的帖子真是难死了,虽然好多关于html5 touch的文章但大多都是 ...

  4. MonkeyRunner 连续两次点击报“Error sending touch event”

    最近用monkeyrunner做自动化测试,遇到连续两次点击,第二次点击就会报错“Error sending touch event”. 具体做法如下: device.touch(234,112, ' ...

  5. IOS touch event animation 转动的风车

    最近开始学习IOS的开发,师兄给我提出一个需求:实现一个可拖动的转盘.师兄提示我说利用touch event和UIView animation.经过一两天的折腾边学边做,算是实现了基本功能.这里写写加 ...

  6. taro 小程序 & touch event 转换 bug

    taro 小程序 & touch event 转换 bug before after 事件处理 https://nervjs.github.io/taro/docs/event.html#do ...

  7. 通过html5 touch事件封装手势识别组件

    html5移动端新增了touchstart,touchmove,touchend事件,利用这3个事件,判断手指的点击和划动轨迹,我们可以封装各种手势的识别功能, 这3个事件和pc端的mousedown ...

  8. android 的touch event分析

    android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进行深入的了解.   一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN ...

  9. html5中event获取data和class

    获取data和class var tare=$(e.relatedTarget).data("id");var tar=event.target;console.log(tare) ...

随机推荐

  1. PHP 常识

    PHP常识 1.谈谈你对MVC的认识,介绍几种目前比较流行的框架 由Model(M),View(V),Cntroller(C) 组成的一种设计模式,Model 主要处理一些业务处理类,View是页面显 ...

  2. opencv 相关一个很好的博客

    http://blog.csdn.net/zouxy09/article/category/1218765 图像卷积与滤波的一些知识点 图像卷积与滤波的一些知识点zouxy09@qq.comhttp: ...

  3. listview去掉条目间的分割线

    未去掉前: 去掉后: java代码可以这么写: 1          listView.setDivider(null);//去掉条目间的分割线 PS:ListView的几个常用操作 listView ...

  4. 休眠唤醒不断开wifi.

    文件: /home/mxy/code/v1/frameworks/base/services/java/com/auto/opandora/Opandora.java 屏蔽掉: 957 SetWifi ...

  5. WINCE下进程间通信(一)

    WINCE下进程间通信(一) 在WINCE开发中经常需要在不同的进程之间传递.共享数据,总结了一下,WINCE下进程间通信常用的方式有:Windows消息,共享内存,socket通信,管道,全局原子, ...

  6. kali系统安装

    kali live 安装到U盘 http://www.backtrack.org.cn/thread-17197-1-1.html 用Live U盘安装Kali Linux http://cn.doc ...

  7. 【HighCharts系列教程】二、Highcharts结构及API文档

    一.你必须知道的 1.首先,HighCharts是基于Jquery框架开发的,所以需要在页面引入Jquery,具体代码是: <script type="text/javascript& ...

  8. word 书签排序算法

    直接上代码 /// <summary> /// 通过计算插入引文的位置格式化合适的引文序号 /// </summary> /// <returns></ret ...

  9. HDU 1828 POJ 1177 Picture

    矩形周长并 POJ上C++,G++都能过,HDU上C++过了,G++WA ,不知道为什么 #include<cstdio> #include<cstring> #include ...

  10. HDU 4408 Minimum Spanning Tree 最小生成树计数

    Minimum Spanning Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...