kineticscroll - Better scrolling behaviour

* Passthrough scrolling directly as long as finger stays on display
* Reset velocity in case last drag event took longer than 150ms
master
Martin Boonk 2024-03-25 19:08:46 +01:00
parent b9287dbf99
commit 773491782e
1 changed files with 53 additions and 29 deletions

View File

@ -20,17 +20,36 @@
*/ */
if (!options) return Bangle.setUI(); // remove existing handlers if (!options) return Bangle.setUI(); // remove existing handlers
const MAX_VELOCITY=100; const SPEED=100;
const LAST_DRAG_WAIT=150;
const MIN_VELOCITY=0.1;
let scheduledDraw; let scheduledDraw;
let velocity = 0; let velocity = 0;
let accDy = 0; let accDy = 0;
let scheduledBrake = setInterval(()=>{velocity*=0.9;}, 50); let direction = 0;
let scheduledBrake;
let lastTouchedDrag = 0;
let lastDragStart = 0; let lastDragStart = 0;
let R = Bangle.appRect; let R = Bangle.appRect;
let menuScrollMin = 0|options.scrollMin; let menuScrollMin = 0|options.scrollMin;
let menuScrollMax = options.h*options.c - R.h; let menuScrollMax = options.h*options.c - R.h;
if (menuScrollMax<menuScrollMin) menuScrollMax=menuScrollMin; if (menuScrollMax<menuScrollMin) menuScrollMax=menuScrollMin;
const startBrake = () => {
if (!scheduledBrake){
scheduledBrake = setInterval(()=>{
velocity *= 0.9;
if (velocity <= MIN_VELOCITY){
velocity = 0;
if (scheduledBrake)
clearInterval(scheduledBrake);
scheduledBrake = undefined;
}
}, 50);
}
};
const touchHandler = (_,e)=>{ const touchHandler = (_,e)=>{
if (e.y<R.y-4) return; if (e.y<R.y-4) return;
velocity = 0; velocity = 0;
@ -53,23 +72,24 @@
}; };
const draw = () => { const draw = () => {
let dy = velocity; if (velocity > MIN_VELOCITY){
if (s.scroll - dy > menuScrollMax){ s.scroll -= velocity * direction;
dy = s.scroll - menuScrollMax;
velocity = 0;
}
if (s.scroll - dy < menuScrollMin){
dy = s.scroll - menuScrollMin;
velocity = 0;
} }
s.scroll -= dy; if (s.scroll > menuScrollMax){
s.scroll = menuScrollMax;
velocity = 0;
}
if (s.scroll < menuScrollMin){
s.scroll = menuScrollMin;
velocity = 0;
}
let oldScroll = rScroll; let oldScroll = rScroll;
rScroll = s.scroll &~1; rScroll = s.scroll &~1;
let d = oldScroll-rScroll; let d = oldScroll-rScroll;
if (Math.abs(velocity) > 0.01) if (velocity > MIN_VELOCITY)
scheduledDraw = setTimeout(draw,0); scheduledDraw = setTimeout(draw,0);
else else
scheduledDraw = undefined; scheduledDraw = undefined;
@ -102,28 +122,31 @@
}; };
const dragHandler = e=>{ const dragHandler = e=>{
if ((velocity <0 && e.dy>0) || (velocity > 0 && e.dy<0)){ direction = e.dy > 0 ? 1 : -1;
velocity *= -1;
accDy = 5 * velocity;
}
//velocity += e.dy * (Date.now() - lastDrag);
if (e.b > 0){ if (e.b > 0){
// Finger touches the display
lastTouchedDrag = Date.now();
if (!lastDragStart){ if (!lastDragStart){
lastDragStart = lastTouchedDrag;
accDy = 0;
}
// Direction has been reversed, reset accumulated y-values and time of first touch
if (accDy * direction < 0 && e.dy * direction > 0){
lastDragStart = Date.now(); lastDragStart = Date.now();
velocity = 0;
accDy = 0; accDy = 0;
} }
accDy += e.dy; accDy += e.dy;
s.scroll -= e.dy;
} else {
// Finger has left the display, only start scrolling kinetically when the last drag event is close enough
if (Date.now() - lastTouchedDrag < LAST_DRAG_WAIT){
velocity = direction * accDy / (Date.now() - lastDragStart) * SPEED;
startBrake();
} }
velocity = accDy / (Date.now() - lastDragStart) * MAX_VELOCITY;
if (lastDragStart && e.b == 0){
accDy = 0;
lastDragStart = 0;
} }
velocity = E.clip(velocity,-MAX_VELOCITY,MAX_VELOCITY);
//lastDrag=Date.now();
if (!scheduledDraw){ if (!scheduledDraw){
scheduledDraw = setTimeout(draw, 0); scheduledDraw = setTimeout(draw, 0);
} }
@ -140,6 +163,7 @@
if (options.remove) uiOpts.remove = () => { if (options.remove) uiOpts.remove = () => {
if (scheduledDraw) if (scheduledDraw)
clearTimeout(scheduledDraw); clearTimeout(scheduledDraw);
if (scheduledBrake)
clearInterval(scheduledBrake); clearInterval(scheduledBrake);
options.remove(); options.remove();
}; };