[重要更新:本文发布后,由于稳定性错误,Firefox Nightly 中已禁用指针事件。此错误修复后,将重新启用指针事件。您仍然可以通过在 about:config
中将 dom.w3c_pointer_events.enabled
设置为“true”来在 Firefox 中测试指针事件。]
今年 2 月,指针事件 成为 W3C 推荐标准。在此期间,Microsoft Open Tech 和 Mozilla 一直在合作实施该规范。随着消费者不断扩展用于探索 Web 的设备范围,并使用触摸、笔或鼠标等不同的输入机制,提供一个统一的 API 供开发人员在其应用程序中使用变得至关重要。在这项工作中,我们刚刚取得了一个重要的里程碑:指针事件现已在 Firefox Nightly 中可用。我们对这项工作感到非常兴奋,它代表了多个浏览器供应商之间的大量合作,旨在产出一个高质量的行业标准 API,并获得越来越广泛的支持。
请务必下载 Firefox Nightly 并试用,并通过 dev-platform 邮件列表或 mozilla.dev.platform 组向我们提供有关实现的反馈。如果您对规范有任何反馈,请发送至 public-pointer-events@w3.org。
此规范的目的是扩展开放 Web 以支持除鼠标之外的各种输入机制,同时保持与大多数基于 Web 的内容的兼容性,这些内容是围绕 鼠标事件 构建的。该 API 旨在创建一个可以处理各种输入设备的解决方案,重点是点设备(鼠标、笔和触摸)。规范中将指针定义为一种与硬件无关的设备,可以定位特定的一组屏幕坐标。指针事件在设计上与当前与鼠标事件关联的事件集相似。
在当前的 Nightly 版本中,现已支持鼠标输入的指针事件。此外,如果您使用的是 Windows,则设置两个首选项后,现在可以启用触摸事件。第一个属性,异步平移和缩放 (APZ),通过将 layers.async-pan-zoom.enabled
Firefox 配置首选项 设置为 true 来启用。还应通过将此值设置为 1 来启用 dom.w3c_touch_events.enabled
首选项。
这篇文章介绍了新 API 的一些基本功能。
使用指针 API
在开始使用指针 API 之前,务必测试当前浏览器是否支持该 API。这可以通过类似于以下示例的代码来完成
if (window.PointerEvent) {
.....
}else{
// use mouse events
}
指针 API 提供了对 pointerdown, pointerup, pointercancel, pointermove, pointerover, pointerout, gotpointercapture,
和 lostpointercapture
事件的支持。如果您以前编写过鼠标输入的事件处理代码,那么大多数这些事件应该都很熟悉。例如,如果您需要一个 Web 应用程序在触摸或单击画布时移动图像,则可以使用以下代码
function DragImage() {
var imageGrabbed = false;
var ctx;
var cnv;
var myImage;
var x = 0;
var y = 0;
var rect;
this.imgMoveEvent = function(evt) {
if (imageGrabbed) {
ctx.clearRect(0, 0, cnv.width, cnv.height);
x = evt.clientX - rect.left;
y = evt.clientY - rect.top;
ctx.drawImage(myImage, x, y, 30, 30);
}
}
this.imgDownEvent = function(evt) {
//Could use canvas hit regions
var xcl = evt.clientX - rect.left;
var ycl = evt.clientY - rect.top;
if (xcl > x && xcl < x + 30 && ycl > y && ycl < y + 30) {
imageGrabbed = true;
}
}
this.imgUpEvent = function(evt) {
imageGrabbed = false;
}
this.initDragExample = function() {
if (window.PointerEvent) {
cnv = document.getElementById("myCanvas");
ctx = cnv.getContext('2d');
rect = cnv.getBoundingClientRect();
x = 0;
y = 0;
myImage = new Image();
myImage.onload = function() {
ctx.drawImage(myImage, 0, 0, 30, 30);
};
myImage.src = 'images/ff.jpg';
cnv.addEventListener("pointermove", this.imgMoveEvent, false);
cnv.addEventListener("pointerdown", this.imgDownEvent, false);
cnv.addEventListener("pointerup", this.imgUpEvent, false);
}
}
}
PointerCapture
事件用于指针设备可能在跟踪事件时离开现有元素区域的情况。例如,假设您正在使用滑块,并且您的手指从实际元素上滑落 - 您需要继续跟踪指针移动。您可以使用类似于以下的代码设置 PointerCapture
var myElement = document.getElementById("myelement");
myelement.addEventListener("pointerdown", function(e) {
if (this.setPointerCapture) {
//specify the id of the point to capture
this.setPointerCapture(e.pointerId);
}
}, false);
此代码保证您仍然会收到 pointermove
事件,即使您离开 myelement
的区域也是如此。如果您没有设置 PointerCapture
,则当您的指针离开其区域时,包含元素将不会调用指针移动事件。您还可以通过调用 releasePointerCapture
来释放捕获。当 pointerup
或 pointercancel
事件发生时,浏览器会自动执行此操作。
指针事件接口
PointerEvent
接口扩展了 MouseEvent
接口,并提供了一些其他属性。这些属性包括 pointerId, width, height, pressure, tiltX, tiltY, pointerType
和 isPrimary
。
pointerId
属性为启动事件的指针提供了唯一的 ID。height
和 width
属性分别以 CSS 像素为单位提供了指针接触几何形状的值。当指针碰巧是鼠标时,这些值将设置为 0。pressure
属性包含一个从 0 到 1 的浮点值,以指示指针施加的压力量,其中 0 为最低,1 为最高。对于不支持压力的指针,该值将设置为 0.5。
tiltY
属性包含指针的 X-Z 平面与屏幕之间的角度值,范围在 -90 到 90 度之间。此属性在使用触控笔进行指针操作时最有用。0 度的值表示指针以相对于 Y 轴的精确垂直角度接触表面。同样,tiltX
属性包含 Y-Z 平面之间的角度。
pointType
属性包含指针表示的设备类型。当前,此值将设置为 mouse, touch, pen, unknown
或空字符串。
var myElement = document.getElementById("myelement");
myElement.addEventListener("pointerdown", function(e) {
switch(e.pointerType) {
case "mouse":
console.log("Mouse Pointer");
break;
case "pen":
console.log("Pen Pointer");
break;
case "touch":
console.log("Touch Pointer");
break;
default:
console.log("Unknown Pointer");
}
}, false);
isPrimary
属性为 true
或 false
,指示指针是否为主指针。当支持多个触摸点以提供多点触控输入和手势支持时,需要主指针属性。当前,当指针首次与跟踪指针事件的元素接触时,此属性将为每种特定指针类型(鼠标、触摸、笔)设置为 true
。如果您同时使用一个触摸点和一个鼠标指针,则两者都将设置为 true
。如果另一个指针已使用相同的 pointerType
处于活动状态,则事件的 isPrimary
属性将设置为 false
。
var myElement = document.getElementById("myelement");
myelement.addEventListener("pointerdown", function(e) {
if( e.pointerType == "touch" ){
if( e.isPrimary ){
//first touch
}else{
//handle multi-touch
}
}
}, false);
处理多点触控
如前所述,触摸指针目前仅在运行 Windows 的 Firefox Nightly 上实现,并且启用了 layers.async-pan-zoom.enabled
和 dom.w3c_touch_events.enabled
首选项。您可以使用以下代码检查是否支持多点触控。
if( window.maxTouchPoints && window.maxTouchPoints > 1 ){
//supports multi-touch
}
某些浏览器为某些触摸交互提供了默认功能,例如使用滑动手势滚动或使用捏合手势进行缩放控制。当使用这些默认操作时,不会触发指针的事件。为了更好地支持不同的应用程序,Firefox Nightly 支持 CSS 属性 touch-action
。此属性可以设置为 auto, none, pan-x, pan-y
和 manipulation
。将此属性设置为 auto
不会在使用触摸事件时更改浏览器的任何默认行为。要禁用所有默认行为并允许您的内容改为使用指针事件处理所有触摸输入,您可以将此值设置为 none
。将此值设置为 pan-x
或 pan-y
会在未在给定方向上平移/滚动时调用所有指针事件。例如,pan-x
在未在水平方向上平移/滚动时会调用指针事件处理程序。当属性设置为 manipulation
时,如果未发生平移/滚动或缩放操作,则会触发指针事件。
// Very Simplistic pinch detector with little error detection,
// using only x coordinates of a pointer event
// Currently active pointers
var myPointers = [];
var lastDif = -1;
function myPointerDown(evt) {
myPointers.push(evt);
this.setPointerCapture(evt.pointerId);
console.log("current pointers down = " + myPointers.length);
}
//remove touch point from array when touch is released
function myPointerUp(evt) {
// Remove pointer from array
for (var i = 0; i < myPointers.length; i++) {
if (myPointers[i].pointerId == evt.pointerId) {
myPointers.splice(i, 1);
break;
}
}
console.log("current pointers down = " + myPointers.length);
if (myPointers.length < 2) {
lastDif = -1;
}
}
//check for a pinch using only the first two touchpoints
function myPointerMove(evt) {
// Update pointer position.
for (var i = 0; i < myPointers.length; i++) { if (evt.pointerId = myPointers[i].pointerId) { myPointers[i] = evt; break; } } if (myPointers.length >= 2) {
// Detect pinch gesture.
var curDif = Math.abs(myPointers[0].clientX - myPointers[1].clientX);
if (lastDif > 0) {
if (curDif > lastDif) { console.log("Zoom in"); }
if (curDif < lastDif) { console.log("Zoom out"); }
}
lastDif = curDif;
}
}
您可以 在此处测试示例代码。有关指针事件 API 在实际应用中的一些出色示例,请参阅 Patrick H. Lauke 在 GitHub 上收集的 触摸和指针事件实验。Patrick 是 W3C 指针事件工作组、W3C 触摸事件社区组的成员,以及 Paciello Group 的高级无障碍顾问。
结论
在这篇文章中,我们介绍了目前在 Firefox Nightly 中实现的一些基础知识。要跟踪此 API 的进度,请查看 Gecko 触摸 Wiki 页面。您还可以关注主要 功能错误,并确保在测试新的指针 API 时报告您发现的任何问题。
17 条评论