The features in this specification extend or modify those found in Pointer Events Level 2 that describes events and related interfaces for handling hardware agnostic pointer input from devices including a mouse, pen, touchscreen, etc.

This proposal intends to add new functionalities to a future version of the Pointer Events Level 2.

Introduction

This document reflects incubation for APIs which are intended to be part of a future version of the Pointer Events specification. They are not yet broadly supported by implementations.

The getCoalescedEvents API (similar to Android getHistorical APIs and iOS GetCoalescedTouches API) exposes all the events that were coalesced into a single event. Coalescing events into a single event enables user agents to prevent processing of the events that don’t get a chance to update the frame content visually. Basically if the javascript handlers process the events and update the screen contents faster than refresh rate only the last update will be rendered and shown in the next frame. However, some applications like drawing apps may want to take advantage of the precise history of events as user moves the pointer on the screen to be able to draw smoother and better looking curves. This API can be used in those scenarios to get all the coalesced events from the event that was dispatched to the javascript.

Extensions to the PointerEvent interface

The following section describes extensions to the existing PointerEvent interface.

partial dictionary PointerEventInit {
    sequence<PointerEvent> coalescedEvents = [];
};

partial interface PointerEvent {
    sequence<PointerEvent> getCoalescedEvents();
};
          
getCoalescedEvents

Returns a sequence of all PointerEvents that were coalesced into the dispatched pointermove event. When the event is created by the user agent the following attributes of the coalesced events will always have the same value as the dispatched event: pointerId, pointerType, isPrimary, isTrusted. Also since these coalesced events are not going to be dispatched by themselves their cancelable and bubbles attributes are false. In addition to that, the other attibutes related to the event dispatch algorithm (e.g. target, currentTarget, eventPhase) will have their default value and the related functions (e.g. stopPropagation, stopImmediatePropagation) will do nothing. But other attributes might be different. The events in the sequence will have increasing timeStamps ([[!WHATWG-DOM]]). So the first event will have the smallest timeStamp. The dispatched event's attributes will be initalized in a way that is best representative of all the coalesced events. For example its timeStamp will be equal to the last event's timeStamp in the sequence and its movementX and movementY ([[!POINTERLOCK]]) will be the sum of those of all the coalesced events. None of the events in the sequence will have (nested) coalesced events, so getCoalescedEvents returns an empty sequence for them. This API always returns at least one coalesced event for pointermove events and an empty list for other types of PointerEvents.

Timing of coalesced event firing

Coalescing events only happens for pointermove events. All the coalesced events should be fired before the next frame or before any pointerup, pointerdown, pointercancel events. Note that user agents don't need to hit-test all the coalesced events as none of them will have null targets.

When the user agent dispatches any PointerEvent it MUST dispatch all the events held back so far for coalescing, regardless of their pointerIds. The ordering of all these dispatched events should be in a way that resemebles the most with the actual events' ordering. For example if a pointerdown event causes the dispatch for the coalesced pointermove events the user agent SHOULD first dispatch one pointermove event with all those coalesced events of a pointerId followed by the pointerdown event.

Here is an example of the actual events happening in one frame with increasing timestamps and the events dispatched by the user agent:

Actual eventsDispatched events
pointermove with pointerId=2
pointermove with pointerId=1
pointermove with pointerId=2
pointermove with pointerId=2
pointermove with pointerId=1
pointermove with pointerId=2
pointerdown with pointerId=1 pointermove with pointerId=1 and two coalesced events
pointermove with pointerId=2 and four coalesced events
pointerdown with pointerId=1 and zero coalesced events
pointermove with pointerId=2
pointermove with pointerId=2
pointerup with pointerId=1 pointermove with pointerId=2 and two coalesced events
pointerup with pointerId=1 and zero coalesced events

Examples

The following are examples that demonstrate how the APIs in this specification might be used.


var pointerEventInitDict =
{
  bubbles: true,
  cancelable: true,
  composed: true,
  pointerId: 42,
  pointerType: "pen",
  clientX: 300,
  clientY: 500,
};

var p1 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.clientX += 10;
var p2 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.coalescedEvents = [p1, p2];
var event = new PointerEvent("pointermove", pointerEventInitDict);

window.addEventListener("pointermove", function(event) {
  for (let e of event.getCoalescedEvents()) {
    drawPoint(e.pageX, e.pageY)
  }
});