// Global vars to cache event state const evCache = []; let prevDiff = -1; function init() { // 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; } 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); } function pointermoveHandler(ev) { // This function implements a 2-pointer horizontal 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.abs(evCache[0].clientX - evCache[1].clientX); 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; } } 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; } } function removeEvent(ev) { // Remove this event from the target's cache const index = evCache.findIndex( (cachedEv) => cachedEv.pointerId === ev.pointerId, ); evCache.splice(index, 1); } // Log events flag let logEvents = false; // 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 = ""; }