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

Needs alternative WheelEvent.deltaMode, WheelEvent.delta(X|Y|Z) #181

Open
masayuki-nakano opened this issue Feb 11, 2018 · 27 comments
Open

Comments

@masayuki-nakano
Copy link

masayuki-nakano commented Feb 11, 2018

Currently, unit of WheelEvent.delta(X|Y|Z) value is defined by WheelEvent.deltaMode in UI Events. However, Chrome and Edge almost always fire wheel events with WheelEvent.DOM_DELTA_PIXEL. Therefore, a lot of web sites are broken on Gecko which is the only browser firing wheel events with native event's units.

So, for backward compatibility, WheelEvent.deltaMode should return always WheelEvent.DOM_DELTA_PIXEL, unfortunately. However, some better web application developers may want raw delta(X|Y|Z) values as far as possible.

Therefore, I'd like to propose that UI Events should declare that WheelEvent.delatMode always return WheelEvent.DOM_DELTA_PIXEL and WheelEvent.delta(X|Y|Z) are delta values in pixels. Additionally, there should be alternative attributes which are set raw event information. E.g., WheelEvent.rawDelta(Mode|X|Y|Z).

@masayuki-nakano
Copy link
Author

Bug of Firefox is here: https://bugzilla.mozilla.org/show_bug.cgi?id=1392460

If it'd be possible, there should've been:

  • WheelEvent.pixelDeltaX
  • WheelEvent.pixelDeltaY
  • WheelEvent.pixelDeltaZ
  • WheelEvent.rawDeltaMode
  • WheelEvent.rawDeltaX
  • WheelEvent.rawDeltaY
  • WheelEvent.rawDeltaZ
    However, we've met this issue with existing attributes, Wheel.delta*. We cannot rename them to pixelDelta*, unfortunately...

@masayuki-nakano
Copy link
Author

@garykac Could you take a look? This is really annoying Spec issue. (Perhaps, some Chrome for Windows users have same issue as users of Firefox for Windows or Linux users since Chrome uses DOM_DELTA_PAGE if user sets per-page-scroll in the system settings.)

@garykac
Copy link
Member

garykac commented May 24, 2018

To summarize the proposal:

Because many web developers don't respect the deltaMode setting and simply assume that delta* always returns pixel values, we're proposing changing delta* to always return pixel values.

  • Change definition of deltaMode to always return DOM_DELTA_PIXEL
  • Change definition of delta(X|Y|Z) to always return pixels values
    • This will be a change for Firefox, but not for Chrome, Edge and Safari.
  • Add rawDelta(X|Y|Z) and rawDeltaMode so that sites that want the non-pixel deltas, can explicitly request it.
    • The simplest implementation would be to duplicate the previous definition for deltaX and deltaMode. Although browsers may choose to return LINE or PAGE since PIXEL is already covered.

This change won't affect sites that properly check the deltaMode attribute, but it would break any site that assumes Firefox == DOM_PIXEL_LINE without actually checking deltaMode.

Sites that currently take advantage of Firefox's non-pixel deltas will no longer do so until they switch to use the new attributes on the event.

@masayuki-nakano
Copy link
Author

FYI: As far as I've tested, deltaMode value of each browser:

  • Windows (system setting is set to multiple line scroll)
    • Edge: DOM_DELTA_PIXEL
    • Chrome: DOM_DELTA_PIXEL
    • Firefox: DOM_DELTA_LINE
  • Windows (system setting is set to per page scroll)
    • Edge: DOM_DELTA_PIXEL
    • Chrome: DOM_DELTA_PAGE
    • Firefox: DOM_DELTA_PAGE
  • macOS (trackpad)
    • Safari: DOM_DELTA_PIXEL
    • Chrome: DOM_DELTA_PIXEL
    • Firefox: DOM_DELTA_PIXEL
  • macOS (mouse)
    • Safari: DOM_DELTA_PIXEL
    • Chrome: DOM_DELTA_PIXEL
    • Firefox: DOM_DELTA_LINE
  • Linux
    • Firefox: DOM_DELTA_LINE
    • Chrome: DOM_DELTA_PIXEL

@garykac
Copy link
Member

garykac commented Jun 5, 2018

@RByers @travisleithead Any thoughts on this proposal?

@RByers
Copy link

RByers commented Jun 6, 2018

I've seen this difference between Chrome and Firefox cause real compat problems on real sites, so I support trying to fix it. I agree that delta is so often pixel that it's safer to require that it ALWAYS be pixel.

So the proposal seems reasonable to me, though I worry we might just have the same problem with rawDeltaMode. It seems to me having any property whose units vary based on another property is potentially problematic. Why not have linesDeltaX/Y and pageDeltaX/Y values (which could be undefined)? The Z axis almost certainly doesn't make sense for lines/pages, right? Does the X axis have a sensible and useful definition for lines?

Anyway @NavidZ is the Chrome expert here, so this is just my $0.02 - I don't have objections either way.

@wisniewskit
Copy link

Let's try to get some momentum going on this one again :)

@NavidZ, mind chiming in with your thoughts?

@masayuki-nakano, what do you think about the concern @RByers raised?

For what it's worth, I feel Rick has a good point and suggestion here. I feel that the default behavior should be consistent, as in my experience working on webcompat, web pages almost always presume pixel values and aren't even aware that there are other potential units. I feel that making the existing property a legacy (and pixel-only) value would be best, along with new properties that are specific to the units.

In fact I wonder if there is even a need to have "pages" and "lines" values at all (as well as a variable default unit)? I also wonder if they aren't a potential fingerprinting vector in some way?

@masayuki-nakano
Copy link
Author

(Sorry, I didn't realize the mention here.)

Yes, sounds like that's great idea. I agree with it.

However, I have a concern about implementing it. For making it, each implementation should have computed value of lineDeltaX/Y and pageDeltaX/Y or line height or page height/width for computing them later since events may be stored with variables and may be referred later (i.e., after ending the propagation).

I don't mind the cost as a developer of Mozilla DOM Events, but I'm not sure how other browser developers.

And in my understanding, the line height, page width and page height values are used the value at dispatching wheel event rather than the attributes are accessed. So, I hope that UI Events should define:

  1. When these reference values are fixed.
  2. Which element's size should be referred (Event.target? Nearest ancestor scrollable Element? Root element?).

@CWies
Copy link

CWies commented Nov 19, 2019

@masayuki-nakano could you add the unit in which the values(deltaX/Y/Z) are actually returned to your list above? I found that, on Windows, when set to multiple line scroll, the actual unit is always lines, and when set to pages it is always pages. Though I have neither a macOS nor a Linux device. Are they always returned in lines? I am especially wondering about macOS with trackpad, since firefox also uses pixels there.

@masayuki-nakano
Copy link
Author

@CWies Isn't you asking about what I commented in #181 (comment) ?

@CWies
Copy link

CWies commented Nov 20, 2019

@masayuki-nakano As I understand, thats what deltaMode returns in each browser. Though I need to know in which unit deltaX/Y/Z are actually returned, because in my testing, both edge and chrome, while returning DOM_DELTA_PIXEL for deltaMode, only give values of 1 for deltaX/Y/Z every time i turn the scrollwheel to the next step, which is actually 1 Line and not 1 Pixel(as far as i understand)

@masayuki-nakano
Copy link
Author

I need to know in which unit deltaX/Y/Z are actually returned

The value can be checked with deletaMode as you know.

because in my testing, both edge and chrome, while returning DOM_DELTA_PIXEL for deltaMode, only give values of 1 for deltaX/Y/Z every time i turn the scrollwheel to the next step, which is actually 1 Line and not 1 Pixel

Don't you see a lot of wheel events in such case? If so, the device tries to scroll smoothly with splitting one action to multiple wheel events.

@CWies
Copy link

CWies commented Nov 21, 2019

Don't you see a lot of wheel events in such case?

No... both on edge and chrome not

The value can be checked with deletaMode as you know.

Why the whole discussion then? Shouldnt something like
if (mode == 0) multiplier = 1; else if (mode == 1) multiplier = Number( window .getComputedStyle(document.body) .getPropertyValue("font-size") .match(/\d+/)[0] ); else if (mode == 2) multiplier = window.innerHeight; else multiplier = 0;
solve any problems? I mean it shouldnt matter in what unit they are returned, as long as you know the unit...

@masayuki-nakano
Copy link
Author

masayuki-nakano commented Nov 21, 2019

@CWies because we got some web-compat issues which some web apps don't check deltaMode even though they refer delta(X|Y).

@CWies
Copy link

CWies commented Nov 21, 2019

Well but that should be their issue, right?

@masayuki-nakano
Copy link
Author

@CWies Right, but such web developers check only on Chrome typically (meaning which has most market share). Therefore, other browsers may need to use same behavior (i.e., using DELTA_MODE_PIXEL) for their users. However, if all browsers just do so, web developers who want raw delta value of native events cannot treat them anymore. Therefore, before switching Firefox's behavior, I suggest new API to retrieve raw delta value.

@karlcow
Copy link
Member

karlcow commented Mar 9, 2021

See also Intent to ship: Return pixel deltas in wheel event if deltaMode is not checked by authors

( s/WheelEvent.delat/WheelEvent.delta/ in the title )

@karlcow
Copy link
Member

karlcow commented Aug 18, 2021

A bit of status here.

Note that this debate was referenced in
svgdotjs/svg.panzoom.js#67
And this is the way they fixed it
https://github.com/svgdotjs/svg.panzoom.js/pull/68/files

We are also having yet another discussion on zoomPan function for openstreetmap related to the same topics.
webcompat/web-bugs#73148

In Mozilla bug, deltaMode default should be DOM_DELTA_PIXEL, @emilio exposed DOM_DELTA_PIXEL rather than DOM_DELTA_LINES to the web

Important: https://bugzilla.mozilla.org/show_bug.cgi?id=1392460#c34

It returns pixels unless deltaMode is checked before getting the delta. If you prefer pixels, you can get the delta before checking deltaMode (and deltaMode would return pixels with the fix for this bug).

This is available only on Nightly so far.

@christianliebel christianliebel changed the title Needs alternative WheelEvent.deltaMode, WheelEvent.delat(X|Y|Z) Needs alternative WheelEvent.deltaMode, WheelEvent.delta(X|Y|Z) Sep 12, 2022
@zcorpan
Copy link
Member

zcorpan commented Jan 3, 2023

Important: https://bugzilla.mozilla.org/show_bug.cgi?id=1392460#c34

It returns pixels unless deltaMode is checked before getting the delta. If you prefer pixels, you can get the delta before checking deltaMode (and deltaMode would return pixels with the fix for this bug).

This behavior is now shipping in Firefox but is causing confusion for web developers, see pixijs/pixijs#8970

I think we should instead do what @RByers suggested in #181 (comment)

@NavidZ and @smfr do you have thoughts about @masayuki-nakano computation cost concern in #181 (comment) ?

@thasmo
Copy link

thasmo commented Jan 17, 2023

This behavior is now shipping in Firefox but is causing confusion for web developers, see pixijs/pixijs#8970

Wow, that oddity tripped me up bad.

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 <[email protected]>
@trusktr
Copy link

trusktr commented Mar 22, 2024

I'd like to propose that UI Events should declare that WheelEvent.delatMode always return WheelEvent.DOM_DELTA_PIXEL and WheelEvent.delta(X|Y|Z) are delta values in pixels

Even in cases when this is already true across browsers, deltaX/Y/Z vary wildly not only across browsers, but across operating systems, and maybe even across hardware.

Is there something we can add to specs to fix this so that we can get a value that is consistent across all browser and OS combinations?

Uses cases where this it is problematic is when building custom interaction using mouse and touchpad scroll, for example zoom controls for a 3D scene using canvas (webgl/webgpu) for custom rendering. It is nearly impossible to make the behavior of a custom interaction behave the same in all browser/OS combos, so much so that most people just pick a sensitivity value that is good enough across all browsers (a little slow in some, a little fast in some, but overall acceptable across all).

And even today after the Firefox bug with is already fixed, the deltaMode behavior still varies across browsers.

Examples of inconsistencies in the wild:

@zaygraveyard
Copy link

I would like to also add that on macOS the scroll direction can be flipped (natural vs normal) which renders scroll-based interactions that don't scroll content (as @trusktr mentioned) inconsistent unless the scroll event includes this information (if the direction is flipped). Not to mention macOS's inertial scrolling.

For context, I'm a developer of an online data visualizer for exploring satellite data on a map (the Ocean Virtual Lab is an example). The scroll interaction is used in multiple components:

  • to zoom the map in/out (changes in steps, not continuously)
  • to change the transparency of a layer (changes continuously)
  • to change the current time (changes continuously)
  • to change the value of <input type=range>-like inputs (changes in steps, or continuously)

And I have yet to find a way to iron-out the inconsistencies in scroll events between different browser and platforms 😔

PS: I apologize if these problems are out-of-scope for this issue, I just don't know where else to go

@zaygraveyard
Copy link

After conducting a survey on wheel deltas, I found the deprecated wheelDelta* properties are generally more consistent across platforms and browsers.
Motivated by these findings we updated the web app mentioned above to use wheelDelta* properties, except on Apple systems (macOS, iOS, iPadOS, ...) for which we still use delta* properties.

Example:

function getWheelDelta(event) {
  if (isApple) {
    // Note that deltaMode MUST be accessed BEFORE delta* in order to get
    // non-pixel values in Firefox.
    // See https://github.com/w3c/uievents/issues/181

    switch (event.deltaMode) {
    default:
    case event.DOM_DELTA_PIXEL:
      return [event.deltaX / 120, -event.deltaY / 120];
    case event.DOM_DELTA_LINE:
    case event.DOM_DELTA_PAGE:
      // Discard the delta value, just take the sign
      return [Math.sign(event.deltaX), Math.sign(-event.deltaY)];
    }
  } else {
    return [-event.wheelDeltaX / 120, event.wheelDeltaY / 120];
  }
}

@karlcow
Copy link
Member

karlcow commented Jul 15, 2024

@zaygraveyard what do you use for isApple?

@zaygraveyard
Copy link

@karlcow The detection is based on navigator.platform and is very basic, but works well enough:

const isApple = /^Mac|iPhone|iPod|iPad/i.test(navigator.platform);

@zaygraveyard
Copy link

I fell down this rabbit-hole again recently and found a (mostly) undocumented but interoperable behavior:
Pinch gesture on an Apple trackpad generates a wheel event with its ctrlKey set to true (even when the control key is not pressed).

Tested on a M1 MacBook Air with macOS Sonoma 14.6.1

  • Firefox Developer Edition v131.0b9
  • Google Chrome v128.0.6613.85
  • Safari v18

I found this while trying to understand how tldraw is able to distinguish between a two-finger pinch and a two-finger drag.

@zaygraveyard
Copy link

Plus I found that many projects have a function to normalize the differences between wheel event deltas, like Facebook's normalizeWheel and tldraw's. And GitHub search for that function returns 4.8k results.

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

No branches or pull requests

10 participants