perf(zoom): only register wheel listener while Ctrl/Meta is held
The zoom-on-Ctrl-wheel handler was registered on `window` for the
lifetime of the app with `{ passive: false, capture: true }`. That
flag combination forces the browser to wait for the handler to return
on EVERY wheel event before applying scroll — even though the handler
exits at line 1 when no modifier is held. The user reported a
characteristic input lag: scrollbar-drag was perfectly smooth, mouse-wheel
was choppy. His description ("como si la ventana principal lo cachara y
lo mandara al div interno y eso causara ese input lag") was literal —
the capture-phase non-passive listener intercepts the event at window
before routing to the scroll container.
Refactor: track Ctrl/Meta state via keydown/keyup and register the
non-passive wheel listener only while a modifier is actually held.
Default state = no wheel listener at all → browser native fast-path.
`window blur` releases the listener if the user alt-tabs with Ctrl held
(otherwise keyup never fires).
cc
This commit is contained in:
1 file changed
+52
-3
@@ -75,10 +75,59 @@ function handleZoomWheel(event: WheelEvent): void {
|
|||||||
void applyZoomLevel(nextZoom);
|
void applyZoomLevel(nextZoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zoom-on-Ctrl-wheel handling.
|
||||||
|
*
|
||||||
|
* Previously this registered a non-passive, capture-phase `wheel` listener
|
||||||
|
* on `window` for the lifetime of the app. The non-passive flag (required
|
||||||
|
* so `preventDefault` actually stops the WebView's native Ctrl+wheel zoom)
|
||||||
|
* also tells the browser "wait for my handler before applying scroll" —
|
||||||
|
* which kills the native fast-path for *every* wheel event in the app,
|
||||||
|
* not just zoom-modified ones. The user perceived this as choppy mouse-wheel
|
||||||
|
* scrolling vs perfectly-smooth scrollbar-drag scrolling.
|
||||||
|
*
|
||||||
|
* New approach: the wheel listener only exists while Ctrl/Meta is held.
|
||||||
|
* Keydown registers it, keyup (or window blur) unregisters it. Net:
|
||||||
|
* - 99% of normal scrolling: no wheel listener at all, browser fast-path
|
||||||
|
* - During zoom (Ctrl held): non-passive listener active, preventDefault
|
||||||
|
* still blocks native zoom and our `applyZoomLevel` runs
|
||||||
|
*/
|
||||||
|
const ZOOM_WHEEL_OPTIONS: AddEventListenerOptions = { passive: false, capture: true };
|
||||||
|
let zoomWheelActive = false;
|
||||||
|
|
||||||
|
function registerZoomWheel(): void {
|
||||||
|
if (zoomWheelActive) return;
|
||||||
|
zoomWheelActive = true;
|
||||||
|
window.addEventListener('wheel', handleZoomWheel, ZOOM_WHEEL_OPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterZoomWheel(): void {
|
||||||
|
if (!zoomWheelActive) return;
|
||||||
|
zoomWheelActive = false;
|
||||||
|
window.removeEventListener('wheel', handleZoomWheel, ZOOM_WHEEL_OPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleZoomKeyDown(e: KeyboardEvent): void {
|
||||||
|
if (e.ctrlKey || e.metaKey) registerZoomWheel();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleZoomKeyUp(e: KeyboardEvent): void {
|
||||||
|
// After any keyup, if neither modifier is held anymore, drop the listener.
|
||||||
|
if (!e.ctrlKey && !e.metaKey) unregisterZoomWheel();
|
||||||
|
}
|
||||||
|
|
||||||
export function setupZoomControls(): () => void {
|
export function setupZoomControls(): () => void {
|
||||||
const options: AddEventListenerOptions = { passive: false, capture: true };
|
window.addEventListener('keydown', handleZoomKeyDown);
|
||||||
window.addEventListener('wheel', handleZoomWheel, options);
|
window.addEventListener('keyup', handleZoomKeyUp);
|
||||||
return () => window.removeEventListener('wheel', handleZoomWheel, options);
|
// Releases the listener if the user alt-tabs with Ctrl held — otherwise
|
||||||
|
// the keyup never fires and we stay in the slow path.
|
||||||
|
window.addEventListener('blur', unregisterZoomWheel);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('keydown', handleZoomKeyDown);
|
||||||
|
window.removeEventListener('keyup', handleZoomKeyUp);
|
||||||
|
window.removeEventListener('blur', unregisterZoomWheel);
|
||||||
|
unregisterZoomWheel();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ Last.fm Session ============
|
// ============ Last.fm Session ============
|
||||||
|
|||||||
Reference in new issue
Block a user