Improved wheel-zoom support for mice/OSes that report inaccurate/imprecise scroll wheel deltas
ubmarco opened this issue · comments
Environment info
- Cytoscape.js version : 3.31.0
- Browser/Node.js & version : On Arch Linux x64 XFCE, Firefox, Chromium, Brave, Edge
Current (buggy) behaviour
Zoom too fast or too much on a single mouse wheel event.
Peek.2025-02-26.15-37.mp4
Browsers:
Chromium Brave
Firefox Edge
Desired behaviour
Cross OS and cross browser smooth zoom behavior.
Minimum steps to reproduce
- Go to https://cytoscape.org/cytoscape.js-dagre/
- Move the mouse wheel to zoom the image
When inserting
window.addEventListener("wheel", event => console.info(event.deltaY));
into the browser console, I get values of +120 and -120 or +132 and -132 on the different browsers.
A user on Mac just gets values between -2 and +2 and smooth zooming.
Changing the Firefox setting mousewheel.system_scroll_override.vertical.factor
from the default of 200 to 20 helps. It makes the overall scrolling super slow, so no solution.
Changing https://js.cytoscape.org/#init-opts/wheelSensitivity helps, but it only helps on one system and breaks others.
I think the code should normalize the deltaY
value of the wheel
event.
For reviewers
Reviewers should ensure that the following tasks are carried out for incorporated issues:
- Ensure that the reporter has included a reproducible demo. They can easily fork this JSBin demo: http://jsbin.com/fiqugiq
- The issue has been associated with a corresponding milestone.
- The commits have been incorporated into the corresponding branches. Bug-fix patches go on
-
master
and -
unstable
.
-
- The issue has been labelled as a
bug
, if necessary.
I think the code should normalize the
deltaY
value of thewheel
event.
What sort of normalisation do you propose?
Good question. I never implemented a zoom feature in JS. I'd peek into other packages that handles zoom differently.
(I don't want to advertise other solutions. I just want to take a look to see how things can be improved.)
E.g. the zoom for visjs or G6 works good on my machine:
https://visjs.github.io/vis-network/examples/network/layout/hierarchicalLayout.html
https://g6.antv.antgroup.com/en/examples/layout/force-directed/#d3-force
For G6 they use clamping of the lower/upper deltaY value together with a sensitivity:
https://github.com/antvis/G6/blob/5.0.44/packages/g6/src/behaviors/zoom-canvas.ts
https://github.com/antvis/G6/blob/5.0.44/packages/g6/src/behaviors/zoom-canvas.ts#L155
For visjs they translate wheel rotations to +1 or -1 and select the next zoom level based on the current value:
https://github.com/visjs/vis-network/blob/v9.1.9/lib/network/modules/InteractionHandler.js#L599
Not sure however how the other libraries work on all systems, I just tested on my Xfce Arch Linux.
The user share of Cytoscape.js is something like this, from most common to least common. Each level is much smaller than the previous level.
- Laptops with good trackpad support (Macs & Windows laptops)
- Tablets and phones
- Desktop Windows computers, with varying mouse quality (some report scroll wheel values properly, some do not)
- Linux computers
Only (3) and (4) are affected by this GitHub issue.
The visjs approach quoted is therefore terrible in this context, as it sacrifices the experience of most users for a very small minority of users -- (1), (2), and some of (3) are worsened for the benefit of (4) and some other parts of (3).
The clamping approach could be useful as long as it doesn't negatively affect (1), (2), and (3). That is difficult to guarantee as you can, for example, make large scrolls all at once on trackpads. This would require experimentation and probably a heuristic to be viable -- e.g. detect if you have a poorly-behaving OS/mouse combo and only then apply the clamping.
Off the top of my head, one heuristic might be to detect the first N (N>=2) scroll events in the page and see whether they are of equal magnitude and of large magnitude. That indicates a high likelihood of a poor scroll system, with a low likelihood of false positives. Those first events would have to be ignored w.r.t. causing a change in zoom level. If those scroll events happen outside of the Cytoscape network, all the better. This approach comes with the assumption that eating the first few scroll events wouldn't be noticed by the user, in the case where those events do happen in the Cytoscape network.
Adding to the 3.32.0 milestone, assuming the answer is yes
Yes sure will test this. Thanks a lot.
For what it's worth, I'm seeing deltaY
values of ±102
in latest Firefox, and ±100
in latest Chrome/Edge, using a high-quality Logitech mouse on Windows 11 (with just the Windows 11 defaults for any mouse-related settings). I also thought Cytoscape.js zooming felt far too fast, so I came searching to see if there was some known issue.
Note: There's logging in the branch so you can see exactly how it's working. You can report your values/logs here.
A visual reference of the scroll resulting from a single wheel
event as emitted from one "notch" of scrollwheel interaction in Firefox on Windows 11:
A representative wheel
event from this same session (all wheel
events reported the same deltaY
of 102
with 100% consistency, regardless of scrollwheel interaction amount or speed etc):
altKey: false
bubbles: true
button: 0
buttons: 0
cancelBubble: false
cancelable: true
clientX: 230
clientY: 1124
composed: true
ctrlKey: false
currentTarget: null
defaultPrevented: false
deltaMode: 0
deltaX: 0
deltaY: 102
deltaZ: 0
detail: 0
eventPhase: 0
explicitOriginalTarget: <div class="Box-sc-g0xbh4-0 fGkgDM I…eViewerContainer--flht4">
isTrusted: true
layerX: 230
layerY: 5128
metaKey: false
movementX: 0
movementY: 0
offsetX: 230
offsetY: 4865
originalTarget: <div class="Box-sc-g0xbh4-0 fGkgDM I…eViewerContainer--flht4">
pageX: 230
pageY: 5232
rangeOffset: 0
rangeParent: null
relatedTarget: null
returnValue: true
screenX: 1199
screenY: 1868
shiftKey: false
srcElement: <div class="Box-sc-g0xbh4-0 fGkgDM I…eViewerContainer--flht4">
target: <div class="Box-sc-g0xbh4-0 fGkgDM I…eViewerContainer--flht4">
timeStamp: 2795984
type: "wheel"
view: Window https://github.com/cytoscape/cytoscape.js/issues/3336#issuecomment-2769995538
wheelDelta: -306
wheelDeltaX: 0
wheelDeltaY: -306
which: 1
x: 230
y: 1124
For a deltaMode
of 0
(which is what I'm seeing in my emitted wheel
events), a deltaY
value of 102
looks 100% accurate here in Firefox, given the actual vertical shift (as measured in pixels) from a single "notch" of the wheel. From looking around the web at how other packages have encountered and attempted to solve this common issue, it sounds like this is a result of some platforms (including most common trackpad platforms) using an internal wheel acceleration factor, while other platforms don't.
That said, based on your breakdown of relative user share across platforms/devices for Cytoscape.js, I fully understand why you would need to make handling this consistent, accurate, non-accelerated deltaY
the special case rather than the norm.
Well put, @Joudan-Sokutogeri. Lousy mice don't allow you to scroll or zoom to exactly where you want. They zoom and scroll really quickly, just like in your example. 100px is huge.
@ubmarco @Joudan-Sokutogeri, try out the PR #3363 and let us know if/how it works for you