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 I am having is, when making a page where text only takes up 1/2 the screen, if I start my pinch with one finger over the text, and one finger not, touches or changedTouches array only contains one element, thus I cannot evaluate the pinch action. If I start my pinch with either, both fingers over the text, or both fingers not over the text, touches/changedTouches contains 2 elements, and everything works fine.
Why is this?
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%
}
body {
font-family: Verdana;
font-size: 18px;
background-color: #fee;
}
#info {
margin: 40px 0 0 0;
padding: 0 0 0 20px;
font-family: monospace;
font-size: 18px;
}
</style>
</head>
<body>
<div id="info">The info window</div>
<div id="info2">The info window2</div>
<div style="height: 10px"></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 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
</body>
</html>
JS:
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;
mssg("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)";
}
}
window.addEventListener("touchstart", onTouchstart, { passive: false, capture: true });
I have tried adding the listener to document.body
(after load
event fires) instead of window
but this is even worse, as both fingers must then be over the text, and it will no longer work if both fingers are not over the text.
I have verified the body element is filling the screen by setting a background color on body
.