How do I evaluate pinch action on touchscreen device when each finger is over 2 different elements when pinch is initiated?

  Kiến thức lập trình

I am attempting to implement a feature which will change text size using pinch on iPhone. I am using meta/viewport tag to override default behavior, as well as css touch-action to override default zooming with pinch.

The problem is, even if my touchstart listener is attached to window or document.body, if I initiate the pinch with each finger over 2 different elements, touches or changedTouches array only contains one element, thus I cannot evaluate the pinch action. If I start my pinch with both fingers over the same element, then the array contains 2 elements (one for each finger) and I can evaluate the pinch action.

How can I make this agnostic to which element the fingers are over upon initiation?

Here is the code I am using: (Note this is a naive implementation only evaluating horizontal movement for demo purposes.)

HTML:

<!DOCTYPE html>
<html>
<head>
  <title>TOUCH</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

  <script src="touch.js?<?php print $ts ?>"></script>

<style type="text/css">
/* Disable default zooming */
:root, html {
  touch-action: pan-x pan-y;
  height: 100%
}
html, body {
  margin: 0;
  padding: 0;
}
body {
  padding: 10px;
  min-height: 100vh;
  font-family: Verdana;
  font-size: 18px;
  background-color: #fee;
}
#info {
  padding: 40px 0 0 20px;
  font-family: monospace;
  font-size: 18px;
}
</style>

</head>
<body>
<div id="info">The info window</div>
<div id="info2" style="color: red">The info window2</div>
<div style="height: 10px"></div>
<div>
This is the way we wash our clothes This is the way we wash our clothes This is the way we wash our clothes This is the way we wash our clothes This is the way we wash our clothes This is the way we wash our clothes This is the way we wash our clothes
</div>
<div>
Every good boy deserves fudge Every good boy deserves fudge Every good boy deserves fudge Every good boy deserves fudge Every good boy deserves fudge Every good boy deserves fudge Every good boy deserves fudge Every good boy deserves fudge Every good boy deserves fudge
</div>
</body>
</html>

JS:

function init() {
  window.addEventListener("touchstart", onTouchstart, { passive: false, capture: true });
}

function onTouchstart(evt) {
  evt.preventDefault();
  evt.stopPropagation();

  let lastDistX = 0;

  window.addEventListener("touchmove", onTouchmove, { passive: false, capture: true });

  window.addEventListener("touchend", (evt) => {
    window.removeEventListener("touchmove", onTouchmove, { passive: false, capture: true });
  }, { once: true });

  window.addEventListener("touchcancel", (evt) => {
    window.removeEventListener("touchmove", onTouchmove, { passive: false, capture: true });
  }, { once: true });

  function onTouchmove(evt) {
    let touches = Array.from(evt.changedTouches);

    if (touches.length == 2) {
      let distX = Math.abs(touches[1].screenX - touches[0].screenX);

      if (!lastDistX) {
        lastDistX = distX;
        return;
      }

      let incDec = distX < lastDistX ? -1 : 1;
      let initFS = parseFloat(getComputedStyle(document.body).fontSize);
      let offset = (incDec * .25);
      let fs = Math.max(initFS + offset, 12);
      let fontSize = fs + "px";

      document.body.style.fontSize = fontSize;
      __("info").innerHTML = "touchmove " + lastDistX + "    " + distX + "        " + incDec + "        " + initFS + "    " + offset + "    " + fontSize;

      lastDistX = distX;

    } else {
      __("info2").innerHTML = touches[0].clientX;
    }

    evt.preventDefault();
    evt.stopPropagation();
    document.body.style.zoom = "100%";
    document.body.style.transform = "scale(1)";
  }
}

2

LEAVE A COMMENT