19

I have an object with the name "element". If somebody touches the tablet, I would like to return the x and y coordinates of the touch position relative to the object, i. e. the upper left corner of the object has the coordinates x=0 and y=0.

I know how to implement this on desktops:

$(function() {
$(document).mousedown(function(e) {
  var offset = $("#element").offset();
  var relativeX = (e.pageX - offset.left);
  var relativeY = (e.pageY - offset.top);
  alert(relativeX+':'+relativeY);
  $(".position").val("afaf");
});
});

So the word "mousedown" should be replaced by "touchstart", I guess. However, it still doesn't work.

How do I change the above code such that it works on tablets with "touchstart" instead of "mousedown"?

Quality Catalyst
  • 6,531
  • 8
  • 38
  • 62
Tall83
  • 343
  • 1
  • 4
  • 8

7 Answers7

33

UPDATE: See Daniel Lavedonio de Lima's answer below

You have to explicitly pull a touches object out of the event, it doesn't contain the coordinates directly. Look at line two of the code below.

Here is the code I always use to get touch/pointer coordinates:

    if(e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel'){
        var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
        x = touch.pageX;
        y = touch.pageY;
    } else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover'|| e.type=='mouseout' || e.type=='mouseenter' || e.type=='mouseleave') {
        x = e.clientX;
        y = e.clientY;
    }

Put this inside an event listener that listens for any or all of those events and add your offset calculation and this should work.

Christopher Reid
  • 4,318
  • 3
  • 35
  • 74
23

Christopher Reid's answer almost worked for me, but I had to make a few ajustments because originalEvent property was not part of the event when I was testing in Google Chrome version 81.0.4044.138 and Mozila Firefox version 76.0.1.

Since I found some answers that use directly the event and other that uses event.originalEvent property, I added a check to use the first if the latter is undefined.

So instead of:

var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];

I used:

var evt = (typeof e.originalEvent === 'undefined') ? e : e.originalEvent;
var touch = evt.touches[0] || evt.changedTouches[0];

So the full answer then becomes:

if(e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel'){
    var evt = (typeof e.originalEvent === 'undefined') ? e : e.originalEvent;
    var touch = evt.touches[0] || evt.changedTouches[0];
    x = touch.pageX;
    y = touch.pageY;
} else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover'|| e.type=='mouseout' || e.type=='mouseenter' || e.type=='mouseleave') {
    x = e.clientX;
    y = e.clientY;
}
3

Normally you would use e.g. e.touches[0].clientX to handle touch events

A non jquery solution, Assuming you have the following HTML

<div id="touchme" style="width: 200px; height: 200px; background: blue;">

And script

document.getElementById("touchme").addEventListener("touchstart",
function clicked(e) {
    var br = document.getElementById("touchme").getBoundingClientRect();
    // x & y are relative to the clicked element
    var x = e.touches[0].clientX - br.left;
    var y = e.touches[0].clientY - br.top;
    console.log("x: " + x + " y: " + y);
});

Note the following script handles only the first (of all the possible) touch input

Domenico
  • 168
  • 1
  • 8
3

PointerEvent supports mouse and touch both.

For example, let's see Sortable.js.

Bind events #L423

el.addEventListener('pointerdown', handler);

Get coords #L574

let touch = (evt.touches && evt.touches[0]) || (evt.pointerType && evt.pointerType === 'touch' && evt);
let clientX = (touch || evt).clientX;
let clientY = (touch || evt).clientY;
Jehong Ahn
  • 1,872
  • 1
  • 19
  • 25
1

Try this:

$(function(){

$('body').on('touchstart', function(e) {
  var offset = $("#element").offset();
  var t = e.targetTouches.length > 0 ? e.targetTouches.item(0) : e.touches.item(0); 
  var relativeX = t.pageX - offset.left;
  var relativeY = t.pageY - offset.top;
  console.log(relativeX+':'+relativeY);
  $(".position").val("afaf");
});

});
StackSlave
  • 10,613
  • 2
  • 18
  • 35
0

I adapted the Domenico solution to move the camera on pc and mobile for threeJS without orbitcontrols:

window.addEventListener("touchmove", function clicked(e) {
cursor.x = e.touches[0].clientX / sizes.width - 0.5
cursor.y = -(e.touches[0].clientY / sizes.height - 0.5)});
Salvador
  • 61
  • 1
  • 8
0

In case you have some built-in scroll, you should do it as follows:

const rect = event.target.getBoundingClientRect();
x = event.targetTouches[0].pageX - (rect.left + document.documentElement.scrollLeft);
y = event.targetTouches[0].pageY - (rect.top + document.documentElement.scrollTop);
Jöcker
  • 5,281
  • 2
  • 38
  • 44