Search code examples
javascripttransformtouch-eventmouse-positionpointer-events

Get touch position on element when parent/body has scale transformation


I need to get the exact mouse/touch position from the left border of an element on move.

The problem is, that my body is scaled down with transform:scale() depending on window/device size.

The touch- and mouse-events x, pageX, and clientX properties values in relation to the elements offsetLeft property are wrong because of the scaling, so I can't use them to make a substraction and get the correct position.

With mouse-events I just use the offsetX property and it works fine.

The problem is, there is no offsetX property with touch-events.

I did some researches and found this issue where pointer-events are mentioned.

I never heard about pointer-events before and was quiet happy because I thought this would solve my issue.

But this pointed me to a new problem. pointer events are NOT supported in safari and ios.

Since the application is designed for ipad first this is a big problem.

So now I'm looking for a offsetX-like property I could use but there is none.

I know I could multiply for example the touch-events pageX by the inverted scale, but this would break if i change the scaling in the styles so no way to use this technique.

//no way to do this:
const windowWidth = window.innerWidth 
let scale = 1
if(windowWidth < 1000) {
  scale = 1.55
} else if(windowWidth < 1101) {
  scale = 1.45
} else if(windowWidth < 1201) {
  scale = 1.35
} else if(windowWidth < 1301) {
  scale = 1.25
} else if(windowWidth < 1401) {
  scale = 1.2
} else if(windowWidth < 1501) {
  scale = 1.12
} else if(windowWidth < 1601) {
  scale = 1.06
}

const x = (e.changedTouches ? (e.changedTouches[0].pageX * scale) - this.offsetLeft : e.offsetX)

I've created a demo where you can play around (switch in dev tools between mobile and desktop/resize for scalings).

My explanation could be a little bit confusing please ask me if something isn't clear.

Help would be greatly appreciated.


Solution

  • If it's just scaling, grab the current scale amount by getting the currently applied transform style and parsing it, then divide by the scale factor.

    If you need to get fancier, such as if rotations or 3D transforms are used, you can multiply by the inverse transformation matrix: see this post and the accompanying jsfiddle for details and code.