简体   繁体   中英

retrieve the same offsetX on touch like mouse event

Hello I am trying to get the offsetX,Y of touch event which should be identical to offsetX of mouse event. To do so I have used this code:

 ev.offsetX = ev.targetTouches[0].pageX- canvasName.offsetLeft

I have even tried to simulate the touch event into mouse event but for that purpose i need the offsetX/Y, which is unavailable in touch event. Is there any way offsetX/Y can be calculated for touch? Please help

I use this

var rect = e.target.getBoundingClientRect();
var x = e.targetTouches[0].pageX - rect.left;
var y = e.targetTouches[0].pageY - rect.top;

The best answer here don't work for me, on webpage with scrolling! This will work better:

var bcr = e.target.getBoundingClientRect();
var x = e.targetTouches[0].clientX - bcr.x;
var y = e.targetTouches[0].clientY - bcr.y;

I used it to solve my problem.

I know this is an old question but the first in a google of "offsetX touch event".. I ended up using something like this after the research I did.

function getOffsetPosition(evt, parent){
    var position = {
        x: (evt.targetTouches) ? evt.targetTouches[0].pageX : evt.clientX,
        y: (evt.targetTouches) ? evt.targetTouches[0].pageY : evt.clientY
    };

    while(parent.offsetParent){
        position.x -= parent.offsetLeft - parent.scrollLeft;
        position.y -= parent.offsetTop - parent.scrollTop;

        parent = parent.offsetParent;
    }

    return position;
}

You should use clientX / clientY properties of mouse event (or pageX / pageY ) if you have scrolling on your page.

As for your solution. It can be corrected by using getElementById(canvasName).clientX

ev.offsetX = ev.targetTouches[0].pageX - getElementById(canvasName).clientX

canvasName.offsetLeft is offset of canvasName with respect to it's parent. So if you want to use offsetLeft you should do something like the following

var left = 0,
elem = getElementById(canvasName);

while(elem) {
  left = left + parseInt(elem.offsetLeft);
  elem = elem.offsetParent;         
}

ev.offsetX = ev.targetTouches[0].pageX - left

If you are using jQuery touchend events, the layerX and layerY attributes provide the relative x and y, but do not take into account the transform. So I manually applied the transform by grabbing the transform scale values from the css.

e = the touchend event from jQuery

parent = the jQuery object of the parent element where the "transform" is applied. For me it was $(e.target.parentNode);

const layerX = e.originalEvent.layerX;
const layerY = e.originalEvent.layerY;
const currentScale = 1 / parseFloat(parent.css('transform').match(/-?[\d\.]+/g)[0]);

const offsetX = layerX * currentScale;
const offsetY = layerY * currentScale;

To make the last two lines compatible with touch and click events:

const offsetX = e.offsetX || layerX * currentScaleX;
const offsetY = e.offsetY || layerY * currentScaleY;

Reference for grabbing transform values: Fetch the css value of transform directly using jquery

If you are using Reactjs onClick then you can get the layerX and layerY values with: e.nativeEvent.layerX . For some reason the layerX and layerY are not available on the React touch events. If you do need to use the React onTouchEnd :

const rect = e.nativeEvent.target.getBoundingClientRect();       
const layerX = e.changedTouches[0].clientX - rect.left;
const layerY = e.changedTouches[0].clientY - rect.top;
const currentScale = 1 / parseFloat(parent.css('transform').match(/-?[\d\.]+/g)[0]);
const offsetX = layerX * currentScale;
const offsetY = layerY * currentScale;

Note: It is better to store the values of the transform in Redux rather than grabbing them with jQuery.

Credits to https://stackoverflow.com/a/11396681/1997890

function recoverOffsetValues(e) {
    var rect = e.target.getBoundingClientRect();
    var bodyRect = document.body.getBoundingClientRect();
    var x = e.originalEvent.changedTouches[0].pageX - (rect.left - bodyRect.left);
    var y = e.originalEvent.changedTouches[0].pageY - (rect.top - bodyRect.top);

    return [x, y];
}

I use this:

const {x, y, width, height} = e.target.getBoundingClientRect();
const offsetX = (e.touches[0].clientX-x)/width*e.target.offsetWidth;
const offsetY = (e.touches[0].clientY-y)/height*e.target.offsetHeight;

You could use PointerEvent instead of touch events, they have more properties. For example:

div.addEventListener('pointermove', console.log);

Output:

isTrusted: true
altKey: false
altitudeAngle: 1.5707963267948966
azimuthAngle: 0
bubbles: true
button: -1
buttons: 1
cancelBubble: false
cancelable: true
clientX: 203
clientY: 483
composed: true
ctrlKey: false
currentTarget: null
defaultPrevented: false
detail: 0
eventPhase: 0
fromElement: null
height: 23
isPrimary: true
layerX: 203
layerY: 177
metaKey: false
movementX: 0
movementY: -1
offsetX: 203
offsetY: 177.6875
pageX: 203
pageY: 483
pointerId: 9
pointerType: "touch"
pressure: 1
relatedTarget: null
returnValue: true
screenX: 734
screenY: 621
shiftKey: false
sourceCapabilities: null
tangentialPressure: 0
tiltX: 0
tiltY: 0
toElement: null
twist: 0
type: "pointermove"
which: 0
width: 23
x: 203
y: 483
[[Prototype]]: PointerEvent

Usage example: MDN: Pinch zoom gestures

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM