Created
September 12, 2011 01:54
-
-
Save willbailey/1210437 to your computer and use it in GitHub Desktop.
springy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var extend = function(dest) { | |
var sources = Array.prototype.slice.call(arguments, 1), source, key; | |
for (var i = 0, l = sources.length; i < l; i++) { | |
source = sources[i]; | |
for (key in source) { | |
if (source.hasOwnProperty(key)) { | |
dest[key] = source[key]; | |
} | |
} | |
} | |
}; | |
/** | |
* SpringSolver provides a lazy run loop for solving springs in the system | |
* when all springs are at rest the loop terminates until a spring in the system | |
* is no longer at rest | |
*/ | |
var Solver = (function() { | |
// collection of springs | |
var _springs = []; | |
// run state | |
var running = false; | |
// internal runloop | |
var loop = function() { | |
if (!running) return; | |
var allAtRest = true, spring; | |
for (var i = 0, l = _springs.length; i < l; i++) { | |
spring = _springs[i]; | |
if (!spring.atRest()) { | |
allAtRest = false; | |
spring.solve(); | |
} | |
} | |
if (!allAtRest && running) { | |
setTimeout(arguments.callee, 20); | |
} else { | |
running = false; | |
} | |
}; | |
return { | |
// add a spring to the solver system | |
add: function(spring) { | |
if (_springs.indexOf(spring) !== -1) return; | |
_springs.push(spring); | |
this.solve(); | |
}, | |
// remove a spring from the system | |
remove: function(spring) { | |
var idx = _springs.indexOf(spring); | |
if (idx === -1) return; | |
springs.splice(idx, 1); | |
}, | |
// inform the solver that it should check if solving is needed | |
solve: function() { | |
running = true; | |
loop(); | |
} | |
}; | |
})(); | |
/** | |
* Spring takes the following named params as options. Tune these inputs | |
* to achieve the desired behavior. | |
* - damping: viscous damping coefficient to apply to the spring | |
* to prevent infinite oscilation | |
* - mass: mass of the object attached to the spring | |
* - tension: stiffness of the spring | |
* - rest: the resting value of the spring | |
* - prec: precision to use in determining if the spring is at rest | |
* - callback: callback to run when the value is changed | |
*/ | |
var nop = function() {}; | |
function Spring(options) { | |
for (var key in options) { | |
this[key] = options[key]; | |
} | |
this.damping = this.damping || 0.92; | |
this.tension = this.tension || 30; | |
this.mass = this.mass || 100; | |
this.rest = this.rest || 0; | |
this.prec = this.prec || 0.00001; | |
this.pos = this.pos || this.rest; | |
this.callback = this.callback || nop; | |
this.velocity = 0; | |
Solver.add(this); | |
} | |
extend(Spring.prototype, { | |
// set the resting value for the spring | |
set: function(val) { | |
this.rest = val; | |
Solver.solve(); | |
}, | |
solve: function() { | |
this.velocity = this.velocity || 0; | |
var force = -this.tension * (this.pos - this.rest); | |
var acceleration = force / this.mass; | |
this.velocity += acceleration; | |
this.velocity *= this.damping; | |
this.pos += this.velocity; | |
this.callback(this.pos); | |
}, | |
atRest: function() { | |
return Math.abs(this.pos - this.rest) <= this.prec && | |
Math.abs(this.velocity) <= this.prec; | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment