UNPKG

smooth-scrollbar

Version:

Customize scrollbar in modern browsers with smooth scrolling experience.

174 lines (130 loc) 3.36 kB
import { getPosition } from './get-position'; export class Tracker { readonly velocityMultiplier = window.devicePixelRatio; updateTime = Date.now(); delta = { x: 0, y: 0 }; velocity = { x: 0, y: 0 }; lastPosition = { x: 0, y: 0 }; constructor(touch: Touch) { this.lastPosition = getPosition(touch); } update(touch: Touch) { const { velocity, updateTime, lastPosition, } = this; const now = Date.now(); const position = getPosition(touch); const delta = { x: -(position.x - lastPosition.x), y: -(position.y - lastPosition.y), }; const duration = (now - updateTime) || 16.7; const vx = delta.x / duration * 16.7; const vy = delta.y / duration * 16.7; velocity.x = vx * this.velocityMultiplier; velocity.y = vy * this.velocityMultiplier; this.delta = delta; this.updateTime = now; this.lastPosition = position; } } export class TouchRecord { private _activeTouchID: number; private _touchList: { [id: number]: Tracker } = {}; private get _primitiveValue() { return { x: 0, y: 0 }; } isActive() { return this._activeTouchID !== undefined; } getDelta() { const tracker = this._getActiveTracker(); if (!tracker) { return this._primitiveValue; } return { ...tracker.delta }; } getVelocity() { const tracker = this._getActiveTracker(); if (!tracker) { return this._primitiveValue; } return { ...tracker.velocity }; } getEasingDistance(damping: number) { const deAcceleration = 1 - damping; let distance = { x: 0, y: 0, }; const vel = this.getVelocity(); Object.keys(vel).forEach(dir => { // ignore small velocity let v = Math.abs(vel[dir]) <= 10 ? 0 : vel[dir]; while (v !== 0) { distance[dir] += v; v = (v * deAcceleration) | 0; } }); return distance; } track(evt: TouchEvent) { const { targetTouches, } = evt; Array.from(targetTouches).forEach(touch => { this._add(touch); }); return this._touchList; } update(evt: TouchEvent) { const { touches, changedTouches, } = evt; Array.from(touches).forEach(touch => { this._renew(touch); }); this._setActiveID(changedTouches); return this._touchList; } release(evt: TouchEvent) { delete this._activeTouchID; Array.from(evt.changedTouches).forEach(touch => { this._delete(touch); }); } private _add(touch: Touch) { if (this._has(touch)) { // reset tracker this._delete(touch); } const tracker = new Tracker(touch); this._touchList[touch.identifier] = tracker; } private _renew(touch: Touch) { if (!this._has(touch)) { return; } const tracker = this._touchList[touch.identifier]; tracker.update(touch); } private _delete(touch: Touch) { delete this._touchList[touch.identifier]; } private _has(touch: Touch): boolean { return this._touchList.hasOwnProperty(touch.identifier); } private _setActiveID(touches: TouchList) { this._activeTouchID = touches[touches.length - 1].identifier; } private _getActiveTracker(): Tracker { const { _touchList, _activeTouchID, } = this; return _touchList[_activeTouchID]; } }