6

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

Johnyk11
  • 81
  • 4
  • 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. – simon Mar 04 '18 at 14:02
  • Added the fiddle. Hope you will be able to reproduce it. – Johnyk11 Mar 04 '18 at 14:44

2 Answers2

0

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/

simon
  • 854
  • 1
  • 9
  • 23
  • Unfortunately changing the listener target doesn't change the behaviour. You can see the output on the following screenshot: https://i.imgur.com/mJUUnfe.jpg I clicked approx. in the middle of the div, touch reports correctly middle (162x149) and pointer is completely off. – Johnyk11 Mar 04 '18 at 16:34
  • Try the updated code, I adjusted it to work now in jsfiddle. – simon Mar 04 '18 at 16:35
  • 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? – Johnyk11 Mar 04 '18 at 16:45
  • What is the problem, that you want the two distinguished differently? – simon Mar 04 '18 at 16:54
  • Running the above code, when running jsfiddle in responsive emulation was giving me this, which is what I believed you wanted. https://imgur.com/a/3QZui – simon Mar 04 '18 at 17:03
  • 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 (https://i.imgur.com/kqyJYwR.jpg) doesn't work the same. Would you please zoom the emulation to another level than 100% and try again? – Johnyk11 Mar 04 '18 at 17:18
  • even with zooming on the emulated device, the records are showing consistant numbers with the above code. Example, zoomed at 150% https://imgur.com/a/LkLfH – simon Mar 04 '18 at 17:58
  • 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 https://mdn.github.io/dom-examples/pointerevents/Using_Pointer_Events.html (from mozilla's pointer event tutorial) in emulation, on 150% and try to click on the canvas. Are the paintings misplaced on your system? – Johnyk11 Mar 04 '18 at 19:20
  • 1
    I see the problem! I updated my chrome and now its busted :) Give me a few minutes to revise. – simon Mar 04 '18 at 19:37
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/

simon
  • 854
  • 1
  • 9
  • 23
  • 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. – simon Mar 04 '18 at 21:25
  • 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. – Johnyk11 Mar 05 '18 at 07:55
  • 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 }); – simon Mar 05 '18 at 20:13