Pinch-Zoom-Gesten
Das Hinzufügen von Gesten zu einer Anwendung kann die Benutzererfahrung erheblich verbessern. Es gibt viele Arten von Gesten: von der einfachen Wischgeste mit einem Berührungspunkt bis zur komplexeren Drehgeste mit mehreren Berührungspunkten, bei der sich die Berührungspunkte (auch Pointer genannt) in unterschiedliche Richtungen bewegen.
Dieses Beispiel zeigt, wie Sie eine Pinch-Zoom-Geste erkennen. Dabei wird mithilfe von Pointer Events festgestellt, ob die nutzende Person zwei Pointer aufeinander zu oder voneinander weg bewegt.
Eine Live-Version dieser Anwendung ist auf GitHub verfügbar. Der Quellcode ist auf GitHub verfügbar; Pull Requests und Fehlermeldungen sind willkommen.
Beispiel
In diesem Beispiel verwenden Sie Pointer Events, um zwei Zeigegeräte beliebiger Art gleichzeitig zu erkennen, darunter Finger, Mäuse und Stifte. Bei der Pinch-in-Geste (Verkleinern), bei der sich die beiden Pointer aufeinander zubewegen, ändert sich die Hintergrundfarbe des Zielelements zu lightblue. Bei der Pinch-out-Geste (Vergrößern), bei der sich die beiden Pointer voneinander entfernen, ändert sich die Hintergrundfarbe des Zielelements zu pink.
Berührungsziel definieren
Die Anwendung verwendet <div>, um die Zielbereiche für die Pointer zu definieren.
div {
margin: 0em;
padding: 2em;
}
#target {
background: white;
border: 1px solid black;
}
Globaler Zustand
Um eine Geste mit zwei Pointern zu unterstützen, muss der Ereigniszustand eines Pointers über verschiedene Ereignisphasen hinweg erhalten bleiben. Diese Anwendung verwendet zwei globale Variablen, um den Ereigniszustand zwischenzuspeichern.
// Global vars to cache event state
const evCache = [];
let prevDiff = -1;
Event-Handler registrieren
Event-Handler werden für die folgenden Pointer Events registriert: pointerdown, pointermove und pointerup. Der Handler für pointerup wird auch für die Ereignisse pointercancel, pointerout und pointerleave verwendet, da diese vier Ereignisse in dieser Anwendung dieselbe Bedeutung haben.
// Install event handlers for the pointer target
const el = document.getElementById("target");
el.onpointerdown = pointerdownHandler;
el.onpointermove = pointermoveHandler;
// Use same handler for pointer{up,cancel,out,leave} events since
// the semantics for these events - in this app - are the same.
el.onpointerup = pointerupHandler;
el.onpointercancel = pointerupHandler;
el.onpointerout = pointerupHandler;
el.onpointerleave = pointerupHandler;
Pointer-Kontakt beginnt
Das Ereignis pointerdown wird ausgelöst, wenn ein Pointer (Maus, Stift oder Berührungspunkt auf einem Touchscreen) mit der Kontaktfläche in Berührung kommt. In dieser Anwendung muss der Ereigniszustand zwischengespeichert werden, falls dieses Ereignis Teil einer Pinch-Zoom-Geste mit zwei Pointern ist.
function pointerdownHandler(ev) {
// The pointerdown event signals the start of a touch interaction.
// This event is cached to support 2-finger gestures
evCache.push(ev);
log("pointerDown", ev);
}
Pointer-Bewegung
Der Event-Handler für pointermove erkennt, ob eine Pinch-Zoom-Geste mit zwei Pointern ausgeführt wird. Wenn zwei Pointer die Kontaktfläche berühren und der Abstand zwischen ihnen zunimmt (Pinch-out oder Vergrößern), ändert sich die Hintergrundfarbe des Elements zu pink. Nimmt der Abstand ab (Pinch-in oder Verkleinern), ändert sich die Hintergrundfarbe zu lightblue. In einer komplexeren Anwendung könnte die Unterscheidung zwischen Pinch-in und Pinch-out für anwendungsspezifische Funktionen genutzt werden.
Bei der Verarbeitung dieses Ereignisses wird der Rahmen des Zielelements auf dashed gesetzt. So wird deutlich sichtbar, dass das Element ein Bewegungsereignis empfangen hat.
function pointermoveHandler(ev) {
// This function implements a 2-pointer pinch/zoom gesture.
//
// If the distance between the two pointers has increased (zoom in),
// the target element's background is changed to "pink" and if the
// distance is decreasing (zoom out), the color is changed to "lightblue".
//
// This function sets the target element's border to "dashed" to visually
// indicate the pointer's target received a move event.
log("pointerMove", ev);
ev.target.style.border = "dashed";
// Find this event in the cache and update its record with this event
const index = evCache.findIndex(
(cachedEv) => cachedEv.pointerId === ev.pointerId,
);
evCache[index] = ev;
// If two pointers are down, check for pinch gestures
if (evCache.length === 2) {
// Calculate the distance between the two pointers
const curDiff = Math.hypot(
evCache[0].clientX - evCache[1].clientX,
evCache[0].clientY - evCache[1].clientY,
);
if (prevDiff > 0) {
if (curDiff > prevDiff) {
// The distance between the two pointers has increased
log("Pinch moving OUT -> Zoom in", ev);
ev.target.style.background = "pink";
}
if (curDiff < prevDiff) {
// The distance between the two pointers has decreased
log("Pinch moving IN -> Zoom out", ev);
ev.target.style.background = "lightblue";
}
}
// Cache the distance for the next move event
prevDiff = curDiff;
}
}
Pointer-Kontakt endet
Das Ereignis pointerup wird ausgelöst, wenn ein Pointer von der Kontaktfläche abgehoben wird. In diesem Fall wird das Ereignis aus dem Ereignis-Cache entfernt, und die Hintergrundfarbe sowie der Rahmen des Zielelements werden auf ihre ursprünglichen Werte zurückgesetzt.
In dieser Anwendung wird dieser Handler auch für die Ereignisse pointercancel, pointerleave und pointerout verwendet.
function pointerupHandler(ev) {
log(ev.type, ev);
// Remove this pointer from the cache and reset the target's
// background and border
removeEvent(ev);
ev.target.style.background = "white";
ev.target.style.border = "1px solid black";
// If the number of pointers down is less than two then reset diff tracker
if (evCache.length < 2) {
prevDiff = -1;
}
}
Benutzeroberfläche der Anwendung
Die Anwendung verwendet ein <div>-Element als Berührungsfläche und stellt Schaltflächen bereit, um die Protokollierung zu aktivieren und das Protokoll zu löschen.
Damit das standardmäßige Berührungsverhalten des Browsers die Pointer-Verarbeitung dieser Anwendung nicht übersteuert, wird die Eigenschaft touch-action auf das <body>-Element angewendet.
<div id="target">
Touch and Hold with 2 pointers, then pinch in or out.<br />
The background color will change to pink if the pinch is opening (Zoom In) or
changes to lightblue if the pinch is closing (Zoom out).
</div>
<!-- UI for logging/debugging -->
<button id="log">Start/Stop event logging</button>
<button id="clear-log">Clear the log</button>
<p></p>
<output></output>
body {
touch-action: none; /* Prevent default touch behavior */
}
Weitere Funktionen
Diese Funktionen unterstützen die Anwendung, sind aber nicht direkt am Ereignisablauf beteiligt.
Cache-Verwaltung
Diese Funktion hilft bei der Verwaltung des globalen Ereignis-Caches evCache.
function removeEvent(ev) {
// Remove this event from the target's cache
const index = evCache.findIndex(
(cachedEv) => cachedEv.pointerId === ev.pointerId,
);
evCache.splice(index, 1);
}
Ereignisprotokollierung
Diese Funktionen geben Informationen über Ereignisaktivitäten im Fenster der Anwendung aus, um das Debugging und das Verständnis des Ereignisablaufs zu unterstützen.
// Log events flag
let logEvents = false;
document.getElementById("log").addEventListener("click", enableLog);
document.getElementById("clear-log").addEventListener("click", clearLog);
// Logging/debugging functions
function enableLog(ev) {
logEvents = !logEvents;
}
function log(prefix, ev) {
if (!logEvents) return;
const o = document.getElementsByTagName("output")[0];
o.innerText += `${prefix}:
pointerID = ${ev.pointerId}
pointerType = ${ev.pointerType}
isPrimary = ${ev.isPrimary}
`;
}
function clearLog(event) {
const o = document.getElementsByTagName("output")[0];
o.textContent = "";
}
Siehe auch
- Pointer Events jetzt in Firefox Nightly; Mozilla Hacks; von Matt Brubeck und Jason Weathersby; 04.08.2015
- Gesten; Material Design