Pointer events 指针事件

翻译正在进行中。

目前绝大多数的Web内容都假设用户的指针定点设备为鼠标。然而,近年来的新兴设备支持更多不同方式的指针定点输入,如各类触控笔和触摸屏幕等。这就有必要扩展现存的定点设备事件模型,以有效追踪各类指针事件

指针事件 - Pointer events 是一类可以为定点设备所触发的DOM事件。它们被用来创建一个可以有效掌握各类输入设备(鼠标、触控笔和单点或多点的手指触摸)的统一的DOM事件模型。所谓 指针 是指一个可以明确指向屏幕上某一组坐标的硬件设备。建立这样一个单独的事件模型可以有效的简化Web站点与应用所需的工作,同时也便于提供更加一致与良好的用户体验,无需关心不同用户和场景在输入硬件上的差异。而且,对于某些特定设备才可处理的交互情景,指针事件也定义了一个 pointerType 属性以使开发者可以知晓该事件的触发设备,以有针对性的加以处理。

这些事件需要能够处理 mouse events 之类较为通用的指针输入(mousedown/pointerdown, mousemove/pointermove, 等)。 因此,指针事件的类型,很大程度上类似于当前的鼠标事件类型。此外,一个指针事件,也同时包含了鼠标事件中所常见的属性(client coordinates, target element, button states,等)以及适用于其他输入设备的新属性:pressure, contact geometry, tilt, 等等。实际上,PointerEvent 接口继承了所有 MouseEvent 中的属性,以保障原有为鼠标事件所开发的内容能更加有效的迁移到指针事件。

名词表

活跃指针 - active pointer
任意指针输入设备都可以产生事件。一个可以产生后继事件的指针可以被认为是一个活跃指针。例如,一个触摸笔处于压下状态时可以认为是活跃的,因为它接下来的抬起或移动都会产生额外的后继事件。
数位设备 - digitizer
一个可以检测其表面接触行为的传感设备。通常来说,其所用的传感设备是一个可以感知由某些输入设备(如触控笔、压感笔、手指等)所提供的输入信息的可触摸屏幕。
命中检测 - hit test
浏览器用以检测某一指针事件的目标元素的过程。通常来说,这一过程是通过比照出现在文档或屏幕媒介上的指针位置与视觉布局来实现的。
指针 - pointer
某个呈现形式并不确定的硬件,该硬件可以指向一个(或一组)屏幕上特定坐标。典型的指针输入设备有鼠标、触控笔、手指触控点等。
指针捕捉 - pointer capture
指针捕捉能够允许某些事件的产生。这些事件在指针将要重新指向一些并非通过命中检测而给定元素时触发。
指针事件 - pointer event
一个被指针触发DOM事件。

相关接口

首要的接口为 PointerEvent 接口,该接口由一个构造函数constructor 加上一些事件类型以及相应全局事件的处理方法构成。

标准中还包括一些对于 ElementNavigator 接口的扩展。接下来的每个部分包含了对于各个接口与属性的简单说明。

PointerEvent 接口

PointerEvent 接口扩展了 MouseEvent 接口,并含有以下属性(这些属性的可写属性全部为 只读 )。

  • pointerId - a unique identifier for the pointer causing the event.
  • width - the width (magnitude on the X axis), in CSS pixels, of the contact geometry of the pointer.
  • height - the height (magnitude on the Y axis), in CSS pixels, of the contact geometry of the pointer.
  • pressure - the normalized pressure of the pointer input in the range of 0 to 1, where 0 and 1 represent the minimum and maximum pressure the hardware is capable of detecting, respectively.
  • tiltX - the plane angle (in degrees, in the range of -90 to 90) between the Y-Z plane and the plane containing both the transducer (e.g. pen stylus) axis and the Y axis.
  • tiltY - the plane angle (in degrees, in the range of -90 to 90) between the X-Z plane and the plane containing both the transducer (e.g. pen stylus) axis and the X axis.
  • pointerType - indicates the device type that caused the event (mouse, pen, touch, etc.)
  • isPrimary - indicates if the pointer represents the primary pointer of this pointer type.

Event types and Global Event Handlers

Pointer events have ten event types, seven of which have similar semantics to their mouse event counterpart (down, up, move, over, out, enter, leave). Below is a short description of each event type and its associated Global Event Handler.

