Html5 touch event
HTML5 for the Mobile Web: Touch Events
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).
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:
- Find the canvas element in the DOM
var canvas = document.getElementById('mycanvas');
- 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");
- 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 touchend
event, 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.com, DeviceAtlas, mobilehtml5.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
- W3C HTML5 Touch Events Specification
- Multi-touch Web Development by Rob Smus on HTML5Rocks.com
- Touch And Mouse by Chris Wilson and Paul Kinlan
- Hammer.js - a JavaScript library for multi-touch gestures by Jorik Tangelder
Download
The code examples in this article can be downloaded below.
Attachment | Size |
---|---|
touch-demos.zip | 2.06 KB |
Html5 touch event的更多相关文章
- Touch Event
转自: http://hi.baidu.com/masaiui/item/971775e8b316238bc10d754b 参考: http://hedgehogking.com/?p=55 ...
- html5 touch事件实现触屏页面上下滑动(二)
五一小长假哪都没去,睡了三天,今天晕晕沉沉的投入工作了,但还是做出了一点点效果 上周用html5的touch事件把简单的滑动做出来了,实现了持续页面上下滑动的效果,参考之前 的文章及代码html5 t ...
- html5 touch事件实现触屏页面上下滑动(一)
最近做的做那个app的项目由于用overflow:hidden导致了很多问题,于是决定研究下html5的touch事件.想找个全面点的帖子真是难死了,虽然好多关于html5 touch的文章但大多都是 ...
- MonkeyRunner 连续两次点击报“Error sending touch event”
最近用monkeyrunner做自动化测试,遇到连续两次点击,第二次点击就会报错“Error sending touch event”. 具体做法如下: device.touch(234,112, ' ...
- IOS touch event animation 转动的风车
最近开始学习IOS的开发,师兄给我提出一个需求:实现一个可拖动的转盘.师兄提示我说利用touch event和UIView animation.经过一两天的折腾边学边做,算是实现了基本功能.这里写写加 ...
- taro 小程序 & touch event 转换 bug
taro 小程序 & touch event 转换 bug before after 事件处理 https://nervjs.github.io/taro/docs/event.html#do ...
- 通过html5 touch事件封装手势识别组件
html5移动端新增了touchstart,touchmove,touchend事件,利用这3个事件,判断手指的点击和划动轨迹,我们可以封装各种手势的识别功能, 这3个事件和pc端的mousedown ...
- android 的touch event分析
android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进行深入的了解. 一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN ...
- html5中event获取data和class
获取data和class var tare=$(e.relatedTarget).data("id");var tar=event.target;console.log(tare) ...
随机推荐
- js的阻塞特性
JS具有阻塞特性,当浏览器在执行js代码时,不能同时做其它事情,即<script>每次出现都会让页面等待脚本的解析和执行(不论JS是内嵌的还是外链的),JS代码执行完成后,才继续渲染页面. ...
- jquery给img添加按钮事件
1. img控件加id <a href="#"><img width="20" height="20" id=" ...
- Mysql获取去重后的总数
如果一张表中某个字段存在重复的值,现在我想去重后获取这个字段值的总数 先看这张表 这张表中的openid有重复值 怎么通过sql语句获取openid的去重总数呢 select count(distin ...
- UITableviewCell 重用内存
转载自:http://www.cnblogs.com/tangbinblog/p/3371545.html 重用实现分析 查看UITableView头文件,会找到NSMutableArray* vi ...
- AES加密,解决了同步问题,和随机密钥和固定密钥,多端通信加密不一致解决办法
1.密钥随机生成. import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyEx ...
- 数据库建表的时候报 “1215 Cannot add foreign key constraint”
很大原因是因为: 引用表中的字段类型和被引用的主键的类型不统一. 比如说学生表中有一个班级ID字段引用班级表. 班级表的ID是int类型,学生表中的班级ID是Varchar类型. 肯定会提示上述121 ...
- 对Java配置文件Properties的读取、写入与更新操作
http://breezylee.iteye.com/blog/1340868 对Java配置文件Properties的读取.写入与更新操作 博客分类: javase properties 对Jav ...
- 《accelerated c++》第九章---设计类
本章简单介绍了类的设计,但是包含了一些好的设计原则. 1一些通用的设计原则 (1)一个函数是否设计成成员函数的原则:如果这个函数改变对象的状态,那么这个函数就应该成为这个对象的成员. (2)对于内置类 ...
- ecstore中kvstore之memcached
memcached的安装 详细见 http://blog.csdn.net/motian06/article/details/17558831 memcached扩展的安装 详细见 http://bl ...
- higncharts 去掉Highcharts.com链接
将credits属性设为false credits: { enabled: false },