Bug 220194

Summary: `PointerEvent.movementX` always 0
Product: WebKit Reporter: 709922234
Component: UI EventsAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: ap, graouts, lgarron, steveruizok, thorton, webkit-bug-importer, wenson_hsieh
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=167775

Description 709922234 2020-12-29 08:51:07 PST
example: https://codepen.io/mantou132/pen/JjRMzMg

The `movementX` property of the `pointermove` event should be equal to `MouseEvent.movementX`
Comment 1 Alexey Proskuryakov 2020-12-30 12:38:11 PST
I can reproduce this in a recent WebKit build; works in Chrome.
Comment 2 Radar WebKit Bug Importer 2021-01-05 08:52:12 PST
<rdar://problem/72814440>
Comment 3 Steve Ruiz 2021-07-29 13:36:18 PDT
Came here to post this one.

https://codesandbox.io/s/muddy-thunder-3wesc
Comment 4 Lucas Garron 2021-12-26 01:04:07 PST
I'm also running into this issue: `movementX` and `movementY` are not populated on `pointermove` events, regardless of whether they are due to mouse, touch, or Apple Pencil.

When the source is a mouse (on macOS), the values are `0`, because the property access chains up to the `MouseEvent` prototype.

Here's a moderately useful repro:

Hosted: https://garron.net/temp/safari-movementX/
Source:
```html
<div id="log" style="background: #90B8DF; width: 90%; height: 90%">(Waiting for data.)</div>
<script>
  window.addEventListener("load", () => {
    document.body.addEventListener("pointermove", (e) => {
      console.log(e);
      document.querySelector("#log").textContent = `{movementX: ${e.movementX}, movementY: ${e.movementY}} at ${Math.round(performance.now()) / 1000}sec`
    })
  })
</script>
```

As far as I can tell, this is a bit tricky/expensive to polyfill:

- Select the correct X/Y coordinates to track per touch.
  - I believe `screenX/screenY` are best, except `screenY` is `undefined` on i[Pad]OS when the event is also used for vertical scrolling‽
- Track the last seen coordinates per `pointerId`.
  - Compensate for bugs like `undefined` values, like described above.
- Evict old cached coordinates so we don't end up with an unbounded growing cache and don't accidentally track a "movement" across mouse clicks (which seem to always have the same `pointerId`).
  - Attach listeners for `pointerup`, and `pointercancel` and hope that catches every cache eviction event‽ (Does that also need to include `pointerleave` and `pointerout`? That would cause issues for the app I'm currently working on.) Track timestamps and discard touches that are sufficiently old?

By contrast, `movementX` and `movementY` are much more ergonomic and I'd really appreciate being able to use them.
Comment 5 Lucas Garron 2021-12-26 01:22:45 PST
> except `screenY` is `undefined` on i[Pad]OS when the event is also used for vertical scrolling‽

Small correction: I think I had a typo while testing this. I'm now consistently getting both `screenX` and `screenY` values (although all the other issues I described are still relevant).
Comment 6 Lucas Garron 2021-12-26 01:53:37 PST
I'd also like to add that none of the following are effective for feature detection:

- `"movementX" in e`
- `e.movementX !== "undefined"`
- `e.hasOwnProperty("movementX")`

The fact that `movementX` can be an incorrect of `0` instead of `undefined` means that I can't trust a numerical value without something like UA sniffing, which should really be an anti-pattern at this point. :-/