Event On Event Handler Description
pointerover onpointerover Fired when a pointing device is moved into an element's hit test boundaries.
pointerenter onpointerenter Fired when a pointing device is moved into the hit test boundaries of an element or one of its descendants, including as a result of a pointerdown event from a device that does not support hover (see pointerdown).
pointerdown onpointerdown Fired when a pointer becomes active.
pointermove onpointermove Fired when a pointer changes coordinates.
pointerup onpointerup Fired when a pointer is no longer active.
pointercancel onpointercancel A browser fires this event if it concludes the pointer will no longer be able to generate events (for example the related device is deactived).
pointerout onpointerout Fired for several reasons including: pointing device is moved out of the hit test boundaries of an element; firing the pointerup event for a device that does not support hover (see pointerup); after firing the pointercancel event (see pointercancel); when a pen stylus leaves the hover range detectable by the digitizer.
pointerleave onpointerleave Fired when a pointing device is moved out of the hit test boundaries of an element. For pen devices, this event is fired when the stylus leaves the hover range detectable by the digitizer.
gotpointercapture ongotpointercapture Fired when an element receives pointer capture.
lostpointercapture onlostpointercapture Fired after pointer capture is released for a pointer.

Element extensions

There are three extensions to the Element interface:

  • setPointerCapture() - this method designates a specific element as the capture target of future pointer events.
  • releasePointerCapture() - the method releases (stops) pointer capture that was previously set for a specific pointer event.

The Navigator.maxTouchPoints property is used to determine the maximum number of simultaneous touch points that are supported at any single point in time.

Examples

This section contains examples of basic usage of using the pointer events interfaces.

Registering event handlers

This example registers a handler for every event type for the given element.

<html>
  <script>
    function over_handler(event) { }
    function enter_handler(event) { }
    function down_handler(event) { }
    function move_handler(event) { }
    function up_handler(event) { }
    function cancel_handler(event) { }
    function out_handler(event) { }
    function leave_handler(event) { }
    function gotcapture_handler(event) { }
    function lostcapture_handler(event) { }

    function init() {
      var el=document.getElementById("target");
      // Register pointer event handlers
      el.onpointerover = over_handler;
      el.onpointerenter = enter_handler;
      el.onpointerdown = down_handler;
      el.onpointermove = move_handler;
      el.onpointerup = up_handler;
      el.onpointercancel = cancel_handler;
      el.onpointerout = out_handler;
      el.onpointerleave = leave_handler;
      el.gotpointercapture = gotcapture_handler;
      el.lostpointercapture = lostcapture_handler;
    }
  </script>
  <body onload="init();">
    <div id="target"> Touch me ... </div>
  </body>
</html>

Event properties

This example illustrates accessing all of a touch event's properties.

<html>
  <script>
    var id = -1;

    function process_id(event) {
      // Process this event based on the event's identifier
    }
    function process_mouse(event) {
      // Process the mouse pointer event
    }
    function process_pen(event) {
      // Process the pen pointer event
    }
    function process_touch(event) {
      // Process the touch pointer event
    }
    function process_tilt(tiltX, tiltY) {
      // Tilt data handler
    }
    function process_pressure(pressure) {
      // Pressure handler
    }
    function process_non_primary(event) {
      // Pressure handler
    }

    function down_handler(ev) { 
      // Calculate the touch point's contact area
      var area = ev.width * ev.height;

      // Compare cached id with this event's id and process accordingly
      if (id == ev.identifier) process_id(ev);

      // Call the appropriate pointer type handler
      switch (ev.pointerType) {
        case "mouse": 
          process_mouse(ev); 
          break;
        case "pen": 
          process_pen(ev); 
          break;
        case "touch": 
          process_touch(ev); 
          break;
        default:
        console.log("pointerType " + ev.pointerType + " is Not suported");
      }

      // Call the tilt handler
      if (ev.tiltX != 0 && ev.tiltY != 0) process_tilt(ev.tiltX, ev.tiltY);

      // Call the pressure handler
      process_pressure(ev.pressure);

      // If this event is not primary, call the non primary handler
      if (!ev.isPrimary) process_non_primary(evt);
    }

    function init() {
      var el=document.getElementById("target");
      // Register pointerdown handler
      el.onpointerdown = down_handler;
    }
  </script>
  <body onload="init();">
    <div id="target"> Touch me ... </div>
  </body>
</html>

Determining the Primary Pointer

In some scenarios there may be multiple pointers (for example a device with both a touchscreen and a mouse) or a pointer supports multiple contact points (for example a touchscreen that supports multiple finger touches). The application can use the isPrimary property to identify a master pointer among the set of active pointers for each pointer type. If an application only wants to support a primary pointer, it can ignore all pointer events that are not primary.

For mouse there is only one pointer, so it will always be the primary pointer. For touch input, a pointer is considered primary if the user touched the screen when there were no other active touches. For pen and stylus input, a pointer is considered primary if the user's pen initially contacted the screen when there were no other active pens contacting the screen.

Determining button states

