mobiforge.com/design-deve…javascript
(本翻译未彻底按照原文进行,由于老外太多废话!)
Pointer Events API 是Hmtl5的事件规范之一,它主要目的是用来将鼠标(Mouse)、触摸(touch)和触控笔(pen)三种事件整合为统一的API。css
相比Touch Events API,虽然目前除了Apple的 Safari浏览器,其余浏览器都在实现对该事件类型的支持,可是状况并非很好。
本篇文章忽略浏览器的兼容问题,只讨论其基本使用方法。更多内容能够参考:Pointer Events 背景资料。html
和 Touch Events API 对应于触摸事件相似,Pointer Events API则对应于Pointer事件,那么什么是Pointer呢?前端
Pointer 是指能够在屏幕上反馈一个指定坐标的输入设备。html5
Pointer Events继承并扩展了Mouse Event,因此它拥有Mouse Event的经常使用属性,好比 clientX, clientY等等,同时也增长了一些新的属性,好比tiltX, tiltY, 和 pressure等等。咱们对Pointer的以下属性更感兴趣:java
属性 | 说明 |
---|---|
pointerId |
惟一数值类型标识符 |
screenX |
相对于用户屏幕的x坐标 |
screenY |
相对于用户屏幕的y坐标 |
clientX |
相对于当前窗口的x坐标,不包含滚动条的滚动距离 |
clientY |
相对当前窗口的y坐标,不包含滚动条的滚动距离 |
pageX |
相对于页面的x坐标, 包含滚动条的滚动距离 |
pageY |
相对于页面的y坐标, 包含滚动条的滚动距离 |
width |
pointer在屏幕上接触范围的宽度 |
height |
pointer在屏幕上接触范围的高度 |
tiltX |
触控介质沿Z轴方向与x轴的偏转角度, x,y坐标轴构成的平面为屏幕表面 |
tiltY |
触控介质沿Z轴方向与y轴的偏转角度, x,y坐标轴构成的平面为屏幕表面 |
pressure |
按压值 |
pointerType |
Pointer 类别: mouse, pen, 或者touch |
isPrimary |
是不是主Pointer设备 |
这里有几点须要注意的地方:web
. pointerId:表明每个独立的Pointer。根据id,咱们能够很轻松的实现多点触控应用。\
. width/height:Mouse Event 在屏幕上只能覆盖一个点的位置,可是一个Pointer可能覆盖一个更大的区域。\
. isPrimary:当有多个Pointer被检测到的时候(好比多点触摸),对每一种类型的Pointer会存在一个Primary Poiter。只有Primary Poiter会产生与之对应的Mouse Event。稍后会讨论更多与此有关的内容。\
. pressure/tilt/width/height: :这些特性,使程序支持更复杂的操做成为可能。canvas
下面是PointerEvent Api 定义的核心事件:api
事件类型 | 触发时机 |
---|---|
pointerover |
pointer移动到一个元素所在区域的时候 |
pointerenter |
pointer 移动到一个元素或者其后代元素所在区域的时候. |
pointerdown |
激活按钮状态 被赋值为非0值: 对于触摸或触控笔是指和屏幕产生接触的时候; 对于鼠标是指一个按键被按下的时候 |
pointermove |
pointer 改变了所在坐标, 或者 按压, 倾斜时,或者触发了没有在规范中定义的其余类型事件 |
pointerup |
active buttons state 值为 left: 触控笔或者手指离开屏幕, 或者释放鼠标按键 |
pointercancel |
检测到当前pointer结束操做的时候, 好比改变方向, 触控点太多等意外输入 |
pointerout |
pointer移出一个元素所在区域.在不支持hover的设备上当 pointerup 事件和pointercancel 事件被触发后触发 |
pointerleave |
pointer 离开元素或者起后代元素后 |
gotpointercapture |
当一个元素成为pointer的目标元素的时候 |
lostpointercapture |
当元素不在成为pointer的目标元素的时候 |
Mouse event | Touch event | Pointer event |
---|---|---|
mousedown |
touchstart |
pointerdown |
mouseenter |
pointerenter |
|
mouseleave |
pointerleave |
|
mousemove |
touchmove |
pointermove |
mouseout |
pointerout |
|
mouseover |
pointerover |
|
mouseup |
touchend |
pointerup |
Mouse Event 和Point Event作一个对等关系很容易,可是Touch Event就没那么乐观了。可是上面的表格只是一个粗略的对照关系,相对应的事件在具体实现和含义上并不彻底相同。这意味着你不能使用同一个处理函数来处理不一样类型的事件,除非你明确的知道你在干什么,由于这些事件的运做方式不一样。例如touchmove 事件的目标元素是touch began 时的元素,即便move的过程当中触点不在该元素区域内,touchemove的目标元素仍然不会改变;可是mousemove 和 pointermove的目标元素是位于触点下方的元素,离开该元素区域,目标元素就会改变。数组
Poiter API的强大之处在于它对Mouse Event的兼容,使得基于Mouse Event的站点能够很好的运行。固然这是有意为之,为了达到这个目的,当Pointer Event被触发以后,会再次触发一个对应的Mouse Event。固然只有被认定为主Pointer(primary Pointer)的Pointer才会继续触发Mouse Event。某种程度上,你能够认为在同一时间只有一个鼠标输入。基于Mouse Event 的网站,原有的处理逻辑无需改动,只须要添加新的针对Touch Event的处理逻辑便可。
Poiter API 整合了鼠标、触摸和触控笔的输入,使得咱们无需对各类类型的事件区分对待。
目前不管是web仍是本地应用都被设计成跨终端(手机,平板,PC)应用,鼠标多数应用在桌面应用,触摸则出如今各类设备上。过去开发人员必须针对不一样的输入设备写不一样的代码,或者写一个polyfill 来封装不一样的逻辑。Pointer Events 改变了这种情况:
统一事件监听,不用再分别处理\
不用为获取不一样事件的坐标值写不一样的代码\
若是输入设备支持,能够获取压力、宽、高、倾斜角度等参数\
若是须要的话能够区别对待不一样是事件类型
下面是各类事件Api的对比。
Mouse Events | Touch Events | Pointer Events | |
支持鼠标 | Y | P | Y |
支持单点触控 | P | Y | Y |
支持多点触控 | N | Y | Y |
支持 笔, Kinect, 其余输入设备 | P | N | Y |
提供对 over/out/enter/leave events 和 hover 的支持 | Y | N | Y |
异步 panning/zooming 硬件加速 | N | N | Y |
W3C 标准 | Y | Y | Y |
在本篇文章中,咱们只展现Pointer Event Api的基本使用。第一件要作的事情是检测浏览器是否支持Pointer Event。
if (window.PointerEvent) {
// Pointer events are supported.
}复制代码
第一个demo,咱们建立Pointer Event的事件监听程序,打印输入点的坐标值。咱们建立两个div,一个用来捕获Pointer事件,另外一个用来展示坐标值。
<div id="coords"></div>
<div id="pointerzone"></div>复制代码
接下来添加事件监听的代码:
function init() {
// Get a reference to our pointer div
var pointerzone = document.getElementById("pointerzone");
// Add an event handler for the pointerdown event
pointerzone.addEventListener("pointerdown", pointerHandler, false);
}复制代码
在pointerHandler函数中,获取并展示pointer事件的坐标值:
function pointerHandler(event) {
// Get a reference to our coordinates div
var coords = document.getElementById("coords");
// Write the coordinates of the pointer to the div
coords.innerHTML = 'x: ' + event.pageX + ', y: ' + event.pageY;
}复制代码
咱们确保在页面加载完成后执行init函数。
<body onload="init()">
...
</body>
}复制代码
如今能够在浏览器打开页面了,若是你的浏览器支持pointer event,单击鼠标,就能够在页面看到输出的坐标值了。
和使用touch api的touchmove
事件同样,咱们可使用pointermove
事件来处理移动事件。
下面咱们设计咱们的demo:当捕获一个pointerdown 事件的时候,咱们开始追踪pointer的移动轨迹。因此咱们首先要监听pointerdown
事件,而后在pointerdown
事件的处理函数中添加对pointermove
事件的监听。
canvas.addEventListener("pointerdown", function() {
canvas.addEventListener("mousemove", drawpointermove, false);
}
, false);复制代码
在drawpointermove函数中,咱们根据先后两个点的坐标,来连续绘制轨迹。
function draw(e) {
ctx.beginPath();
// Start at previous point
ctx.moveTo(lastPt.x, lastPt.y);
// Line to latest point
ctx.lineTo(e.pageX, e.pageY);
// Draw it!
ctx.stroke();
//Store latest pointer
lastPt = {x:e.pageX, y:e.pageY};
}复制代码
当pointer路径结束的时候——用户移开了手指或者笔尖,松开了鼠标按钮——咱们须要中止绘图。因此咱们须要监听pointerup
事件,并添加一个endPointer
处理函数。
canvas.addEventListener("pointerup", endPointer, false);
function endPointer(e) {
//Stop tracking the pointermove event
canvas.removeEventListener("pointermove", drawpointermove, false);
//Set last point to null to end our pointer path
lastPt = null;
}复制代码
运行结果:
下面给出这个demo的完整代码:
<html>
<head>
<style> /* Disable intrinsic user agent touch behaviors (such as panning or zooming) */ canvas { touch-action: none; } </style>
<script type='text/javascript'> var lastPt = null; var canvas; var ctx; function init() { canvas = document.getElementById("mycanvas"); ctx = canvas.getContext("2d"); var offset = getOffset(canvas); if(window.PointerEvent) { canvas.addEventListener("pointerdown", function() { canvas.addEventListener("pointermove", draw, false); } , false); canvas.addEventListener("pointerup", endPointer, false); } else { //Provide fallback for user agents that do not support Pointer Events canvas.addEventListener("mousedown", function() { canvas.addEventListener("mousemove", draw, false); } , false); canvas.addEventListener("mouseup", endPointer, false); } } // Event handler called for each pointerdown event: function draw(e) { if(lastPt!=null) { ctx.beginPath(); // Start at previous point ctx.moveTo(lastPt.x, lastPt.y); // Line to latest point ctx.lineTo(e.pageX, e.pageY); // Draw it! ctx.stroke(); } //Store latest pointer lastPt = {x:e.pageX, y:e.pageY}; } function getOffset(obj) { //... } function endPointer(e) { //Stop tracking the pointermove (and mousemove) events canvas.removeEventListener("pointermove", draw, false); canvas.removeEventListener("mousemove", draw, false); //Set last point to null to end our pointer path lastPt = null; } </script>
</head>
<body onload="init()">
<canvas id="mycanvas" width="500" height="500" style="border:1px solid black;"></canvas>
</body>
</html>复制代码
这个例子中,咱们扩展上面的pointmove事件的代码,来实现对多点触控的支持。
首先咱们初始一个多个颜色的数组,用来追踪不一样的pointer。
var colours = ['red', 'green', 'blue', 'yellow','black'];复制代码
画线的时候经过pointer的id来取色。
//Key the colour based on the id of the Pointer
multitouchctx.strokeStyle = colours[id%5];
multitouchctx.lineWidth = 3;复制代码
在这个demo中,咱们要追踪每个pointer,因此须要分别保存每个pointer的相关坐标点。这里咱们使用关联数组来存储数据,每一个数据使用pointerId作key,咱们使用一个Object对象做为关联数组,用以下方法添加数据:
// This will be our associative array
var multiLastPt=new Object();
...
// Get the id of the pointer associated with the event
var id = e.pointerId;
...
// Store coords
multiLastPt[id] = {x:e.pageX, y:e.pageY};复制代码
结束画线的时候,须要删除相关数据。
delete multiLastPt[id];复制代码
运行结果以下:
完整代码以下:
<!DOCTYPE html>
<html> <head> <title>HTML5 multi-touch</title> <style> canvas { touch-action: none; } </style> <script> var canvas; var ctx; var lastPt = new Object(); var colours = ['red', 'green', 'blue', 'yellow', 'black']; function init() { canvas = document.getElementById('mycanvas'); ctx = canvas.getContext("2d"); if(window.PointerEvent) { canvas.addEventListener("pointerdown", function() { canvas.addEventListener("pointermove", draw, false); } , false); canvas.addEventListener("pointerup", endPointer, false); } else { //Provide fallback for user agents that do not support Pointer Events canvas.addEventListener("mousedown", function() { canvas.addEventListener("mousemove", draw, false); } , false); canvas.addEventListener("mouseup", endPointer, false); } } function draw(e) { var id = e.pointerId; if(lastPt[id]) { ctx.beginPath(); ctx.moveTo(lastPt[id].x, lastPt[id].y); ctx.lineTo(e.pageX, e.pageY); ctx.strokeStyle = colours[id%5]; ctx.stroke(); } // Store last point lastPt[id] = {x:e.pageX, y:e.pageY}; } function endPointer(e) { var id = e.pointerId; canvas.removeEventListener("mousemove", draw, false); // 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>复制代码
本文只是简单介绍了Pointer Event的使用,虽然目前浏览器的支持状况并不完美,可是做为w3c的标准,会被支持的愈来愈好。
若是你在开发中使用Pointer Event Api,必定要注意它和touch事件的区别,处理touch相关操做的时候要谨慎。
欢迎关注玄魂工做室--订阅号回复“html5”,更多前端开发知识