Skip to content

Commit

Permalink
Improve wheel event handling
Browse files Browse the repository at this point in the history
  • Loading branch information
inokawa committed Jan 16, 2024
1 parent e483ba3 commit 2e62169
Showing 1 changed file with 34 additions and 32 deletions.
66 changes: 34 additions & 32 deletions src/core/scroller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,19 @@ const createScrollObserver = (
getScrollOffset: () => number,
updateScrollOffset: (value: number, isMomentumScrolling: boolean) => void
) => {
const now = Date.now;

let lastScrollTime = 0;
let wheeling = false;
let touching = false;
let justTouchEnded = false;
let stillMomentumScrolling = false;

const onScrollEnd = debounce(() => {
if (touching) {
// Wait while touching
if (wheeling || touching) {
wheeling = false;

// Wait while wheeling or touching
onScrollEnd();
return;
}
Expand All @@ -53,6 +59,8 @@ const createScrollObserver = (
}, 150);

const onScroll = () => {
lastScrollTime = now();

if (justTouchEnded) {
stillMomentumScrolling = true;
}
Expand All @@ -63,36 +71,30 @@ const createScrollObserver = (

// Infer scroll state also from wheel events
// Sometimes scroll events do not fire when frame dropped even if the visual have been already scrolled
const onWheel = (() => {
const now = Date.now;
const ms = 50;
let time = now() - ms;

return (e: WheelEvent) => {
const n = now();
if (time + ms < n) {
time = n;

if (
// Scroll start should be detected with scroll event
store._getScrollDirection() === SCROLL_IDLE ||
// Probably a pinch-to-zoom gesture
e.ctrlKey
) {
return;
}
// Get delta before checking deltaMode for firefox behavior
// https://github.com/w3c/uievents/issues/181#issuecomment-392648065
// https://bugzilla.mozilla.org/show_bug.cgi?id=1392460#c34
if (isHorizontal ? e.deltaX : e.deltaY) {
const offset = store._getScrollOffset();
if (offset > 0 && offset < store._getMaxScrollOffset()) {
onScrollEnd();
}
}
}
};
})() as (e: Event) => void; // FIXME type error. why only here?
const onWheel = ((e: WheelEvent) => {
if (
wheeling ||
// Scroll start should be detected with scroll event
store._getScrollDirection() === SCROLL_IDLE ||
// Probably a pinch-to-zoom gesture
e.ctrlKey
) {
return;
}

const timeDelta = now() - lastScrollTime;
if (
// Check if wheel event occurs some time after scrolling
50 < timeDelta &&
150 > timeDelta &&
// Get delta before checking deltaMode for firefox behavior
// https://github.com/w3c/uievents/issues/181#issuecomment-392648065
// https://bugzilla.mozilla.org/show_bug.cgi?id=1392460#c34
(isHorizontal ? e.deltaX : e.deltaY)
) {
wheeling = true;
}
}) as (e: Event) => void; // FIXME type error. why only here?

const onTouchStart = () => {
touching = true;
Expand Down

0 comments on commit 2e62169

Please sign in to comment.