erratic-gate/src/modules/simulationRenderer/classes/MouseVelocityManager.ts
2019-07-16 12:38:42 +03:00

89 lines
2.4 KiB
TypeScript

import { Singleton } from '@eix-js/utils'
import { MouseSubject } from '../../core/types/MouseSubject'
import { clamp } from '../../simulation/helpers/clamp'
@Singleton
export class MouseVelocityManager {
private history: number[] = []
private total = 0
private limit = 10
private lastPosition = 0
private lastDirection = 0
private minimumDifference = 10
private lastMove = performance.now()
private resetLimit = 500
// mouseMoveInput is optional because we want to be able to get
// the instance even if we don't have a subject
// (as long as we passed one the first time)
public constructor(public mouseMoveInput?: MouseSubject) {
if (this.mouseMoveInput) {
this.mouseMoveInput.subscribe(event => {
this.lastMove = performance.now()
const position = event.position[0]
const dx = position - this.lastPosition
if (Math.abs(dx) < this.minimumDifference) {
this.lastPosition = position
return
}
if (dx === 0) {
this.lastDirection = 0
} else {
this.lastDirection = Math.abs(dx) / dx
}
this.lastPosition = event.position[0]
})
} else {
throw new Error(
'You need to pass a MouseMoveInput the first time you instantiate this class!'
)
}
}
public getDirection() {
if (this.history.length) {
return clamp(-1, 1, this.total / this.history.length)
}
return 0
}
public update(maybeAgain = true) {
if (this.lastDirection === 0) {
return 0
}
if (
this.lastDirection !== 0 &&
performance.now() - this.lastMove > this.resetLimit
) {
this.lastDirection = 0
}
this.history.push(this.lastDirection)
this.total += this.lastDirection
if (this.history.length > this.limit) {
const removed = this.history.shift()
if (removed !== undefined) {
this.total -= removed
}
}
}
public clear(value?: number) {
if (value) {
this.lastPosition = value
}
this.history = []
this.total = 0
this.lastMove = performance.now()
this.lastDirection = 0
}
}