Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

movementX/Y coordinate space #42

Open
EiraGe opened this issue Mar 21, 2019 · 10 comments
Open

movementX/Y coordinate space #42

EiraGe opened this issue Mar 21, 2019 · 10 comments

Comments

@EiraGe
Copy link
Contributor

EiraGe commented Mar 21, 2019

The spec define movementX/Y from screenX/Y. However, while all major browser (except Edge) having screenX/Y in DIP(w3c/uievents#150), movementX/Y implementation are kind of mess here:

movementX/Y Edge Chrome Firefox Safari
coordinate space Physical pixel Physical pixel CSS pixel DIP(buggy?)
Scaled by device-scale-factor(OS High DPI setting) X X
Scaled by page zoom X X X
Scale by Pinch-zoom X X X X

It would be nicer and clearer to have better interoperability.
WDYT? @NavidZ @mustaqahmed @smaug----

@mustaqahmed
Copy link
Member

I agree with Ella re the incompatible implementations.

The current movementX/Y definition in the spec (difference between consecutive screenX/Y values) is problematic from another perspective: screenX/Y spec itself doesn't match the reality! The spec defines screenX/Y as CSS pixels, but most major browsers have DIPs. As a result, browsers have two interpretations of the PointerLock spec: implement movementX/Y either

  • as DIPs to match most browsers' screenX/Y, or
  • as CSS pixels to match screenX/Y spec.

Chrome's movementX/Y-in-physical-pixels clearly doesn't look great. We want to change it, see the following possible ways forward:

  1. Modify movementX/Y to DIP to match screenX/Y reality, and keep the PointerLock spec as is.
    This has two advantages: (i) seems like a safe change because sites shouldn't be affected by scale change in movementX/Y, and (ii) if we ever change screenX/Y spec to DIP in future, everything will be good from spec perspective.

  2. Modify movementX/Y to CSS pixels to match screenX/Y spec, and keep the PointerLock spec as is.
    This essentially pulls the screenX/Y problem (that spec doesn't not matching reality, see linked issue above) into PointerLock without a clear benefit: changing most browsers' screenX/Y to match spec is almost impossible; hopefully one day we will change screenX/Y to match browsers instead, which would then call for a change of movementX/Y to DIPs.

  3. Change PointerLock spec to make movementX/Y in physical pixels.
    This completely isolates movementX/Y from screenX/Y coordinate space (and corresponding spec-not-reflecting-reality problem).

Wondering what other browser vendors think about these three options (and possibly other we didn't see).

@NavidZ
Copy link
Member

NavidZ commented Mar 25, 2019

Modify movementX/Y to DIP to match screenX/Y reality, and keep the PointerLock spec as is.
This has two advantages: (i) seems like a safe change because sites shouldn't be affected by scale change in movementX/Y, and (ii) if we ever change screenX/Y spec to DIP in future, everything will be good from spec perspective.

So with this first way if we change screenX/Y spec to DIP first we don't need to change Pointerlock spec either. Right? I know that task has hit some road block. So I'm fine with changing the movementx/y to be DIP on its own. Not sure how to specify it very well though. Do we have all the values needed for that specified already?

@mustaqahmed
Copy link
Member

So I'm fine with changing the movementx/y to be DIP on its own. Not sure how to specify it very well though. Do we have all the values needed for that specified already?

In my first and second points above, I am not proposing any normative spec change at all. I am proposing that browsers would pick one of the two possible interpretations of the current specs (I mean the two interpretations with bullets in my last post). There can be a non-normative note in PointerLock spec though.

@tim-janik
Copy link

Here is one more suggestion to deal with the situation from an API user perspective.

I'm implementing a slider/knob, that can be adjusted by dragging. For the adjustment during dragging, the distance traveled in clientX/Y coordinates can be used.
But when pointer lock is enganged during dragging, the movementX/Y coordinates have to be used instead. The obvious expectation here would be for movementX/Y to match the clientX/Y coordinate space. This seems to work on FF-77 but not Chrome-83 with devicePixelRatio=2. So the idea is:

  1. Modify movementX/Y to CSS to match clientX/Y (or pageX/Y) coordinate space, this needs a wording correction of the PointerLock spec.
    (i) Chrome would have to be fixed to match Firefox' calculations.
    (ii) Changing the screenX/Y spec has no effects on movementX/Y.

Alternatively, movementX/Y could be documented/speced to always be scaled up by devicePixelRatio and FF would need fixing. But that doesn't seem to be consistent with any other coordinate pair exposed by the mouse/pointer events. Related crbug#1092358.

tim-janik added a commit to tim-janik/beast that referenced this issue Jun 14, 2020
Up to at least Chrome/83, the movementX/Y coordinates of a MouseEvent are
incorrectly scaled up by devicePixelRatio. Links for the crbug#1092358 and
the related W3C discussion:

https://bugs.chromium.org/p/chromium/issues/detail?id=1092358
w3c/pointerlock#42

Signed-off-by: Tim Janik <timj@gnu.org>
tim-janik added a commit to tim-janik/beast that referenced this issue Jun 14, 2020
* knob:
  EBEAST: b/knob.vue: keep internal drag position to drag with steppings
  EBEAST: b/knob.vue: allow knob resizing by setting a CSS height
  EBEAST: b/knob.vue: add UI element for scalar inputs
  EBEAST: index.html: embedd ebeast/eknob.svg to reference its SVG elements
  EBEAST: eknob.svg: add knob drawing for <b-knob/> component
  EBEAST: add CONFIG.dpr_movement to work around crbug#1092358
	Up to at least Chrome/83, the movementX/Y coordinates of a MouseEvent are
	incorrectly scaled up by devicePixelRatio. Links for the crbug#1092358 and
	the related W3C discussion:
	https://bugs.chromium.org/p/chromium/issues/detail?id=1092358
	w3c/pointerlock#42
  EBEAST: utilities.js: add capture_event() helper
  EBEAST: wrap data-bubble text and add pointy triangle
  EBEAST: utilities.js: add data_bubble_force() and data_bubble_clear()
  EBEAST: utilities.js: add restarts and animation frame to debounce()
  EBEAST: utilities.js: data_bubble_callback(): update bubbles via callback
  EBEAST: b/hscrollbar.vue: fix hscrolling by using Util.wheel_delta()
	It was barely possible to trigger horizontal scrolling in Firefox.
	Now wheel_delta() normalizes the pixel distance so Firefox behviour
	comes close to Chromium, allthough its steps are less fine grained.
  EBEAST: utilities.js: add wheel_delta() for normalized scroll deltas
  EBEAST: b/fed-object.vue: add typedata blurbs as data-bubble
  EBEAST: b/fed-number.vue: avoid bogus browser generated title tooltip
  EBEAST: b/fed-object.vue: refactor inline array into named object fields
  EBEAST: b/color-picker.vue: use data-bubble="" for color info popups
  EBEAST: utilities.js: hide data-bubble on mouseleave (window looses focus)
  EBEAST: app.scss: fix data-bubble z-index
  EBEAST: utilities.js: hide data-bubble on resize and mousedown
  EBEAST: utilities.js: move ResizeObserver compat decl to the top
  EBEAST: support free floating tooltips via a data-bubble="" attribute
  EBEAST: utilities.js: add matches_forof() to search iteratables
  EBEAST: cssaux.scss: provide dppx() to deal with device pixels
  EBEAST: index.html: provide a --device-pixel-ratio CSS variable
	Allow specification of CSS sizes in device pixels.
  EBEAST: index.html: disable Vuejs `performance` config to fix leaks
	Firefox (76), Chrome (83) and Electron (7) all show major memory
	leakage during animation rendering when the Vuejs `performance`
	config is enabled which uses the performance.measure() web API.
	The leaks strangely occour *outside* of the JS heap which shows
	steady usage of a few dozen megabytes while the browser process
	footprint goes through the roof (gigabytes).

Signed-off-by: Tim Janik <timj@gnu.org>
@BlobTheKat
Copy link

Seriously, how long is this going to take? Are there any work arounds for now?

@trusktr
Copy link

trusktr commented Jan 11, 2024

Can we please get this fixed. movementX, movementY, and movementZ are not reliable at all without consistent units.

For consistency, CSS pixel seem would be the best (a user can multiply by devicePixelRatio to convert to physical if they wish).

This will align with px in CSS which means that mapping movementX, for example, to a difference in width or transform will simply work. f.e.

el.style.width = currentWidth + event.movementX + 'px'

Right now, that will produce weird results where the element being moved or resized will move or resize differently than expected.

The workaround right now is to instead never use movement* properties, and calculate the value directly using some math using the client* properties.

const movementX = event.clientX - previousClientX
const movementY = event.clientY - previousClientY

This has been working better for me, but I haven't tested with user zoom.

It seems like basing it on CSS pixels is the way to make it result in correct calculation based on the web content. I've never wanted the delta to be anything other than aligned with the content (which means CSS pixels).

@trusktr
Copy link

trusktr commented Jan 11, 2024

Here's a demo showing movementX is not usable in Chrome (on a macbook air m2 with dpr 2):

https://codepen.io/trusktr/pen/OJqROvd/823fc7ec003e4652d97ff13e32d91b80

When you drag left/right on the demo, notice the mouse moves different speed than then orange border.

Here's a demo using movementX = event.clientX - previousClientX, and it works as expected, dragging moves the box at the same speed as the mouse:

https://codepen.io/trusktr/pen/gOEwXdZ/6257b761fdc13f2b7c354ed2cf422af4

@neonfuz
Copy link

neonfuz commented Jan 12, 2024

Here's a demo showing movementX is not usable in Chrome (on a macbook air m2 with dpr 2):

https://codepen.io/trusktr/pen/OJqROvd/823fc7ec003e4652d97ff13e32d91b80

When you drag left/right on the demo, notice the mouse moves different speed than then orange border.

Here's a demo using movementX = event.clientX - previousClientX, and it works as expected, dragging moves the box at the same speed as the mouse:

https://codepen.io/trusktr/pen/gOEwXdZ/6257b761fdc13f2b7c354ed2cf422af4

I would like to point out this is zoom level dependent. On my monitor the first demo worked fine until I zoomed in.

tim-janik added a commit to tim-janik/anklang that referenced this issue Feb 8, 2024
tim-janik added a commit to tim-janik/anklang that referenced this issue Feb 8, 2024
…e and Firefox

* MOUSE-WHEEL:
  ui/util.js: remove unused wheel2scrollbars
  ui/b/pianoroll.js: reinstante hzoom and vzoom adjustments via Ctrl
  ui/util.js: use Mouse.wheel_delta()
  ui/b/knob.js: use Mouse.wheel_delta()
  ui/b/pianoroll.js: properly scroll via deltaY from Mouse.wheel_delta()
  ui/mouse.js: wheel_delta(): provide .x, .y, .z in pixels
  ui/b/app.js: defer ZMove handling to mouse.js
  ui/mouse.js: include ZMove notification handling
  ui/index.html: start mouse.js early on
  ui/mouse.js: add event_movement() and wheel_delta() to fix event coords
	Cross browser normalization of movementX,movementY and deltaX,deltaY is a hot mess, see:
	https://bugs.chromium.org/p/chromium/issues/detail?id=1092358
	https://bugzilla.mozilla.org/show_bug.cgi?id=1392460
	w3c/uievents#181
	w3c/pointerlock#42
	mdn/content#11811
  ui/index.html: disable modulepreload, it causes module errors in Firefox-122

Signed-off-by: Tim Janik <timj@gnu.org>
@psnet
Copy link

psnet commented May 9, 2024

This is important topic

@BlobTheKat
Copy link

Can we bump the priority of this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants