Skip to content

feat(RenderWindowInteractor): add optional mouseWheelSpinYBuffering - #3623

Open
yehor-murza-lx wants to merge 1 commit into
Kitware:masterfrom
yehor-murza-lx:feat/optional-mouse-wheel-spinY-buffering
Open

feat(RenderWindowInteractor): add optional mouseWheelSpinYBuffering#3623
yehor-murza-lx wants to merge 1 commit into
Kitware:masterfrom
yehor-murza-lx:feat/optional-mouse-wheel-spinY-buffering

Conversation

@yehor-murza-lx

Copy link
Copy Markdown

Motivation

High-frequency wheel input devices (e.g. trackpads) can emit many small fractional spinY deltas in quick succession. Consumers of �tkRenderWindowInteractor that map wheel events directly to camera zoom/dolly can end up with jittery or overly sensitive interactions as a result.

Change

  • Adds an opt-in mouseWheelSpinYBuffering flag (default alse). When enabled, fractional spinY deltas are accumulated per interactor instance and a mouseWheelEvent is only dispatched once the buffered spin reaches a full step (rounded via Math.sign). The buffer resets when the scroll direction reverses and when the wheel-end debounce fires.
  • Adds a configurable wheelEndDebounceDelay (default 200, matching the previous hardcoded value) so consumers can tune how long to wait after the last wheel event before the wheel-end event fires.
  • Updates the corresponding TypeScript definitions (index.d.ts).

Backward compatibility

Both new properties default to values that reproduce the current behavior exactly (mouseWheelSpinYBuffering: false disables buffering entirely; wheelEndDebounceDelay: 200 matches the previous hardcoded timeout), so no existing consumer behavior changes unless they opt in.

Testing

pm run reformat and lint (oxlint) pass with no issues.

  • Manually verified against a downstream application that previously carried this behavior as a local patch; setting mouseWheelSpinYBuffering(true) reproduces that smoothing behavior.

High-frequency wheel devices (e.g. trackpads) can emit many small fractional
spinY deltas in quick succession, causing jittery or overly sensitive zoom/
rotate interactions in consumers of vtkRenderWindowInteractor.

Add an opt-in mouseWheelSpinYBuffering flag (default false) that, when
enabled, accumulates fractional spinY deltas per interactor instance and
only dispatches a mouseWheelEvent once the buffered spin reaches a full
step. The buffer resets on direction change and on wheel-end.

Also add a configurable wheelEndDebounceDelay (default 200, matching the
previous hardcoded value) so consumers can tune how long to wait after the
last wheel event before firing the wheel-end event.

Both properties default to the existing behavior, so this change is fully
backward compatible.
callData.spinY = Math.sign(scrollBuffer);
scrollBuffer -= callData.spinY;
publicAPI.mouseWheelEvent(callData);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move things around to cleanup the logic:
If (wheeleventid ==) {
Startmousewheelevent();
} Else {
ClearTimeout();
}

If (not wheelbuferring or ...)
Mousewheelevent();
}

...

model.mouseWheelSpinYBuffering &&
Math.abs(scrollBuffer) >= SCROLL_THRESHOLD
) {
callData.spinY = Math.sign(scrollBuffer);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think spinY should be 3 (and not 1) if the scroll buffer is 3.2 (maybe the last event added 2.3 to the buffer)

model.wheelTimeoutID = setTimeout(() => {
publicAPI.extendAnimation(600);
publicAPI.endMouseWheelEvent();
model.wheelTimeoutID = 0;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please take the opportunity to move wheeltimeoutid out of model?

'preventDefaultOnPointerDown',
'preventDefaultOnPointerUp',
'mouseScrollDebounceByPass',
'wheelEndDebounceDelay',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of exposing the delay. But in such a case it duplicates the debouncebypass. Please consolidate both (e.g. a delay of null or 0 is equivalent to a debounce by pass). Let's not break the api for now and simply create a warning that the debounce by pass is now obsolete.

@finetjul

finetjul commented Sep 2, 2026

Copy link
Copy Markdown
Member

We now have a case when a startmousewheelevent may not be followed by a mouse event. Please check in the code base that it is fine. I think I remember that assumption to be expected

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

Successfully merging this pull request may close these issues.

3 participants