Some pointer devices, such as mouse and pen, support multiple buttons and the button presses can be chorded i.e. depressing an additional button while another button on the pointer device is already depressed. To determine the state of button presses, pointer events uses the button and buttons properties of the MouseEvent interface (that PointerEvent inherits from). The following table provides the values of button and buttons for the various device button states.

Device Button State button buttons
Mouse move with no buttons pressed -1 0
Left Mouse, Touch Contact, Pen contact (with no modifier buttons pressed) 0 1
Middle Mouse 1 4
Right Mouse, Pen contact with barrel button pressed 2 2
X1 (back) Mouse 3 8
X2 (forward) Mouse 4 16
Pen contact with eraser button pressed 5 32

Pointer capture

Pointer capture allows events for a particular pointer event to be re-targeted to a particular element instead of the normal hit test at a pointer's location. This can be used to ensure that an element continues to receive pointer events even if the pointer device's contact moves off the element (for example by scrolling).

The following example shows pointer capture being set on an element.

<html>
<script>
  function downHandler(ev) {
    var el=document.getElementById("target");
    //Element 'target' will receive/capture further events
    el.setPointerCapture(ev.pointerId);
  }

  function init() {
    var el=document.getElementById("target");
    el.onpointerdown = downHandler;
  }
</script>
<body onload="init();">
  <div id="target"> Touch me ... </div>
</body>
</html>

The following example shows a pointer capture being released (when a pointercancel event occurs. The browser does this automatically when a pointerup or pointercancel event occurs.

<html>
  <script>
    function downHandler(ev) {
      var el=document.getElementById("target");
      // Element "target" will receive/capture further events
      el.setPointerCapture(ev.pointerId);
    }

    function cancelHandler(ev) {
      var el=document.getElementById("target");
      // Release the pointer capture
      el.releasePointerCapture(ev.pointerId);
    }

    function init() {
      var el=document.getElementById("target");
      // Register pointerdown and pointercancel handlers
      el.onpointerdown = downHandler;
      el.onpointercancel = cancelHandler;
    }
  </script>
  <body onload="init();">
    <div id="target"> Touch me ... </div>
  </body>
</html>

touch-action property

The touch-action CSS property is used to specify whether or not the browser should apply its default (native) touch behavior (such as zooming or panning) to a region. This property may be applied to all elements except: non-replaced inline elements, table rows, row groups, table columns, and column groups.

A value of auto means the browser is free to apply its default touch behavior (to the specified region) and the value of none disables the browser's default touch behavior for the region. The values pan-x and pan-y, mean that touches that begin on the specified region are only for horizontal and vertical scrolling, respectively. The value manipulation means the browser may consider touches that begin on the element are only for scrolling and zooming.

In the following example, the browser's default touch behavior is disabled for the div element.

<html>
  <body>
    <div style="touch-action:none;">Can't touch this ... </div>
  </body>
</html>

In the following example, default touch behavior is disabled for some button elements.

button#tiny {
  touch-action: none;
}

In the following example, when the target element is touched, it will only pan in the horizontal direction.

#target {
  touch-action: pan-x;
}

Compatibility with mouse events

Although the pointer event interfaces enable applications to create enhanced user experiences on pointer enabled devices, the reality is the vast majority of today's web content is designed to only work with mouse input. Consequently, even if a browser supports pointer events, the browser must still process mouse events so content that assumes mouse-only input will work as is without direct modification. Ideally, a pointer enabled application does not need to explicitly handle mouse input. However, because the browser must process mouse events, there may be some compatibility issues that need to be handled. This section contains information about pointer event and mouse event interaction and the ramifications for application developers.

The browser may map generic pointer input to mouse events for compatibility with mouse-based content. This mapping of events is called compatibility mouse events. Authors can prevent the production of certain compatibility mouse events by canceling the pointerdown event but note that:

  • Mouse events can only be prevented when the pointer is down.
  • Hovering pointers (e.g. a mouse with no buttons pressed) cannot have their mouse events prevented.
  • The mouseover, mouseout, mouseenter, and mouseleave events are never prevented (even if the pointer is down).

Best practices

Here are some best practices to consider when using pointer events:

  • Minimize the amount of work done that is done in the event handlers.
  • Add the event handlers to a specific target element (rather than the entire document or nodes higher up in the document tree).
  • The target element (node) should be large enough to accommodate the largest contact surface area (typically a finger touch). If the target area is too small, touching it could result in firing other events for adjacent elements.

Implementation and deployment status

The pointer events browser compatibility data indicates pointer event support among desktop and mobile browsers is available almost everywhere except in Safari.

Some new value have been proposed for the css touch-action property as part of Pointer Events Level 2 specification but currently those new values have no implementation support.

Demos and examples

Community

文档标签和贡献者

此页面的贡献者: ldwformat
最后编辑者: ldwformat,