Pinch-Zoom-Gesten
Das Hinzufügen von Gesten zu einer Anwendung kann das Benutzererlebnis erheblich verbessern. Es gibt viele Arten von Gesten, von der einfachen Single-Touch-Wischgeste bis zur komplexeren Multi-Touch-Drehgeste, bei der sich die Berührungspunkte (auch Zeiger genannt) in verschiedene Richtungen bewegen.
Dieses Beispiel zeigt, wie die Pinch/Zoom-Geste erkannt wird, bei der Zeigervorgänge verwendet werden, um festzustellen, ob der Benutzer zwei Zeiger näher zueinander oder weiter 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 die Zeigervorgänge, um gleichzeitig zwei Zeigegeräte beliebigen Typs zu erkennen, einschließlich Finger, Mäuse und Stifte. Die Pinch-In (Zoom-Out)-Geste, bei der die beiden Zeiger aufeinander zu bewegt werden, ändert die Hintergrundfarbe des Zielelements in lightblue. Die Pinch-Out (Zoom-In)-Geste, bei der die beiden Zeiger voneinander weg bewegt werden, ändert die Hintergrundfarbe des Zielelements in pink.
Berührungsziel definieren
Die Anwendung verwendet <div>, um die Zielbereiche der Zeiger zu definieren.
div {
margin: 0em;
padding: 2em;
}
#target {
background: white;
border: 1px solid black;
}
Globaler Status
Die Unterstützung einer Zwei-Zeiger-Geste erfordert die Aufrechterhaltung des Ereignisstatus eines Zeigers während verschiedener Ereignisphasen. Diese Anwendung verwendet zwei globale Variablen, um den Ereignisstatus zwischenspeichern.
// Global vars to cache event state
const evCache = [];
let prevDiff = -1;
Ereignis-Handler registrieren
Ereignis-Handler werden für die folgenden Zeigervorgänge registriert: pointerdown, pointermove und pointerup. Der Handler für pointerup wird für die Ereignisse pointercancel, pointerout und pointerleave verwendet, da diese vier Ereignisse in dieser Anwendung die gleichen Semantiken 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 Down
Das pointerdown-Ereignis wird ausgelöst, wenn ein Zeiger (Maus, Stift/Stylus oder Berührungspunkt auf einem Touchscreen) Kontakt mit der Kontaktfläche aufnimmt. In dieser Anwendung muss der Status des Ereignisses zwischengespeichert werden, falls dieses Down-Ereignis Teil einer Zwei-Zeiger-Pinch/Zoom-Geste 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 Move
Der pointermove-Ereignis-Handler erkennt, ob ein Benutzer eine Zwei-Zeiger-Pinch/Zoom-Geste initiiert. Wenn zwei Zeiger unten sind und der Abstand zwischen den Zeigern zunimmt (was auf eine Pinch-Out oder Zoom-In-Geste hinweist), wird die Hintergrundfarbe des Elements in pink geändert, und wenn der Abstand zwischen den Zeigern abnimmt (eine Pinch-In oder Zoom-Out-Geste), wird die Hintergrundfarbe in lightblue geändert. In einer ausgefeilteren Anwendung könnte die Bestimmung von Pinch-In oder Pinch-Out verwendet werden, um anwendungsspezifische Semantiken anzuwenden.
Wenn dieses Ereignis verarbeitet wird, wird der Rand des Ziels auf dashed gesetzt, um eine klare visuelle Anzeige zu bieten, dass das Element ein Bewegungsevent 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 Up
Das pointerup-Ereignis wird ausgelöst, wenn ein Zeiger von der Kontaktfläche gehoben wird. Wenn dies geschieht, wird das Ereignis aus dem Ereignis-Cache entfernt und die Hintergrundfarbe und der Rand 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 für den Berührungsbereich und bietet Schaltflächen, um das Logging zu aktivieren und das Log zu löschen.
Um zu verhindern, dass das standardmäßige Berührungsverhalten des Browsers die Zeigerverarbeitung dieser Anwendung überschreibt, wird die touch-action Eigenschaft 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 */
}
Verschiedene Funktionen
Diese Funktionen unterstützen die Anwendung, sind jedoch nicht direkt am Ereignisfluss beteiligt.
Cache-Verwaltung
Diese Funktion hilft bei der Verwaltung der globalen Ereigniscaches 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 werden verwendet, um Ereignisaktivitäten an das Anwendungsfenster zu senden (zur Unterstützung der Fehlersuche und um mehr über den Ereignisfluss zu erfahren).
// 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. August 2015
- jQuery Pointer Events Polyfill
- Gesten; Material Design