100 lines
3.3 KiB
TypeScript
100 lines
3.3 KiB
TypeScript
/**
|
|
* Lethargy help distinguish between scroll events initiated by the user, and those by inertial scrolling.
|
|
* Lethargy does not have external dependencies.
|
|
*
|
|
* @param stability - Specifies the length of the rolling average.
|
|
* In effect, the larger the value, the smoother the curve will be.
|
|
* This attempts to prevent anomalies from firing 'real' events. Valid values are all positive integers,
|
|
* but in most cases, you would need to stay between 5 and around 30.
|
|
*
|
|
* @param sensitivity - Specifies the minimum value for wheelDelta for it to register as a valid scroll event.
|
|
* Because the tail of the curve have low wheelDelta values,
|
|
* this will stop them from registering as valid scroll events.
|
|
* The unofficial standard wheelDelta is 120, so valid values are positive integers below 120.
|
|
*
|
|
* @param tolerance - Prevent small fluctuations from affecting results.
|
|
* Valid values are decimals from 0, but should ideally be between 0.05 and 0.3.
|
|
*
|
|
* Based on https://github.com/d4nyll/lethargy
|
|
*/
|
|
|
|
export type LethargyConfig = {
|
|
stability?: number;
|
|
sensitivity?: number;
|
|
tolerance?: number;
|
|
delay?: number;
|
|
};
|
|
|
|
export class Lethargy {
|
|
private stability: number;
|
|
|
|
private sensitivity: number;
|
|
|
|
private tolerance: number;
|
|
|
|
private delay: number;
|
|
|
|
private lastUpDeltas: Array<number>;
|
|
|
|
private lastDownDeltas: Array<number>;
|
|
|
|
private deltasTimestamp: Array<number>;
|
|
|
|
constructor({
|
|
stability = 8,
|
|
sensitivity = 100,
|
|
tolerance = 1.1,
|
|
delay = 150
|
|
}: LethargyConfig = {}) {
|
|
this.stability = stability;
|
|
this.sensitivity = sensitivity;
|
|
this.tolerance = tolerance;
|
|
this.delay = delay;
|
|
this.lastUpDeltas = new Array(this.stability * 2).fill(0);
|
|
this.lastDownDeltas = new Array(this.stability * 2).fill(0);
|
|
this.deltasTimestamp = new Array(this.stability * 2).fill(0);
|
|
}
|
|
|
|
check(e: any) {
|
|
let lastDelta;
|
|
e = e.originalEvent || e;
|
|
if(e.wheelDelta !== undefined) {
|
|
lastDelta = e.wheelDelta;
|
|
} else if(e.deltaY !== undefined) {
|
|
lastDelta = e.deltaY * -40;
|
|
} else if(e.detail !== undefined || e.detail === 0) {
|
|
lastDelta = e.detail * -40;
|
|
}
|
|
this.deltasTimestamp.push(Date.now());
|
|
this.deltasTimestamp.shift();
|
|
if(lastDelta > 0) {
|
|
this.lastUpDeltas.push(lastDelta);
|
|
this.lastUpDeltas.shift();
|
|
return this.isInertia(1);
|
|
} else {
|
|
this.lastDownDeltas.push(lastDelta);
|
|
this.lastDownDeltas.shift();
|
|
return this.isInertia(-1);
|
|
}
|
|
}
|
|
|
|
isInertia(direction: number) {
|
|
const lastDeltas = direction === -1 ? this.lastDownDeltas : this.lastUpDeltas;
|
|
if(lastDeltas[0] === undefined) return direction;
|
|
if(
|
|
this.deltasTimestamp[this.stability * 2 - 2] + this.delay > Date.now() &&
|
|
lastDeltas[0] === lastDeltas[this.stability * 2 - 1]
|
|
) {
|
|
return false;
|
|
}
|
|
const lastDeltasOld = lastDeltas.slice(0, this.stability);
|
|
const lastDeltasNew = lastDeltas.slice(this.stability, this.stability * 2);
|
|
const oldSum = lastDeltasOld.reduce((t, s) => t + s);
|
|
const newSum = lastDeltasNew.reduce((t, s) => t + s);
|
|
const oldAverage = oldSum / lastDeltasOld.length;
|
|
const newAverage = newSum / lastDeltasNew.length;
|
|
return Math.abs(oldAverage) < Math.abs(newAverage * this.tolerance) &&
|
|
this.sensitivity < Math.abs(newAverage);
|
|
}
|
|
}
|