summaryrefslogtreecommitdiffstats
path: root/src/animation/Controller.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/animation/Controller.js')
-rw-r--r--src/animation/Controller.js252
1 files changed, 174 insertions, 78 deletions
diff --git a/src/animation/Controller.js b/src/animation/Controller.js
index cee7115..9efe87e 100644
--- a/src/animation/Controller.js
+++ b/src/animation/Controller.js
@@ -7,85 +7,149 @@ Base Class
The base stepper class that will be
***/
-function makeSetterGetter (k, f) {
- return function (v) {
- if (v == null) return this[v]
+function makeSetterGetter ( k, f ) {
+
+ return function ( v ) {
+
+ if ( v == null ) return this[v]
this[k] = v
- if (f) f.call(this)
+ if ( f ) f.call( this )
return this
+
}
+
}
export let easing = {
- '-': function (pos) { return pos },
- '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
- '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
- '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 },
- bezier: function (x1, y1, x2, y2) {
+ '-': function ( pos ) {
+
+ return pos
+
+ },
+ '<>': function ( pos ) {
+
+ return -Math.cos( pos * Math.PI ) / 2 + 0.5
+
+ },
+ '>': function ( pos ) {
+
+ return Math.sin( pos * Math.PI / 2 )
+
+ },
+ '<': function ( pos ) {
+
+ return -Math.cos( pos * Math.PI / 2 ) + 1
+
+ },
+ bezier: function ( x1, y1, x2, y2 ) {
+
// see https://www.w3.org/TR/css-easing-1/#cubic-bezier-algo
- return function (t) {
- if (t < 0) {
- if (x1 > 0) {
+ return function ( t ) {
+
+ if ( t < 0 ) {
+
+ if ( x1 > 0 ) {
+
return y1 / x1 * t
- } else if (x2 > 0) {
+
+ } else if ( x2 > 0 ) {
+
return y2 / x2 * t
+
} else {
+
return 0
+
}
- } else if (t > 1) {
- if (x2 < 1) {
- return (1 - y2) / (1 - x2) * t + (y2 - x2) / (1 - x2)
- } else if (x1 < 1) {
- return (1 - y1) / (1 - x1) * t + (y1 - x1) / (1 - x1)
+
+ } else if ( t > 1 ) {
+
+ if ( x2 < 1 ) {
+
+ return ( 1 - y2 ) / ( 1 - x2 ) * t + ( y2 - x2 ) / ( 1 - x2 )
+
+ } else if ( x1 < 1 ) {
+
+ return ( 1 - y1 ) / ( 1 - x1 ) * t + ( y1 - x1 ) / ( 1 - x1 )
+
} else {
+
return 1
+
}
+
} else {
- return 3 * t * (1 - t) ** 2 * y1 + 3 * t ** 2 * (1 - t) * y2 + t ** 3
+
+ return 3 * t * ( 1 - t ) ** 2 * y1 + 3 * t ** 2 * ( 1 - t ) * y2 + t ** 3
+
}
+
}
+
},
// see https://www.w3.org/TR/css-easing-1/#step-timing-function-algo
- steps: function (steps, stepPosition = 'end') {
+ steps: function ( steps, stepPosition = 'end' ) {
+
// deal with "jump-" prefix
- stepPosition = stepPosition.split('-').reverse()[0]
+ stepPosition = stepPosition.split( '-' ).reverse()[0]
let jumps = steps
- if (stepPosition === 'none') {
+ if ( stepPosition === 'none' ) {
+
--jumps
- } else if (stepPosition === 'both') {
+
+ } else if ( stepPosition === 'both' ) {
+
++jumps
+
}
// The beforeFlag is essentially useless
- return (t, beforeFlag = false) => {
+ return ( t, beforeFlag = false ) => {
+
// Step is called currentStep in referenced url
- let step = Math.floor(t * steps)
- const jumping = (t * step) % 1 === 0
+ let step = Math.floor( t * steps )
+ const jumping = ( t * step ) % 1 === 0
+
+ if ( stepPosition === 'start' || stepPosition === 'both' ) {
- if (stepPosition === 'start' || stepPosition === 'both') {
++step
+
}
- if (beforeFlag && jumping) {
+ if ( beforeFlag && jumping ) {
+
--step
+
}
- if (t >= 0 && step < 0) {
+ if ( t >= 0 && step < 0 ) {
+
step = 0
+
}
- if (t <= 1 && step > jumps) {
+ if ( t <= 1 && step > jumps ) {
+
step = jumps
+
}
return step / jumps
+
}
+
}
}
export class Stepper {
- done () { return false }
+
+ done () {
+
+ return false
+
+ }
+
}
/***
@@ -94,17 +158,25 @@ Easing Functions
***/
export class Ease extends Stepper {
- constructor (fn) {
+
+ constructor ( fn ) {
+
super()
this.ease = easing[fn || timeline.ease] || fn
+
}
- step (from, to, pos) {
- if (typeof from !== 'number') {
+ step ( from, to, pos ) {
+
+ if ( typeof from !== 'number' ) {
+
return pos < 1 ? from : to
+
}
- return from + (to - from) * this.ease(pos)
+ return from + ( to - from ) * this.ease( pos )
+
}
+
}
/***
@@ -113,51 +185,65 @@ Controller Types
***/
export class Controller extends Stepper {
- constructor (fn) {
+
+ constructor ( fn ) {
+
super()
this.stepper = fn
+
}
- step (current, target, dt, c) {
- return this.stepper(current, target, dt, c)
+ step ( current, target, dt, c ) {
+
+ return this.stepper( current, target, dt, c )
+
}
- done (c) {
+ done ( c ) {
+
return c.done
+
}
+
}
function recalculate () {
+
// Apply the default parameters
- var duration = (this._duration || 500) / 1000
+ var duration = ( this._duration || 500 ) / 1000
var overshoot = this._overshoot || 0
// Calculate the PID natural response
var eps = 1e-10
var pi = Math.PI
- var os = Math.log(overshoot / 100 + eps)
- var zeta = -os / Math.sqrt(pi * pi + os * os)
- var wn = 3.9 / (zeta * duration)
+ var os = Math.log( overshoot / 100 + eps )
+ var zeta = -os / Math.sqrt( pi * pi + os * os )
+ var wn = 3.9 / ( zeta * duration )
// Calculate the Spring values
this.d = 2 * zeta * wn
this.k = wn * wn
+
}
export class Spring extends Controller {
- constructor (duration, overshoot) {
+
+ constructor ( duration, overshoot ) {
+
super()
- this.duration(duration || 500)
- .overshoot(overshoot || 0)
+ this.duration( duration || 500 )
+ .overshoot( overshoot || 0 )
+
}
- step (current, target, dt, c) {
- if (typeof current === 'string') return current
+ step ( current, target, dt, c ) {
+
+ if ( typeof current === 'string' ) return current
c.done = dt === Infinity
- if (dt === Infinity) return target
- if (dt === 0) return current
+ if ( dt === Infinity ) return target
+ if ( dt === 0 ) return current
- if (dt > 100) dt = 16
+ if ( dt > 100 ) dt = 16
dt /= 1000
@@ -165,65 +251,75 @@ export class Spring extends Controller {
var velocity = c.velocity || 0
// Apply the control to get the new position and store it
- var acceleration = -this.d * velocity - this.k * (current - target)
- var newPosition = current +
- velocity * dt +
- acceleration * dt * dt / 2
+ var acceleration = -this.d * velocity - this.k * ( current - target )
+ var newPosition = current
+ + velocity * dt
+ + acceleration * dt * dt / 2
// Store the velocity
c.velocity = velocity + acceleration * dt
// Figure out if we have converged, and if so, pass the value
- c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002
+ c.done = Math.abs( target - newPosition ) + Math.abs( velocity ) < 0.002
return c.done ? target : newPosition
+
}
+
}
-extend(Spring, {
- duration: makeSetterGetter('_duration', recalculate),
- overshoot: makeSetterGetter('_overshoot', recalculate)
-})
+extend( Spring, {
+ duration: makeSetterGetter( '_duration', recalculate ),
+ overshoot: makeSetterGetter( '_overshoot', recalculate )
+} )
export class PID extends Controller {
- constructor (p, i, d, windup) {
+
+ constructor ( p, i, d, windup ) {
+
super()
p = p == null ? 0.1 : p
i = i == null ? 0.01 : i
d = d == null ? 0 : d
windup = windup == null ? 1000 : windup
- this.p(p).i(i).d(d).windup(windup)
+ this.p( p ).i( i ).d( d ).windup( windup )
+
}
- step (current, target, dt, c) {
- if (typeof current === 'string') return current
+ step ( current, target, dt, c ) {
+
+ if ( typeof current === 'string' ) return current
c.done = dt === Infinity
- if (dt === Infinity) return target
- if (dt === 0) return current
+ if ( dt === Infinity ) return target
+ if ( dt === 0 ) return current
var p = target - current
- var i = (c.integral || 0) + p * dt
- var d = (p - (c.error || 0)) / dt
+ var i = ( c.integral || 0 ) + p * dt
+ var d = ( p - ( c.error || 0 ) ) / dt
var windup = this.windup
// antiwindup
- if (windup !== false) {
- i = Math.max(-windup, Math.min(i, windup))
+ if ( windup !== false ) {
+
+ i = Math.max( -windup, Math.min( i, windup ) )
+
}
c.error = p
c.integral = i
- c.done = Math.abs(p) < 0.001
+ c.done = Math.abs( p ) < 0.001
+
+ return c.done ? target : current + ( this.P * p + this.I * i + this.D * d )
- return c.done ? target : current + (this.P * p + this.I * i + this.D * d)
}
+
}
-extend(PID, {
- windup: makeSetterGetter('windup'),
- p: makeSetterGetter('P'),
- i: makeSetterGetter('I'),
- d: makeSetterGetter('D')
-})
+extend( PID, {
+ windup: makeSetterGetter( 'windup' ),
+ p: makeSetterGetter( 'P' ),
+ i: makeSetterGetter( 'I' ),
+ d: makeSetterGetter( 'D' )
+} )