Skip to content

Instantly share code, notes, and snippets.

@vaalentin
Last active May 20, 2017 11:16
Show Gist options
  • Save vaalentin/affaf6f01e53796c471b73d5c9488a91 to your computer and use it in GitHub Desktop.
Save vaalentin/affaf6f01e53796c471b73d5c9488a91 to your computer and use it in GitHub Desktop.
class Signal<T> {
private _listeners: ((data?: T) => any)[]
constructor() {
this._listeners = []
}
public add(listener: (data?: T) => any) {
const i = this._listeners.indexOf(listener)
if (i !== -1) {
return
}
this._listeners.push(listener)
}
public remove(listener: (data?: T) => any) {
const i = this._listeners.indexOf(listener)
if (i === -1) {
return
}
this._listeners.splice(i, 1)
}
public dispatch(data?: T) {
for (let listener of this._listeners) {
listener(data)
}
}
public dispose() {
this._listeners.length = 0
}
}
class Spring {
private static _EPSILON = 0.001
private static _MAX_DELTA = 0.032
private static _springs: Spring[] = []
public static update(dt: number) {
dt = Math.min(Spring._MAX_DELTA, dt)
for (let spring of Spring._springs) {
spring.update(dt)
}
}
private _currentValue: number
private _endValue: number
private _velocity: number
private _isActive: boolean
public stiffness: number
public damping: number
public mass: number
public onUpdate: Signal<{ value: number, velocity: number }>
public onComplete: Signal<{ value: number, velocity: number }>
constructor(stiffness = -30, damping = -0.97, mass = 0.1) {
this._currentValue = 0
this._endValue = 0
this._velocity = 0
this._isActive = false
this.stiffness = stiffness
this.damping = damping
this.mass = mass
this.onUpdate = new Signal()
this.onComplete = new Signal()
}
private _start() {
this._isActive = true
Spring._springs.push(this)
}
private _stop() {
this._isActive = false
const i = Spring._springs.indexOf(this)
if (i === -1) {
return
}
Spring._springs.splice(i, 1)
}
public setCurrentValue(value: number) {
this._currentValue = value
this._endValue = value
}
public setEndValue(value: number) {
if (value === this._endValue) {
return
}
this._endValue = value
if (!this._isActive) {
this._start()
}
}
public update(dt: number) {
const springForce = this.stiffness * ((this._currentValue - this._endValue))
if (Math.abs(springForce) < Spring._EPSILON) {
this._currentValue = this._endValue
this._velocity = 0
this.onUpdate.dispatch({ value: this._currentValue, velocity: this._velocity })
this.onComplete.dispatch({ value: this._currentValue, velocity: this._velocity })
return this._stop()
}
const dampingForce = this.damping * this._velocity
const acceleration = (springForce + dampingForce) / this.mass
this._velocity += acceleration * dt
this._currentValue += this._velocity * dt
this.onUpdate.dispatch({ value: this._currentValue, velocity: this._velocity })
}
public dispose() {
this._stop()
this.onUpdate.dispose()
this.onComplete.dispose()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment