How to get same coordinates from pointer events as from touch events while viewport is zoomed?
Asked Answered
F

2

7

I was trying to use pointer events (e.g. pointerdown) instead of combining touch (e.g. touchstart) and mouse (e.g. mousedown) events to figure out the input event coordinates.

var bodyElement = document.body;

bodyElement.addEventListener("touchstart", function(e) {console.log("touch: " + e.changedTouches[0].clientX + " " + e.changedTouches[0].clientY);});
bodyElement.addEventListener("pointerdown", function(e) {console.log("point: " + e.clientX + " " + e.clientY);});

All works fine until the viewport gets zoomed (e.g. android chrome zooms the webpage, device toolbar zoom factor in chrome's dev tools is other than 100%, ...). The pointer events then start reporting completely wrong values.

You can observe the error in following screenshots:

1) viewport scaled to 100%, 300px*300px div clicked to bottom right corder: unzoomed

2) viewport scaled to 150%, 300px*300px div clicked to bottom right corner: zoomed

Do you guys know how to get the correct coordinates from pointer events?

Edit:
Added jsfiddle: jsfiddle

Fitting answered 4/3, 2018 at 13:53 Comment(2)
Sounds like an offset issue. If you can, get a working demo of this in either stackoverflows personal editor or jsfiddle or equivalent and I can help.Sputum
Added the fiddle. Hope you will be able to reproduce it.Fitting
S
1

Target the div, rather than the "relative" body which can possibly change the actual div's orientation.

Try this:

const dostuffwithdiv = () =>{
  var u = document.getElementById('uniqueDiv');

  u.addEventListener("touchstart", e=> {
    var rect = e.target.getBoundingClientRect();
    var x = e.targetTouches[0].pageX - rect.left;
    var y = e.targetTouches[0].pageY - rect.top;
    var msg = `touch: ${x} ${y}`;
    console.log(msg);
  });
  u.addEventListener("pointerdown", e=> {
    var rect = e.target.getBoundingClientRect();
    var x = e.clientX - rect.left;
    var y = e.clientY - rect.top;
    var msg = `point: ${x} ${y}`;
    console.log(msg);
  });
}

document.onreadystatechange = dostuffwithdiv(); //since this is jsfiddle this will work
//but on a real frontend you'd want to do something more like this:
//document.addEventListener("DOMContentLoaded", dostuffwithdiv);

Here is a fiddle, although the very bottom of it is listening for a different event, because of how jsfiddle works internally i had to alter the last line. I hope this makes sense and if it doesn't just ask.

https://jsfiddle.net/L3tbsyax/42/

Sputum answered 4/3, 2018 at 16:18 Comment(9)
Unfortunately changing the listener target doesn't change the behaviour. You can see the output on the following screenshot: i.imgur.com/mJUUnfe.jpg I clicked approx. in the middle of the div, touch reports correctly middle (162x149) and pointer is completely off.Fitting
Try the updated code, I adjusted it to work now in jsfiddle.Sputum
Still the same. The bounding rectangle is in both TouchEvent and PointerEvent the same, so it can't affect the two events differently. Were you able to reproduce the issue I described?Fitting
What is the problem, that you want the two distinguished differently?Sputum
Running the above code, when running jsfiddle in responsive emulation was giving me this, which is what I believed you wanted. imgur.com/a/3QZuiSputum
The problem is that I want my web applications working on touch-enabled desktop devices without the hassle of managing both touch + mouse events simultaneously. @your imgur - that looks great, no idea why mine (i.imgur.com/kqyJYwR.jpg) doesn't work the same. Would you please zoom the emulation to another level than 100% and try again?Fitting
even with zooming on the emulated device, the records are showing consistant numbers with the above code. Example, zoomed at 150% imgur.com/a/LkLfHSputum
I tried reproducing it on multiple different systems. Reproducible everywhere. No idea why your chrome works differently than mine.. I have another reproduction idea: Launch mdn.github.io/dom-examples/pointerevents/… (from mozilla's pointer event tutorial) in emulation, on 150% and try to click on the canvas. Are the paintings misplaced on your system?Fitting
I see the problem! I updated my chrome and now its busted :) Give me a few minutes to revise.Sputum
S
0

This was as close as I could get it. I think chrome recently changed these in how they operate and well ... I'm not well enough versed to understand the -insert explicit remark- touchstart or pointerdown events, but this is as close as I could get it:

html (notice i removed the border you were applying because it made extra hell that you'd have to calculate later if absolutely necessary)

<body style="margin:0; padding: 0;">
    <div id="uniqueDiv" style="width:300px;height:300px;background-color: black;"></div>
</body>

js

const dostuffwithdiv = () =>{
  var u = document.getElementById('uniqueDiv');

  u.addEventListener("touchstart", e=> {
    var rect = e.target.getBoundingClientRect();
    var x = e.targetTouches[0].clientX - rect.left;
    var y = e.targetTouches[0].clientY - rect.top;
    var msg = `touch: ${x} ${y}`;
    console.log(msg);
  });
  u.addEventListener("mouseup", e=> {
    var msg = `point: ${e.clientX} ${e.clientY}`;
    console.log(msg);
  });
}

// document.addEventListener("DOMContentLoaded", dostuffwithdiv);
document.onreadystatechange = dostuffwithdiv();

https://jsfiddle.net/jmf74Lwc/4/

Sputum answered 4/3, 2018 at 21:16 Comment(3)
If you wanted to consolidate these two events into the same, you could just check for which event was passed in and do different logic accordingly.Sputum
Like mentioned at the top of my question, I was previously using combination of mouse and touch events - similar to your approach. Was hoping it would be possible to improve the pointer event listeners instead of going back to mouse+touch.Fitting
so just listen to both events. something like u.addEventListener('touchstart mouseup', function(){ if (e.type == 'touchstart') { //do touchstart related stuff } else { //do mouseup stuff });Sputum

© 2022 - 2024 — McMap. All rights reserved.