Mouse Events und Touch Events, aber einfacher: die Pointer Events API

Tales from the Web side  –  0 Kommentare

Im Februar hat das W3C die Pointer Events API als Recommendation veröffentlicht. Dies und die Tatsache, dass sich Browserhersteller Google (nach einigem Hin und Her in der Vergangenheit) nun doch dazu entschieden hat, die Pointer Events API zu implementieren (und nicht wie Apple auf der Touch Events API beharrt), sei zum Anlass genommen, noch einmal kurz zu zeigen, was es mit ihr auf sich hat.

Pointer Events (übrigens nicht zu verwechseln mit der gleichnamigen CSS-Eigenschaft pointer-events) wurden ursprünglich von Microsoft für den Internet Explorer 10 eingeführt. Sie fassen – grob gesagt – unter anderem Maus- und Touch-Events zusammen, indem Eingabegeräte wie eben Maus und Touch Pens allgemein als Pointing Devices abstrahiert werden. Die API wird derzeit allerdings nur vom Internet Explorer und dessen Nachfolger Edge (sowohl in der Desktop-Variante als auch in den mobilen Versionen) unterstützt. Für die anderen Browser muss man bislang auf Polyfills wie das Pointer Events Polyfill, kurz PEP, zurückgreifen.

Einige Zeit sah es so aus, als würde der IE der einzige Browser bleiben, der diese API implementiert und die anderen Browserhersteller (allen voran Apple) eher auf die thematisch verwandte Touch Events API setzen. In der Google-Chrome-Mailinglist verkündete Rick Byers, Software-Engineer bei Google, allerdings vor einigen Monaten nun doch die Absichten des Chrome-Teams, die Pointer Events API zu implementieren:

"Last year we announced that, despite our involvement in the Pointer Events standard, we were going to focus on incremental improvements to existing APIs (like Touch Events), rather than implement Pointer Events in Chromium. Since then we’ve received a steady stream of feedback from web developers, framework authors, and other browser vendors indicating that they see Pointer Events as a highly valuable addition to the platform. Since we’re committed to a web platform which evolves collaboratively through open discussion and data from real-world development, we need to take this feedback very seriously."

Ein Blick auf die API

Insgesamt definiert die API 10 verschiedene Pointer-Eventtypen, die mehr oder weniger auf bereits bekannte Maus-Events abgebildet werden können:

  • pointerover: Pointing Device betritt ein Element (mouseover)
  • pointerenter: Ähnlich zu pointerover, aber ohne Event-Bubbling (mouseenter)
  • pointerdown: Pointing Device wird aktiviert bzw. "drückt" (mousedown)
  • pointermove: Pointing Device wird innerhalb eines Elements bewegt (mousemove)
  • pointerup: Pointing Device wird deaktiviert bzw. "lässt los" (mouseup)
  • pointercancel: Pointing Device wird abgebrochen, d.h. sendet keine weiteren Events mehr (kein Äquivalent)
  • pointerout: Pointer verlässt ein Element (mouseout)
  • pointerleave: Ähnlich zu pointerout, aber ohne Event-Bubbling (mouseleave)
  • gotpointercapture: Element fängt Pointer-Events ab (kein Äquivalent)
  • lostpointercapture: Element fängt nicht mehr länger Pointer-Events ab (kein Äquivalent)

Des Weiteren definiert die API das Interface PointerEvent, das von dem bereits bekannten Interface MouseEvent ableitet und dies um Pointer-spezifische Eigenschaften erweitert:

  • pointerId: ID des Pointer Device (notwendig, um beispielsweise bei Multi-Touch-Anwendungen zwischen einzelnen Pointer Devices unterscheiden zu können)
  • width: die Breite der Kontaktstelle des Pointer Device
  • height: die Höhe der Kontaktstelle des Pointer Device
  • pressure: Angabe des ausgeübten Drucks im Wertebereich 0 bis 1
  • tiltX: horizontale Neigung des Pointer Device
  • tiltY: vertikale Neigung des Pointer Device
  • pointerType: Typ des Pointer Device (mouse, pen oder touch)
  • isPrimary: boolesche Angabe darüber, ob es sich bei dem Pointer Device, welches das Event ausgelöst hat, um das primäre Pointer Device handelt

Darüber hinaus erweitert die API die bereits existierenden Interfaces Element (um die Eigenschaften ongotpointercapture und onlostpointercapture sowie die Methoden setPointerCapture() und releasePointerCapture()), Navigator (um die Eigenschaft maxTouchPoints) und GlobalEventHandlers (um die Eigenschaften onpointerdown, onpointermove, onpointerup, onpointercancel, onpointerover, onpointerout, onpointerenter und onpointerleave). Mit anderen Worten: es lassen sich – wie für andere Events auch – sowohl über addEventListener() als auch über entsprechende on[eventname]-Eigenschaften der entsprechende Event-Handler setzen.

Zu guter Letzt kann über die neue CSS-Eigenschaft touch-action bestimmt werden, ob bei entsprechenden Pointer Events die Standardaktionen des Browsers ausgeführt werden sollen oder nicht.

Ein einfaches Beispiel

Genug der Theorie. Ein einfaches Beispiel des oben Vorgestellten zeigt folgendes Listing. Hier werden an dem <div>-Element mit der ID "capture" Event-Handler für die unterschiedlichen Events registriert. Die jeweils aufgerufene Methode handleEvent() gibt zudem alle relevanten Eigenschaften des empfangenen Events aus.

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Beispiel zur Pointer Events API</title>
<style>
#capture {
background-color: green;
height: 250px;
width: 250px;
}
</style>
<!-- Einbinden des Polyfills PEP -->
<script src="https://code.jquery.com/pep/0.3.0/pep.js"></script>
</head>
<body onload="initialize()">
<script>
function handleEvent(event) {
console.log('Pointer ID:' + event.pointerId); // ID des Pointer, um
// verschiedene Pointer
// bei Multi-Touch-
// Anwendungen zu
// unterscheiden
console.log('Width:' + event.width); // Breite des Pointer
console.log('Height:' + event.height); // Höhe des Pointer
console.log('Pressure:' + event.pressure); // Druck (im Wertebereich
// 0 bis 1)
console.log('Tilt X:' + event.tiltX); // Neigung des Pointer
// zwischen Y- und Z-Ebene
console.log('Tilt Y:' + event.tiltY); // Neigung des Pointer
// zwischen X- und Z-Ebene
console.log('Pointer Type:' + event.pointerType); // Typ des Pointer:
// mouse, pen oder
// touch
console.log('Is primary:' + event.isPrimary); // Angabe, ob der Pointer
// den Primärpointer
// darstellt,
// interessant für
// Multi-Touch-Anwendungen
}
function initialize() {
console.log('initialize');
var element = document.getElementById('capture');
var events = [
'pointerdown', // Pointing Device betritt ein Element
'gotpointercapture', // Element fängt Pointer-Events ab
// (kein Äquivalent)
'lostpointercapture', // Element fängt nicht mehr länger
// Pointer-Events ab (kein Äquivalent)
'pointerenter', // Ähnlich zu pointerover, aber
// ohne Event-Bubbling
'pointerdown', // Pointing Device wird aktiviert
// bzw. "drückt"
'pointermove', // Pointing Device wird innerhalb
// eines Elements bewegt
'pointerup', // Pointing Device wird deaktiviert
// bzw. "lässt los"
'pointercancel', // Pointing Device wird abgebrochen,
// d.h. sendet keine weiteren Events mehr
'pointerout', // Pointer verlässt ein Element (mouseout)
'pointerleave' // Ähnlich zu pointerout, aber ohne
// Event-Bubbling (mouseleave)
];
for (var i = 0; i < events.length; i++) {
var eventType = events[i];
element.addEventListener(events[i], (function (eventType) {
return function (event) {
console.log(eventType);
handleEvent(event);
}
})(eventType));
}
}
</script>
<div id="capture" style="touch-action:none">
</div>
</body>
</html>
Fazit

Die Pointer Events API fasst Pointing Devices wie Maus, Touch Pens etc. bzw. die mit dieser Art von Eingabegerät verbundenen Events auf einer abstrakteren Ebene zusammen. Der Browsersupport sieht momentan zwar noch dürftig aus, aber Googles Versprechen, die API nun ebenfalls zu implementieren, könnte ja vielleicht den ein oder anderen Nachzügler haben. Bis dahin kann man auf das Polyfill PEP zurückgreifen.