in client/src/components/scroll-list/scroll-list.ts [380:424]
private updateDeceleration(decelerationInfo: {velocity: number, prevTime: number}) {
// get target velocity
let targetVelocity = 0;
const scrollPos = this.getScrollPosition();
let outsideBounds = false;
const contentWidth = this.getScrollContentWidth();
const containerWidth = this.getScrollContainerWidth();
if(scrollPos > 0) {
// too far right - accelerate left
targetVelocity = -this.config.snapMaxSpeed * Math.min(1, scrollPos / this.config.snapDecelerationDistance);
outsideBounds = true;
} else {
const minScroll = Math.min(0, containerWidth - contentWidth);
if(scrollPos < minScroll) {
// too far left - accelerate right
targetVelocity = this.config.snapMaxSpeed * Math.min(1, (minScroll - scrollPos) / this.config.snapDecelerationDistance);
outsideBounds = true;
}
}
// accelerate towards target velocity
let velocity = decelerationInfo.velocity;
const t = ScrollListComponent.getTime();
const dt = t - decelerationInfo.prevTime;
const maxDV = this.config.snapDeceleration * dt;
if(Math.abs(velocity - targetVelocity) > maxDV) {
velocity = velocity > targetVelocity ? velocity - maxDV : velocity + maxDV;
} else {
velocity = targetVelocity;
}
// stop content from scrolling completely offscreen
if(scrollPos < -contentWidth) {
velocity = Math.max(0, velocity);
} else if(scrollPos > containerWidth) {
velocity = Math.min(0, velocity);
}
// update position
if(velocity != 0 || outsideBounds) {
decelerationInfo.prevTime = t;
decelerationInfo.velocity = velocity;
this.setScrollPosition(scrollPos + velocity * dt);
} else {
clearInterval(this.animationInterval);
this.animationInterval = 0;
}
}