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
pull/3296/head
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
const MAX_VELOCITY=100;
const SPEED=100;
const LAST_DRAG_WAIT=150;
const MIN_VELOCITY=0.1;
let scheduledDraw;
let velocity = 0;
let accDy = 0;
let scheduledBrake = setInterval(()=>{velocity*=0.9;}, 50);
let direction = 0;
let scheduledBrake;
let lastTouchedDrag = 0;
let lastDragStart = 0;
let R = Bangle.appRect;
let menuScrollMin = 0|options.scrollMin;
let menuScrollMax = options.h*options.c - R.h;
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)=>{
if (e.y<R.y-4) return;
velocity = 0;
@ -53,23 +72,24 @@
};
const draw = () => {
let dy = velocity;
if (s.scroll - dy > menuScrollMax){
dy = s.scroll - menuScrollMax;
velocity = 0;
}
if (s.scroll - dy < menuScrollMin){
dy = s.scroll - menuScrollMin;
velocity = 0;
if (velocity > MIN_VELOCITY){
s.scroll -= velocity * direction;
}
s.scroll -= dy;
if (s.scroll > menuScrollMax){
s.scroll = menuScrollMax;
velocity = 0;
}
if (s.scroll < menuScrollMin){
s.scroll = menuScrollMin;
velocity = 0;
}
let oldScroll = rScroll;
rScroll = s.scroll &~1;
let d = oldScroll-rScroll;
if (Math.abs(velocity) > 0.01)
if (velocity > MIN_VELOCITY)
scheduledDraw = setTimeout(draw,0);
else
scheduledDraw = undefined;
@ -102,30 +122,33 @@
};
const dragHandler = e=>{
if ((velocity <0 && e.dy>0) || (velocity > 0 && e.dy<0)){
velocity *= -1;
accDy = 5 * velocity;
}
//velocity += e.dy * (Date.now() - lastDrag);
direction = e.dy > 0 ? 1 : -1;
if (e.b > 0){
// Finger touches the display
lastTouchedDrag = Date.now();
if (!lastDragStart){
lastDragStart = Date.now();
velocity = 0;
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();
accDy = 0;
}
accDy += e.dy;
}
velocity = accDy / (Date.now() - lastDragStart) * MAX_VELOCITY;
if (lastDragStart && e.b == 0){
accDy = 0;
lastDragStart = 0;
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 = E.clip(velocity,-MAX_VELOCITY,MAX_VELOCITY);
//lastDrag=Date.now();
if (!scheduledDraw){
scheduledDraw = setTimeout(draw,0);
scheduledDraw = setTimeout(draw, 0);
}
};
@ -140,7 +163,8 @@
if (options.remove) uiOpts.remove = () => {
if (scheduledDraw)
clearTimeout(scheduledDraw);
clearInterval(scheduledBrake);
if (scheduledBrake)
clearInterval(scheduledBrake);
options.remove();
};