├── .gitattributes ├── .bowerrc ├── .gitignore ├── CHANGELOG ├── .editorconfig ├── .jshintrc ├── package.json ├── lib ├── util.js ├── body.js ├── spring.js ├── decelerate.js ├── simulation.js ├── accelerate.js ├── drag.js ├── boundary.js ├── interact.js ├── animation.js ├── attach-spring.js ├── renderer.js ├── index.js └── vector.js ├── bower.json ├── LICENSE ├── README.md ├── impulse.min.js └── impulse.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .tmp 3 | .sass-cache 4 | app/bower_components 5 | .DS_Store 6 | *.swp 7 | *.swm 8 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | ### Impulse 0.1.0 (December 8th 2014) 2 | * [FEATURE] Add force render method, incase your style functions contain side effects. 3 | * [FEATURE] Acceleration can now be an object. 4 | * [BUGFIX] Animations aren't applied infinitely once an animation ends. 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "asi": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "white": false 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "impulse", 3 | "version": "0.1.0", 4 | "main": "lib/index.js", 5 | "scripts": { 6 | "build": "browserify lib/index.js -s Impulse > impulse.js", 7 | "build-min": "ccjs impulse.js --compilation_level=SIMPLE_OPTIMIZATIONS --language_in=ECMASCRIPT5 > impulse.min.js" 8 | }, 9 | "engines": { 10 | "node": ">=0.10.0" 11 | }, 12 | "dependencies": { 13 | "inherits": "~2.0.1", 14 | "raf": "~2.0.1", 15 | "promise": "~5.0.0", 16 | "component-emitter": "~1.1.3", 17 | "lodash.defaults": "~2.4.1", 18 | "touch-velocity": "0.0.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/util.js: -------------------------------------------------------------------------------- 1 | var Vector = require('./vector') 2 | 3 | function vertex(a, b) { 4 | return -b / (2 * a) 5 | } 6 | 7 | function height(a, b, c) { 8 | return parabola(a, b, c, vertex(a, b)) 9 | } 10 | 11 | function parabola(a, b, c, x) { 12 | return a * x * x + b * x + c 13 | } 14 | 15 | function eventVector(evt) { 16 | return Vector({ 17 | x: evt.touches && evt.touches[0].pageX || evt.pageX, 18 | y: evt.touches && evt.touches[0].pageY || evt.pageY 19 | }) 20 | } 21 | 22 | function floatEqual(a, b) { 23 | return Math.abs(a - b) < Number.EPSILON 24 | } 25 | 26 | module.exports.height = height 27 | module.exports.eventVector = eventVector 28 | module.exports.floatEqual = floatEqual 29 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "impulse", 3 | "version": "0.1.0", 4 | "dependencies": {}, 5 | "homepage": "https://github.com/luster-io/physics", 6 | "authors": [ 7 | "Zach Smith " 8 | ], 9 | "description": "Impulse physics animations.", 10 | "main": "impulse.js", 11 | "moduleType": [ 12 | "amd", 13 | "globals", 14 | "node" 15 | ], 16 | "keywords": [ 17 | "physics", 18 | "animation", 19 | "dynamic", 20 | "interaction", 21 | "touch" 22 | ], 23 | "license": "MIT", 24 | "ignore": [ 25 | "**/.*", 26 | "node_modules", 27 | "bower_components", 28 | "app/bower_components", 29 | "test", 30 | "tests" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /lib/body.js: -------------------------------------------------------------------------------- 1 | var Vector = require('./vector') 2 | 3 | module.exports = Body 4 | 5 | function Body(vel, from, fns) { 6 | if(!(this instanceof Body)) return new Body(vel, from, fns) 7 | 8 | this.previousPosition = this.position = Vector(from) 9 | this.velocity = Vector(vel) 10 | this._fns = fns 11 | } 12 | 13 | Body.prototype.update = function(alpha) { 14 | var pos = this.previousPosition.clone().lerp(this.position, alpha) 15 | this._fns.update(pos, this.velocity) 16 | } 17 | 18 | Body.prototype.accelerate = function(state, t) { 19 | return this._fns.accelerate(state, t) 20 | } 21 | 22 | Body.prototype.atRest = function() { 23 | return this.velocity.norm() < .01 24 | } 25 | 26 | Body.prototype.atPosition = function(pos) { 27 | //return whether the distance between this.position and pos is less than .1 28 | return this.position.sub(Vector(pos)).norm() < .01 29 | } 30 | -------------------------------------------------------------------------------- /lib/spring.js: -------------------------------------------------------------------------------- 1 | var Body = require('./body') 2 | var simulation = require('./simulation') 3 | var Boundary = require('./boundary') 4 | var Animation = require('./animation') 5 | 6 | var Spring = module.exports = Animation({ 7 | defaultOptions: { 8 | tension: 100, 9 | damping: 10 10 | }, 11 | onStart: function(velocity, from, to, opts, update) { 12 | var body = this._body = new Body(velocity, from, { 13 | accelerate: function(state, t) { 14 | return state.position.selfSub(to) 15 | .selfMult(-opts.tension) 16 | .selfSub(state.velocity.mult(opts.damping)) 17 | }, 18 | update: function(position, velocity) { 19 | if(body.atRest() && body.atPosition(to)) { 20 | update.done(to, { x: 0, y: 0 }) 21 | } else { 22 | update.state(position, velocity) 23 | } 24 | } 25 | }) 26 | simulation.addBody(this._body) 27 | }, 28 | onEnd: function() { 29 | simulation.removeBody(this._body) 30 | } 31 | }) 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright © 2014 impulse authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/decelerate.js: -------------------------------------------------------------------------------- 1 | var Body = require('./body') 2 | var simulation = require('./simulation') 3 | var Boundary = require('./boundary') 4 | var Animation = require('./animation') 5 | 6 | var Decelerate = module.exports = Animation({ 7 | defaultOptions: { 8 | deceleration: 400 9 | }, 10 | onStart: function(velocity, from, to, opts, update, done) { 11 | var direction = to.sub(from).normalize() 12 | , deceleration = direction.mult(opts.deceleration).negate() 13 | , boundary = Boundary({ 14 | left: Math.min(to.x, from.x), 15 | right: Math.max(to.x, from.x), 16 | top: Math.min(to.y, from.y), 17 | bottom: Math.max(to.y, from.y) 18 | }) 19 | 20 | velocity = direction.mult(velocity.norm()) 21 | 22 | this._body = Body(velocity, from, { 23 | accelerate: function(s, t) { 24 | return deceleration 25 | }, 26 | update: function(position, velocity) { 27 | if(!direction.directionEqual(velocity)) { 28 | update.cancel(position, { x: 0, y: 0 }) 29 | } else if(boundary.contains(position)) { 30 | update.state(position, velocity) 31 | } else { 32 | update.done(to, velocity) 33 | } 34 | } 35 | }) 36 | simulation.addBody(this._body) 37 | }, 38 | 39 | onEnd: function() { 40 | simulation.removeBody(this._body) 41 | } 42 | }) 43 | -------------------------------------------------------------------------------- /lib/simulation.js: -------------------------------------------------------------------------------- 1 | var Vector = require('./vector') 2 | , bodies = [] 3 | , raf = require('raf') 4 | 5 | function increment(a, b, c, d) { 6 | var vec = Vector(0, 0) 7 | vec.selfAdd(a) 8 | vec.selfAdd(b.add(c).selfMult(2)) 9 | vec.selfAdd(d) 10 | vec.selfMult(1/6) 11 | return vec 12 | } 13 | 14 | var positionVec = Vector(0, 0) 15 | var velocityVec = Vector(0, 0) 16 | 17 | function evaluate(initial, t, dt, d) { 18 | var state = {} 19 | 20 | state.position = positionVec.setv(d.dx).selfMult(dt).selfAdd(initial.position) 21 | state.velocity = velocityVec.setv(d.dv).selfMult(dt).selfAdd(initial.velocity) 22 | 23 | var next = { 24 | dx: state.velocity.clone(), 25 | dv: initial.accelerate(state, t).clone() 26 | } 27 | return next 28 | } 29 | 30 | var der = { dx: Vector(0, 0), dv: Vector(0, 0) } 31 | function integrate(state, t, dt) { 32 | var a = evaluate( state, t, 0, der ) 33 | var b = evaluate( state, t, dt*0.5, a ) 34 | var c = evaluate( state, t, dt*0.5, b ) 35 | var d = evaluate( state, t, dt, c ) 36 | 37 | var dxdt = increment(a.dx,b.dx,c.dx,d.dx) 38 | , dvdt = increment(a.dv,b.dv,c.dv,d.dv) 39 | 40 | state.position.selfAdd(dxdt.selfMult(dt)); 41 | state.velocity.selfAdd(dvdt.selfMult(dt)); 42 | } 43 | 44 | var currentTime = Date.now() / 1000 45 | , accumulator = 0 46 | , t = 0 47 | , dt = 0.015 48 | 49 | function simulate() { 50 | raf(function() { 51 | simulate() 52 | var newTime = Date.now() / 1000 53 | var frameTime = newTime - currentTime 54 | currentTime = newTime 55 | 56 | if(frameTime > 0.05) 57 | frameTime = 0.05 58 | 59 | 60 | accumulator += frameTime 61 | 62 | var j = 0 63 | 64 | while(accumulator >= dt) { 65 | for(var i = 0 ; i < bodies.length ; i++) { 66 | bodies[i].previousPosition = bodies[i].position.clone() 67 | integrate(bodies[i], t, dt) 68 | } 69 | t += dt 70 | accumulator -= dt 71 | } 72 | 73 | for(var i = 0 ; i < bodies.length ; i++) { 74 | bodies[i].update(accumulator / dt) 75 | } 76 | }, 16) 77 | } 78 | simulate() 79 | 80 | module.exports.addBody = function(body) { 81 | bodies.push(body) 82 | return body 83 | } 84 | 85 | module.exports.removeBody = function(body) { 86 | var index = bodies.indexOf(body) 87 | if(index >= 0) 88 | bodies.splice(index, 1) 89 | } 90 | -------------------------------------------------------------------------------- /lib/accelerate.js: -------------------------------------------------------------------------------- 1 | var Body = require('./body') 2 | var simulation = require('./simulation') 3 | var Boundary = require('./boundary') 4 | var Animation = require('./animation') 5 | var Vector = require('./vector') 6 | var height = require('./util').height 7 | 8 | var Accelerate = module.exports = Animation({ 9 | defaultOptions: { 10 | acceleration: 1000, 11 | bounce: false, 12 | minBounceDistance: 5, 13 | damping: 0.2, 14 | restitution: 0.2 15 | }, 16 | 17 | onStart: function(velocity, from, to, opts, update, done) { 18 | var direction = to.sub(from).normalize() 19 | if(typeof opts.acceleration === 'number') { 20 | var acceleration = direction.mult(opts.acceleration) 21 | } else { 22 | var acceleration = Vector(opts.acceleration) 23 | } 24 | var bounceAcceleration = direction.mult(opts.bounceAcceleration || acceleration) 25 | , bouncing = false 26 | , boundary = Boundary({ 27 | left: (to.x > from.x) ? -Infinity : to.x, 28 | right: (to.x > from.x) ? to.x : Infinity, 29 | top: (to.y > from.y) ? -Infinity : to.y, 30 | bottom: (to.y > from.y) ? to.y : Infinity 31 | }) 32 | 33 | if(to.sub(from).norm() < .001 && velocity.norm() < .001) { 34 | return update.done(to, velocity) 35 | } 36 | 37 | var restitution = opts.restitution || opts.damping // TODO remove damping 38 | 39 | var body = this._body = Body(velocity, from, { 40 | accelerate: function(s, t) { 41 | if(bouncing) 42 | return bounceAcceleration 43 | else 44 | return acceleration 45 | }, 46 | update: function(position, velocity) { 47 | if(boundary.contains(position)) { 48 | update.state(position, velocity) 49 | } else { 50 | if(opts.bounce && 51 | Math.abs(height(bounceAcceleration.norm(), velocity.norm() * restitution, 0)) > opts.minBounceDistance) { 52 | bouncing = true 53 | body.position = Vector(to) 54 | body.velocity.selfMult(-opts.damping) 55 | update.state(to, body.velocity) 56 | } else { 57 | update.done(to, velocity) 58 | } 59 | } 60 | } 61 | }) 62 | simulation.addBody(this._body) 63 | }, 64 | onEnd: function() { 65 | simulation.removeBody(this._body) 66 | } 67 | }) 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Impulse 2 | [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/luster-io/impulse?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 3 | 4 | Create animations that flow naturally from the user's movements. 5 | 6 | Rather than animating properties for a set amount of time, 7 | impulse takes a start position, end position, and velocity. 8 | 9 | ##example 10 | 11 | ``` 12 | var ball = Impulse(document.querySelector('.ball')) 13 | .style({ 14 | translate: function(x, y) { return x + 'px, ' + y + 'px' }, 15 | }) 16 | //set a starting position 17 | ball.position(50, 50) 18 | 19 | ball.spring({ tension: 100, damping: 10 }) 20 | .to(100, 100).start() 21 | ``` 22 | 23 | 24 | More examples can be found [here](http://impulse.luster.io/examples.html) 25 | 26 | ##Installation 27 | 28 | ####Browserify 29 | ``` 30 | npm install impulse 31 | ``` 32 | 33 | ####Bower 34 | 35 | ``` 36 | bower install impulse 37 | ``` 38 | Exposes a global called Physics 39 | 40 | ####Component 41 | 42 | ``` 43 | component install luster-io/impulse 44 | ``` 45 | 46 | ####Manually 47 | 48 | Get `build/impulse.js` or `build/impulse.min.js` from github. 49 | 50 | ```html 51 | 52 | ``` 53 | 54 | Exposes a global called impulse 55 | 56 | ##High Level Explanation 57 | 58 | Calling `Impulse` on an element or set of elements returns an Impulse object. 59 | A physics object maintains it's own position and velocity. You can interact 60 | with a Impulse object (drag, pan, etc), and animate it. Animations take 61 | the current position and velocity of the PhysicsObject as a starting point, and 62 | animate to a user defined position. 63 | 64 | This makes the animations flow naturally from the user's actions. For example a user can drag an element around. Once they're done dragging, 65 | the next animation will start from the position and velocity that they left off. 66 | 67 | Documentation can be found [here](http://impulse.luster.io/guides.html) 68 | 69 | #Contributing 70 | 71 | Bug reports are extremely useful, if you think something's wrong, create an 72 | issue. 73 | 74 | If there's an interaction you'd like to see, but you don't know if it's 75 | possible, please create an issue. Maybe we can find a way to build it! 76 | 77 | #Discussion 78 | 79 | There's also a place to ask questions, or get help here: 80 | 81 | [https://gitter.im/luster-io/impulse](https://gitter.im/luster-io/impulse) 82 | 83 | ##LICENSE 84 | MIT -- Read LICENSE 85 | -------------------------------------------------------------------------------- /lib/drag.js: -------------------------------------------------------------------------------- 1 | var Emitter = require('component-emitter') 2 | , defaults = require('lodash.defaults') 3 | 4 | var defaultOpts = {} 5 | 6 | module.exports = Drag 7 | 8 | function Drag(phys, opts, start) { 9 | var handles 10 | 11 | this._phys = phys 12 | if(typeof opts === 'function') { 13 | this._startFn = opts 14 | opts = {} 15 | } else { 16 | this._startFn = start 17 | } 18 | 19 | this._opts = defaults({}, defaultOpts, opts) 20 | 21 | //Warn of deprecated option 22 | if(this._opts.boundry){ 23 | console.warn("Warning: Misspelled option 'boundry' is being deprecated. Please use 'boundary' instead."); 24 | this._opts.boundary = this._opts.boundry; 25 | delete this._opts.boundry; 26 | } 27 | 28 | handles = this._opts.handle 29 | 30 | 31 | if(handles && !handles.length) { 32 | handles = [handles] 33 | } else if(handles && handles.length) { 34 | handles = [].slice.call(handles) 35 | } else { 36 | handles = phys.els 37 | } 38 | handles.forEach(this._setupHandle, this) 39 | } 40 | 41 | Emitter(Drag.prototype) 42 | 43 | Drag.prototype.moved = function() { 44 | return (this._interaction.distance() > 10) 45 | } 46 | 47 | Drag.prototype._setupHandle = function(el) { 48 | //start events 49 | el.addEventListener('touchstart', this._start.bind(this)) 50 | el.addEventListener('mousedown', this._start.bind(this)) 51 | 52 | //move events 53 | el.addEventListener('touchmove', this._move.bind(this)) 54 | //apply the move event to the window, so it keeps moving, 55 | //event if the handle doesn't 56 | window.addEventListener('mousemove', this._move.bind(this)) 57 | 58 | //end events 59 | el.addEventListener('touchend', this._end.bind(this)) 60 | window.addEventListener('mouseup', this._end.bind(this)) 61 | } 62 | 63 | Drag.prototype._start = function(evt) { 64 | this._startTime = Date.now() 65 | evt.preventDefault() 66 | this._mousedown = true 67 | this._interaction = this._phys.interact({ 68 | boundary: this._opts.boundary, 69 | damping: this._opts.damping, 70 | direction: this._opts.direction 71 | }) 72 | var promise = this._interaction.start(evt) 73 | this._startFn && this._startFn(promise) 74 | this.emit('start', evt) 75 | } 76 | 77 | Drag.prototype._move = function(evt) { 78 | if(!this._mousedown) return 79 | evt.preventDefault() 80 | 81 | this._interaction.update(evt) 82 | this.emit('move', evt) 83 | } 84 | 85 | Drag.prototype._end = function(evt) { 86 | if(!this._mousedown) return 87 | evt.preventDefault() 88 | 89 | this._mousedown = false 90 | 91 | this._interaction.end() 92 | this.emit('end', evt) 93 | } 94 | -------------------------------------------------------------------------------- /lib/boundary.js: -------------------------------------------------------------------------------- 1 | var Vector = require('./vector') 2 | module.exports = Boundary 3 | 4 | function pointBetween(p, p1, p2) { 5 | return p >= p1 && p <= p2 6 | } 7 | 8 | function yIntersect(y, point, direction) { 9 | var factor = (y - point.y) / direction.y 10 | return point.add(direction.clone().mult(factor)) 11 | } 12 | 13 | function xIntersect(x, point, direction) { 14 | var factor = (x - point.x) / direction.x 15 | return point.add(direction.clone().mult(factor)) 16 | } 17 | 18 | Boundary.prototype.applyDamping = function(position, damping) { 19 | var x = position.x 20 | , y = position.y 21 | 22 | if(x < this.left) 23 | x = this.left - (this.left - x) * damping 24 | 25 | if(y < this.top) 26 | y = this.top - (this.top - y) * damping 27 | 28 | if(x > this.right) 29 | x = this.right - (this.right - x) * damping 30 | 31 | if(y > this.bottom) 32 | y = this.bottom - (this.bottom - y) * damping 33 | 34 | return Vector(x, y) 35 | } 36 | 37 | function Boundary(boundary) { 38 | if(!(this instanceof Boundary)) 39 | return new Boundary(boundary) 40 | 41 | this.left = (typeof boundary.left !== 'undefined') ? boundary.left : -Infinity 42 | this.right = (typeof boundary.right !== 'undefined') ? boundary.right : Infinity 43 | this.top = (typeof boundary.top !== 'undefined') ? boundary.top : -Infinity 44 | this.bottom = (typeof boundary.bottom !== 'undefined') ? boundary.bottom : Infinity 45 | } 46 | 47 | Boundary.prototype.contains = function(pt) { 48 | return pt.x >= this.left && 49 | pt.x <= this.right && 50 | pt.y >= this.top && 51 | pt.y <= this.bottom 52 | } 53 | 54 | Boundary.prototype.nearestIntersect = function(point, velocity) { 55 | var direction = Vector(velocity).normalize() 56 | , point = Vector(point) 57 | , isect 58 | , distX 59 | , distY 60 | 61 | if(velocity.y < 0) 62 | isect = yIntersect(this.top, point, direction) 63 | if(velocity.y > 0) 64 | isect = yIntersect(this.bottom, point, direction) 65 | 66 | if(isect && pointBetween(isect.x, this.left, this.right)) 67 | return isect 68 | 69 | if(velocity.x < 0) 70 | isect = xIntersect(this.left, point, direction) 71 | if(velocity.x > 0) 72 | isect = xIntersect(this.right, point, direction) 73 | 74 | if(isect && pointBetween(isect.y, this.top, this.bottom)) 75 | return isect 76 | 77 | //if the velocity is zero, or it didn't intersect any lines (outside the box) 78 | //just send it it the nearest boundary 79 | distX = (Math.abs(point.x - this.left) < Math.abs(point.x - this.right)) ? this.left : this.right 80 | distY = (Math.abs(point.y - this.top) < Math.abs(point.y - this.bottom)) ? this.top : this.bottom 81 | 82 | return (distX < distY) ? Vector(distX, point.y) : Vector(point.x, distY) 83 | } 84 | -------------------------------------------------------------------------------- /lib/interact.js: -------------------------------------------------------------------------------- 1 | var defaults = require('lodash.defaults') 2 | var Velocity = require('touch-velocity') 3 | var Vector = require('./vector') 4 | var Promise = require('promise') 5 | var util = require('./util') 6 | var Boundary = require('./boundary') 7 | 8 | module.exports = Interact 9 | 10 | var defaultOpts = { 11 | boundary: Boundary({}), 12 | damping: 0, 13 | direction: 'both' 14 | } 15 | 16 | function Interact(phys, opts) { 17 | this._phys = phys 18 | this._running = false 19 | this._opts = defaults({}, opts, defaultOpts) 20 | 21 | //Warn of deprecated option 22 | if(this._opts.boundry){ 23 | console.warn("Warning: Misspelled option 'boundry' is being deprecated. Please use 'boundary' instead."); 24 | this._opts.boundary = this._opts.boundry; 25 | delete this._opts.boundry; 26 | } 27 | } 28 | 29 | Interact.prototype.position = function(x, y) { 30 | var direction = this._opts.direction 31 | , boundary = this._opts.boundary 32 | , pos = Vector(x, y) 33 | 34 | if(direction !== 'both' && direction !== 'horizontal') pos.x = 0 35 | if(direction !== 'both' && direction !== 'vertical') pos.y = 0 36 | 37 | this._veloX.updatePosition(pos.x) 38 | this._veloY.updatePosition(pos.y) 39 | 40 | this._phys.velocity(this._veloX.getVelocity(), this._veloY.getVelocity()) 41 | 42 | pos = boundary.applyDamping(pos, this._opts.damping) 43 | 44 | this._phys.position(pos) 45 | 46 | return this 47 | } 48 | 49 | Interact.prototype.update = function(evt) { 50 | //for jquery and hammer.js 51 | evt = evt.originalEvent || evt 52 | var position = util.eventVector(evt).sub(this._startPosition) 53 | 54 | this.position(position) 55 | return this 56 | } 57 | 58 | Interact.prototype.start = function(evt) { 59 | var that = this 60 | , evtPosition = evt && util.eventVector(evt) 61 | , position = this._phys.position() 62 | 63 | this._running = true 64 | this._phys._startAnimation(this) 65 | this._startPosition = evt && evtPosition.sub(position) 66 | this._initialPosition = this._phys.position() 67 | 68 | this._veloX = new Velocity() 69 | this._veloY = new Velocity() 70 | 71 | this.position(position) 72 | 73 | return this._ended = new Promise(function(res, rej) { 74 | that._resolve = res 75 | that._reject = rej 76 | }) 77 | } 78 | 79 | Interact.prototype.distance = function() { 80 | return this._initialPosition.sub(this._phys.position()).norm() 81 | } 82 | 83 | Interact.prototype.cancel = function() { 84 | this._running = false 85 | this._reject(new Error('Canceled the interaction')) 86 | } 87 | 88 | Interact.prototype.running = function() { 89 | return this._running 90 | } 91 | 92 | Interact.prototype.end = function() { 93 | this._phys.velocity(this._veloX.getVelocity(), this._veloY.getVelocity()) 94 | this._resolve({ velocity: this._phys.velocity(), position: this._phys.position() }) 95 | return this._ended 96 | } 97 | -------------------------------------------------------------------------------- /lib/animation.js: -------------------------------------------------------------------------------- 1 | var defaults = require('lodash.defaults') 2 | , Promise = window.Promise || require('promise') 3 | , Boundary = require('./boundary') 4 | , Vector = require('./vector') 5 | , Emitter = require('component-emitter') 6 | 7 | var proto = { 8 | to: function(x, y) { 9 | if(x instanceof Boundary) 10 | this._to = x 11 | else 12 | this._to = Vector(x, y) 13 | return this 14 | }, 15 | 16 | velocity: function(x, y) { 17 | this._velocity = Vector(x, y) 18 | return this 19 | }, 20 | 21 | from: function(x, y) { 22 | this._from = Vector(x, y) 23 | return this 24 | }, 25 | 26 | _updateState: function(position, velocity) { 27 | this._phys.position(position) 28 | this._phys.velocity(velocity) 29 | }, 30 | 31 | cancel: function() { 32 | this._onEnd() 33 | this._running = false 34 | this._reject() 35 | }, 36 | 37 | running: function() { 38 | return this._running || false 39 | }, 40 | 41 | start: function() { 42 | var that = this 43 | , from = (this._from) ? this._from : this._phys.position() 44 | , to = (this._to) ? this._to : this._phys.position() 45 | , velocity = (this._velocity) ? this._velocity : this._phys.velocity() 46 | , opts = defaults({}, this._opts || {}, this._defaultOpts) 47 | 48 | var update = { 49 | state: function(position, velocity) { 50 | that._updateState(position, velocity) 51 | }, 52 | done: function(position, velocity) { 53 | that._updateState(position, velocity) 54 | that._onEnd() 55 | that._running = false 56 | that._resolve({ position: position, velocity: velocity }) 57 | }, 58 | cancel: function(position, velocity) { 59 | that._updateState(position, velocity) 60 | that._onEnd() 61 | that._running = false 62 | that._reject() 63 | } 64 | } 65 | this._phys._startAnimation(this) 66 | 67 | this._running = true 68 | if(to instanceof Boundary) 69 | to = to.nearestIntersect(from, velocity) 70 | this._onStart(velocity, from, to, opts, update) 71 | 72 | return that._ended 73 | } 74 | } 75 | 76 | function Animation(callbacks) { 77 | var animation = function(phys, opts) { 78 | var that = this 79 | this._opts = opts 80 | this._phys = phys 81 | this._onStart = callbacks.onStart 82 | this._onEnd = callbacks.onEnd 83 | this._defaultOpts = callbacks.defaultOptions 84 | 85 | this._ended = new Promise(function(resolve, reject) { 86 | that._resolve = resolve 87 | that._reject = reject 88 | }) 89 | 90 | this.start = this.start.bind(this) 91 | } 92 | 93 | Emitter(animation.prototype) 94 | animation.prototype = proto 95 | 96 | return animation 97 | } 98 | 99 | 100 | 101 | 102 | 103 | module.exports = Animation 104 | -------------------------------------------------------------------------------- /lib/attach-spring.js: -------------------------------------------------------------------------------- 1 | var defaults = require('lodash.defaults') 2 | , Vector = require('./vector') 3 | , simulation = require('./simulation') 4 | , Body = require('./body') 5 | 6 | var defaultOptions = { 7 | tension: 100, 8 | damping: 10, 9 | seperation: 0, 10 | offset: { x: 0, y: 0 } 11 | } 12 | 13 | module.exports = AttachSpring 14 | function AttachSpring(phys, attachment, opts) { 15 | this._phys = phys 16 | this._opts = defaults({}, opts || {}, defaultOptions) 17 | this._position = phys.position() 18 | this._velocity = phys.velocity() 19 | if(typeof attachment.position === 'function') 20 | this._attachment = attachment.position.bind(attachment) 21 | else 22 | this._attachment = attachment 23 | } 24 | 25 | AttachSpring.prototype.position = function(x, y) { 26 | if(arguments.length === 0) { 27 | return this._position 28 | } 29 | if(this._body) 30 | this._body.position = this._position = Vector(x, y) 31 | else 32 | this._position = Vector(x, y) 33 | } 34 | 35 | AttachSpring.prototype.velocity = function(x, y) { 36 | if(this._body) 37 | this._body.velocity = this._velocity = Vector(x, y) 38 | else 39 | this._velocity = Vector(x, y) 40 | } 41 | 42 | AttachSpring.prototype.cancel = function(x, y) { 43 | this._running = false 44 | simulation.removeBody(this._body) 45 | } 46 | 47 | AttachSpring.prototype.stop = function(x, y) { 48 | this._running = false 49 | simulation.removeBody(this._body) 50 | } 51 | 52 | AttachSpring.prototype.running = function(x, y) { 53 | return this._running 54 | } 55 | 56 | window.unit = 0 57 | AttachSpring.prototype.start = function() { 58 | var attachment = this._attachment 59 | , opts = this._opts 60 | , phys = this._phys 61 | , velocity = this._velocity 62 | , position = this._position 63 | , that = this 64 | 65 | phys._startAnimation(this) 66 | 67 | this._running = true 68 | 69 | var body = this._body = Body(velocity, position, { 70 | accelerate: function(state, t) { 71 | var distVec = state.position.selfSub(attachment()) 72 | , dist = distVec.norm() 73 | , distNorm = distVec.normalize() 74 | 75 | if(distNorm.x === 0 && distNorm.y === 0) { 76 | distNorm.x = distNorm.y = 1 77 | distNorm.normalize() 78 | } 79 | var accel = distNorm 80 | .selfMult(-opts.tension) 81 | .selfMult(dist - opts.seperation) 82 | .selfSub(state.velocity.selfMult(opts.damping)) 83 | 84 | return accel 85 | }, 86 | update: function(position, velocity) { 87 | that._position = body.position 88 | that._velocity = body.velocity 89 | if(opts.offset) { 90 | var pos = position.add(opts.offset) 91 | phys.position(pos) 92 | } else { 93 | phys.position(position) 94 | } 95 | phys.velocity(velocity) 96 | } 97 | }) 98 | simulation.addBody(body) 99 | return this 100 | } -------------------------------------------------------------------------------- /lib/renderer.js: -------------------------------------------------------------------------------- 1 | var prefixes = ['Webkit', 'Moz', 'Ms', 'ms'] 2 | var calls = [] 3 | var transformProp 4 | var raf = require('raf') 5 | var floatEqual = require('./util').floatEqual 6 | 7 | function loop() { 8 | raf(function() { 9 | loop() 10 | for(var i = calls.length - 1; i >= 0; i--) { 11 | calls[i]() 12 | } 13 | }) 14 | } 15 | loop() 16 | 17 | function prefixed(prop) { 18 | var prefixed 19 | for (var i = 0; i < prefixes.length; i++) { 20 | prefixed = prefixes[i] + prop[0].toUpperCase() + prop.slice(1) 21 | if(typeof document.body.style[prefixed] !== 'undefined') 22 | return prefixed 23 | } 24 | return prop 25 | } 26 | 27 | var transformsProperties = ['translate', 'translateX', 'translateY', 'translateZ', 28 | 'rotate', 'rotateX', 'rotateY', 'rotate3d', 'rotateZ', 29 | 'scale', 'scaleX', 'scaleY', 'scaleZ', 30 | 'skew', 'skewX', 'skewY', 'skewZ'] 31 | 32 | module.exports = Renderer 33 | 34 | function Renderer(els) { 35 | if(typeof els.length === 'undefined') 36 | els = [els] 37 | this.els = els 38 | this.styles = {} 39 | this.invisibleEls = [] 40 | this.changed = false 41 | calls.push(this.render.bind(this)) 42 | } 43 | 44 | Renderer.prototype.render = function() { 45 | if(!this.changed) return 46 | 47 | if(!transformProp) 48 | transformProp = prefixed('transform') 49 | var transformsToApply 50 | , els = this.els 51 | , position = this.currentPosition 52 | , styles = this.styles 53 | , value 54 | , props = Object.keys(styles) 55 | , elsLength = els.length 56 | , propsLength = props.length 57 | , i, j 58 | , transforms 59 | 60 | this.changed = false 61 | 62 | for(i = 0 ; i < elsLength ; i++) { 63 | transformsToApply = [] 64 | if(this.visibleFn && !this.visibleFn(position, i)) { 65 | if(!this.invisibleEls[i]) { 66 | els[i].style.webkitTransform = 'translate3d(0, -99999px, 0)' 67 | } 68 | this.invisibleEls[i] = true 69 | } else { 70 | this.invisibleEls[i] = false 71 | for (j = 0; j < propsLength; j++) { 72 | var prop = props[j] 73 | value = (typeof styles[prop] === 'function') ? styles[prop](position.x, position.y, i) : styles[prop] 74 | 75 | if(transformsProperties.indexOf(prop) !== -1) { 76 | transformsToApply.push(prop + '(' + value + ')') 77 | } else { 78 | els[i].style[prop] = value 79 | } 80 | } 81 | transforms = transformsToApply.join(' ') 82 | transforms += ' translateZ(0)' 83 | els[i].style[transformProp] = transforms 84 | } 85 | } 86 | } 87 | 88 | Renderer.prototype.style = function(property, value) { 89 | if(typeof property === 'object') { 90 | for(prop in property) { 91 | if(property.hasOwnProperty(prop)) { 92 | this.style(prop, property[prop]) 93 | } 94 | } 95 | } 96 | this.styles[property] = value 97 | return this 98 | } 99 | 100 | Renderer.prototype.visible = function(isVisible) { 101 | this.visibleFn = isVisible 102 | return this 103 | } 104 | 105 | Renderer.prototype.update = function(x, y) { 106 | if(this.currentPosition) { 107 | var equal = floatEqual(x, this.currentPosition.x) && floatEqual(y, this.currentPosition.y) 108 | this.changed = this.changed || !equal 109 | } else { 110 | this.changed = true 111 | } 112 | this.currentPosition = { x: x, y: y } 113 | } 114 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var simulation = require('./simulation') 2 | var Vector = require('./vector') 3 | var Renderer = require('./renderer') 4 | var defaults = require('lodash.defaults') 5 | var Spring = require('./spring') 6 | var AttachSpring = require('./attach-spring') 7 | var Decelerate = require('./decelerate') 8 | var Accelerate = require('./accelerate') 9 | var Drag = require('./drag') 10 | var Interact = require('./interact') 11 | var Boundary = require('./boundary') 12 | var Promise = window.Promise || require('promise') 13 | 14 | module.exports = Physics 15 | 16 | function Physics(rendererOrEls) { 17 | if(!(this instanceof Physics)) { 18 | return new Physics(rendererOrEls) 19 | } 20 | if(typeof rendererOrEls === 'function') { 21 | this._render = rendererOrEls 22 | this.els = [] 23 | } else { 24 | if(rendererOrEls.length) 25 | this.els = [].slice.call(rendererOrEls) 26 | else 27 | this.els = [rendererOrEls] 28 | 29 | this._renderer = new Renderer(this.els) 30 | this._render = this._renderer.update.bind(this._renderer) 31 | } 32 | 33 | this._position = Vector(0, 0) 34 | this._velocity = Vector(0, 0) 35 | } 36 | 37 | Physics.Boundary = Boundary 38 | Physics.Boundry = Boundary 39 | Physics.Vector = Vector 40 | Physics.Promise = Promise 41 | 42 | Physics.prototype.style = function() { 43 | this._renderer.style.apply(this._renderer, arguments) 44 | return this 45 | } 46 | 47 | Physics.prototype.visible = function() { 48 | this._renderer.visible.apply(this._renderer, arguments) 49 | return this 50 | } 51 | 52 | Physics.prototype.direction = function(d) { 53 | var velocity = this.velocity() 54 | , h, v, c 55 | 56 | if(velocity.x < 0) h = 'left' 57 | else if(velocity.x > 0) h = 'right' 58 | 59 | if(velocity.y < 0) v = 'up' 60 | else if(velocity.y > 0) v = 'down' 61 | 62 | var c = h + (v || '').toUpperCase() 63 | 64 | return d === h || d === v || d === c 65 | } 66 | 67 | Physics.prototype.forceRender = function() { 68 | if(this._renderer) { 69 | this._renderer.changed = true 70 | } 71 | } 72 | 73 | Physics.prototype.atRest = function() { 74 | var velocity = this.velocity() 75 | return velocity.x === 0 && velocity.y === 0 76 | } 77 | 78 | Physics.prototype._startAnimation = function(animation) { 79 | if(this._currentAnimation && this._currentAnimation.running()) { 80 | this._currentAnimation.cancel() 81 | } 82 | this._currentAnimation = animation 83 | } 84 | 85 | Physics.prototype.velocity = function(x, y) { 86 | if(!arguments.length) return this._velocity 87 | this._velocity = Vector(x, y) 88 | return this 89 | } 90 | 91 | Physics.prototype.position = function(x, y) { 92 | if(!arguments.length) return this._position.clone() 93 | this._position = Vector(x, y) 94 | this._render(this._position.x, this._position.y) 95 | return this 96 | } 97 | 98 | Physics.prototype.interact = function(opts) { 99 | return new Interact(this, opts) 100 | } 101 | 102 | Physics.prototype.drag = function(opts, start) { 103 | return new Drag(this, opts, start) 104 | } 105 | 106 | Physics.prototype.spring = function(opts) { 107 | return new Spring(this, opts) 108 | } 109 | 110 | Physics.prototype.decelerate = function(opts) { 111 | return new Decelerate(this, opts) 112 | } 113 | 114 | Physics.prototype.accelerate = function(opts) { 115 | return new Accelerate(this, opts) 116 | } 117 | 118 | Physics.prototype.attachSpring = function(attachment, opts) { 119 | return new AttachSpring(this, attachment, opts) 120 | } 121 | -------------------------------------------------------------------------------- /lib/vector.js: -------------------------------------------------------------------------------- 1 | module.exports = Vector 2 | 3 | function Vector(x, y) { 4 | if(!(this instanceof Vector)) 5 | return new Vector(x, y) 6 | 7 | if(typeof x.x !== 'undefined') { 8 | this.x = x.x 9 | this.y = x.y 10 | } else { 11 | this.x = x || 0 12 | this.y = y || 0 13 | } 14 | } 15 | 16 | Vector.prototype.equals = function(vec) { 17 | return vec.x === this.x && vec.y === this.y 18 | } 19 | 20 | Vector.prototype.directionEqual = function(vec) { 21 | return vec.x > 0 === this.x > 0 && this.y > 0 === vec.y > 0 22 | } 23 | 24 | Vector.prototype.dot = function (vec) { 25 | return this.x * vec.x + this.y * vec.y; 26 | } 27 | 28 | Vector.prototype.negate = function() { 29 | return Vector(this.x, this.y).mult(-1) 30 | } 31 | 32 | Vector.prototype.norm = function() { 33 | return Math.sqrt(this.normsq()) 34 | } 35 | 36 | Vector.prototype.clone = function() { 37 | return Vector(this.x, this.y) 38 | } 39 | 40 | Vector.prototype.normsq = function() { 41 | return this.x * this.x + this.y * this.y 42 | } 43 | 44 | Vector.prototype.normalize = function() { 45 | var magnitude = this.norm() 46 | 47 | if(magnitude === 0) { 48 | return this 49 | } 50 | 51 | magnitude = 1 / magnitude 52 | 53 | this.x *= magnitude 54 | this.y *= magnitude 55 | 56 | return this 57 | } 58 | 59 | Vector.prototype.mult = function(x, y) { 60 | if(x instanceof Vector) { 61 | return new Vector(x.x * this.x, x.y * this.y) 62 | } 63 | if(typeof y === 'undefined') { //scalar 64 | return new Vector(x * this.x, x * this.y) 65 | } 66 | return new Vector(x * this.x, y * this.y) 67 | } 68 | 69 | Vector.prototype.selfMult = function(x, y) { 70 | if(x instanceof Vector) { 71 | this.x *= x.x 72 | this.y *= x.y 73 | return this 74 | } 75 | if(typeof y === 'undefined') { //scalar 76 | this.x *= x 77 | this.y *= x 78 | return this 79 | } 80 | this.x *= x 81 | this.y *= y 82 | return this 83 | } 84 | 85 | Vector.prototype.selfAdd = function(x, y) { 86 | if(typeof x.x !== 'undefined') { 87 | this.x += x.x 88 | this.y += x.y 89 | return this 90 | } 91 | if(typeof y === 'undefined') { //scalar 92 | this.x += x 93 | this.y += x 94 | return this 95 | } 96 | this.x += x 97 | this.y += y 98 | return this 99 | } 100 | 101 | Vector.prototype.selfSub = function(x, y) { 102 | if(typeof x.x !== 'undefined') { 103 | this.x -= x.x 104 | this.y -= x.y 105 | return this 106 | } 107 | if(typeof y === 'undefined') { //scalar 108 | this.x -= x 109 | this.y -= x 110 | return this 111 | } 112 | this.x -= x 113 | this.y -= y 114 | 115 | return this 116 | } 117 | 118 | Vector.prototype.sub = function(x, y) { 119 | 120 | if(typeof x.x !== 'undefined') 121 | return new Vector(this.x - x.x, this.y - x.y) 122 | 123 | if(typeof y === 'undefined')//scalar 124 | return new Vector(this.x - x, this.y - x) 125 | 126 | return new Vector(this.x - x, this.y - y) 127 | } 128 | 129 | Vector.prototype.add = function(x, y) { 130 | if(typeof x.x !== 'undefined') { 131 | return new Vector(this.x + x.x, this.y + x.y) 132 | } 133 | if(typeof y === 'undefined') { //scalar 134 | return new Vector(this.x + x, this.y + x) 135 | } 136 | return new Vector(this.x + x, this.y + y) 137 | } 138 | 139 | Vector.prototype.setv = function(vec) { 140 | this.x = vec.x 141 | this.y = vec.y 142 | return this 143 | } 144 | 145 | Vector.prototype.lerp = function(vector, alpha) { 146 | return this.mult(1-alpha).add(vector.mult(alpha)) 147 | } 148 | -------------------------------------------------------------------------------- /impulse.min.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.Impulse=e()}}(function(){var e,t,n;return function r(e,t,n){function i(o,u){if(!t[o]){if(!e[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(s)return s(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=t[o]={exports:{}};e[o][0].call(l.exports,function(t){var n=e[o][1][t];return i(n?n:t)},l,l.exports,r,e,t,n)}return t[o].exports}var s=typeof require=="function"&&require;for(var o=0;ot.x?-Infinity:n.x,right:n.x>t.x?n.x:Infinity,top:n.y>t.y?-Infinity:n.y,bottom:n.y>t.y?n.y:Infinity});if(n.sub(t).norm()<.001&&e.norm()<.001){return f.done(n,e)}var m=o.restitution||o.damping;var g=this._body=r(e,t,{accelerate:function(e,t){if(d)return p;else return h},update:function(e,t){if(v.contains(e)){f.state(e,t)}else{if(o.bounce&&Math.abs(a(p.norm(),t.norm()*m,0))>o.minBounceDistance){d=true;g.position=u(n);g.velocity.selfMult(-o.damping);f.state(n,g.velocity)}else{f.done(n,t)}}}});i.addBody(this._body)},onEnd:function(){i.removeBody(this._body)}})},{"./animation":2,"./body":4,"./boundary":5,"./simulation":11,"./util":13,"./vector":14}],2:[function(e,t,n){function f(e){var t=function(t,n){var r=this;this._opts=n;this._phys=t;this._onStart=e.onStart;this._onEnd=e.onEnd;this._defaultOpts=e.defaultOptions;this._ended=new i(function(e,t){r._resolve=e;r._reject=t});this.start=this.start.bind(this)};u(t.prototype);t.prototype=a;return t}var r=e("lodash.defaults"),i=window.Promise||e("promise"),s=e("./boundary"),o=e("./vector"),u=e("component-emitter");var a={to:function(e,t){if(e instanceof s)this._to=e;else this._to=o(e,t);return this},velocity:function(e,t){this._velocity=o(e,t);return this},from:function(e,t){this._from=o(e,t);return this},_updateState:function(e,t){this._phys.position(e);this._phys.velocity(t)},cancel:function(){this._onEnd();this._running=false;this._reject()},running:function(){return this._running||false},start:function(){var e=this,t=this._from?this._from:this._phys.position(),n=this._to?this._to:this._phys.position(),i=this._velocity?this._velocity:this._phys.velocity(),o=r({},this._opts||{},this._defaultOpts);var u={state:function(t,n){e._updateState(t,n)},done:function(t,n){e._updateState(t,n);e._onEnd();e._running=false;e._resolve({position:t,velocity:n})},cancel:function(t,n){e._updateState(t,n);e._onEnd();e._running=false;e._reject()}};this._phys._startAnimation(this);this._running=true;if(n instanceof s)n=n.nearestIntersect(t,i);this._onStart(i,t,n,o,u);return e._ended}};t.exports=f},{"./boundary":5,"./vector":14,"component-emitter":16,"lodash.defaults":17,promise:24}],3:[function(e,t,n){function a(e,t,n){this._phys=e;this._opts=r({},n||{},u);this._position=e.position();this._velocity=e.velocity();if(typeof t.position==="function")this._attachment=t.position.bind(t);else this._attachment=t}var r=e("lodash.defaults"),i=e("./vector"),s=e("./simulation"),o=e("./body");var u={tension:100,damping:10,seperation:0,offset:{x:0,y:0}};t.exports=a;a.prototype.position=function(e,t){if(arguments.length===0){return this._position}if(this._body)this._body.position=this._position=i(e,t);else this._position=i(e,t)};a.prototype.velocity=function(e,t){if(this._body)this._body.velocity=this._velocity=i(e,t);else this._velocity=i(e,t)};a.prototype.cancel=function(e,t){this._running=false;s.removeBody(this._body)};a.prototype.stop=function(e,t){this._running=false;s.removeBody(this._body)};a.prototype.running=function(e,t){return this._running};window.unit=0;a.prototype.start=function(){var e=this._attachment,t=this._opts,n=this._phys,r=this._velocity,i=this._position,u=this;n._startAnimation(this);this._running=true;var a=this._body=o(r,i,{accelerate:function(n,r){var i=n.position.selfSub(e()),s=i.norm(),o=i.normalize();if(o.x===0&&o.y===0){o.x=o.y=1;o.normalize()}var u=o.selfMult(-t.tension).selfMult(s-t.seperation).selfSub(n.velocity.selfMult(t.damping));return u},update:function(e,r){u._position=a.position;u._velocity=a.velocity;if(t.offset){var i=e.add(t.offset);n.position(i)}else{n.position(e)}n.velocity(r)}});s.addBody(a);return this}},{"./body":4,"./simulation":11,"./vector":14,"lodash.defaults":17}],4:[function(e,t,n){function i(e,t,n){if(!(this instanceof i))return new i(e,t,n);this.previousPosition=this.position=r(t);this.velocity=r(e);this._fns=n}var r=e("./vector");t.exports=i;i.prototype.update=function(e){var t=this.previousPosition.clone().lerp(this.position,e);this._fns.update(t,this.velocity)};i.prototype.accelerate=function(e,t){return this._fns.accelerate(e,t)};i.prototype.atRest=function(){return this.velocity.norm()<.01};i.prototype.atPosition=function(e){return this.position.sub(r(e)).norm()<.01}},{"./vector":14}],5:[function(e,t,n){function i(e,t,n){return e>=t&&e<=n}function s(e,t,n){var r=(e-t.y)/n.y;return t.add(n.clone().mult(r))}function o(e,t,n){var r=(e-t.x)/n.x;return t.add(n.clone().mult(r))}function u(e){if(!(this instanceof u))return new u(e);this.left=typeof e.left!=="undefined"?e.left:-Infinity;this.right=typeof e.right!=="undefined"?e.right:Infinity;this.top=typeof e.top!=="undefined"?e.top:-Infinity;this.bottom=typeof e.bottom!=="undefined"?e.bottom:Infinity}var r=e("./vector");t.exports=u;u.prototype.applyDamping=function(e,t){var n=e.x,i=e.y;if(nthis.right)n=this.right-(this.right-n)*t;if(i>this.bottom)i=this.bottom-(this.bottom-i)*t;return r(n,i)};u.prototype.contains=function(e){return e.x>=this.left&&e.x<=this.right&&e.y>=this.top&&e.y<=this.bottom};u.prototype.nearestIntersect=function(e,t){var n=r(t).normalize(),e=r(e),u,a,f;if(t.y<0)u=s(this.top,e,n);if(t.y>0)u=s(this.bottom,e,n);if(u&&i(u.x,this.left,this.right))return u;if(t.x<0)u=o(this.left,e,n);if(t.x>0)u=o(this.right,e,n);if(u&&i(u.y,this.top,this.bottom))return u;a=Math.abs(e.x-this.left)10};o.prototype._setupHandle=function(e){e.addEventListener("touchstart",this._start.bind(this));e.addEventListener("mousedown",this._start.bind(this));e.addEventListener("touchmove",this._move.bind(this));window.addEventListener("mousemove",this._move.bind(this));e.addEventListener("touchend",this._end.bind(this));window.addEventListener("mouseup",this._end.bind(this))};o.prototype._start=function(e){this._startTime=Date.now();e.preventDefault();this._mousedown=true;this._interaction=this._phys.interact({boundary:this._opts.boundary,damping:this._opts.damping,direction:this._opts.direction});var t=this._interaction.start(e);this._startFn&&this._startFn(t);this.emit("start",e)};o.prototype._move=function(e){if(!this._mousedown)return;e.preventDefault();this._interaction.update(e);this.emit("move",e)};o.prototype._end=function(e){if(!this._mousedown)return;e.preventDefault();this._mousedown=false;this._interaction.end();this.emit("end",e)}},{"component-emitter":16,"lodash.defaults":17}],8:[function(e,t,n){function v(e){if(!(this instanceof v)){return new v(e)}if(typeof e==="function"){this._render=e;this.els=[]}else{if(e.length)this.els=[].slice.call(e);else this.els=[e];this._renderer=new s(this.els);this._render=this._renderer.update.bind(this._renderer)}this._position=i(0,0);this._velocity=i(0,0)}var r=e("./simulation");var i=e("./vector");var s=e("./renderer");var o=e("lodash.defaults");var u=e("./spring");var a=e("./attach-spring");var f=e("./decelerate");var l=e("./accelerate");var c=e("./drag");var h=e("./interact");var p=e("./boundary");var d=window.Promise||e("promise");t.exports=v;v.Boundary=p;v.Boundry=p;v.Vector=i;v.Promise=d;v.prototype.style=function(){this._renderer.style.apply(this._renderer,arguments);return this};v.prototype.visible=function(){this._renderer.visible.apply(this._renderer,arguments);return this};v.prototype.direction=function(e){var t=this.velocity(),n,r,i;if(t.x<0)n="left";else if(t.x>0)n="right";if(t.y<0)r="up";else if(t.y>0)r="down";var i=n+(r||"").toUpperCase();return e===n||e===r||e===i};v.prototype.forceRender=function(){if(this._renderer){this._renderer.changed=true}};v.prototype.atRest=function(){var e=this.velocity();return e.x===0&&e.y===0};v.prototype._startAnimation=function(e){if(this._currentAnimation&&this._currentAnimation.running()){this._currentAnimation.cancel()}this._currentAnimation=e};v.prototype.velocity=function(e,t){if(!arguments.length)return this._velocity;this._velocity=i(e,t);return this};v.prototype.position=function(e,t){if(!arguments.length)return this._position.clone();this._position=i(e,t);this._render(this._position.x,this._position.y);return this};v.prototype.interact=function(e){return new h(this,e)};v.prototype.drag=function(e,t){return new c(this,e,t)};v.prototype.spring=function(e){return new u(this,e)};v.prototype.decelerate=function(e){return new f(this,e)};v.prototype.accelerate=function(e){return new l(this,e)};v.prototype.attachSpring=function(e,t){return new a(this,e,t)}},{"./accelerate":1,"./attach-spring":3,"./boundary":5,"./decelerate":6,"./drag":7,"./interact":9,"./renderer":10,"./simulation":11,"./spring":12,"./vector":14,"lodash.defaults":17,promise:24}],9:[function(e,t,n){function l(e,t){this._phys=e;this._running=false;this._opts=r({},t,f);if(this._opts.boundry){console.warn("Warning: Misspelled option 'boundry' is being deprecated. Please use 'boundary' instead.");this._opts.boundary=this._opts.boundry;delete this._opts.boundry}}var r=e("lodash.defaults");var i=e("touch-velocity");var s=e("./vector");var o=e("promise");var u=e("./util");var a=e("./boundary");t.exports=l;var f={boundary:a({}),damping:0,direction:"both"};l.prototype.position=function(e,t){var n=this._opts.direction,r=this._opts.boundary,i=s(e,t);if(n!=="both"&&n!=="horizontal")i.x=0;if(n!=="both"&&n!=="vertical")i.y=0;this._veloX.updatePosition(i.x);this._veloY.updatePosition(i.y);this._phys.velocity(this._veloX.getVelocity(),this._veloY.getVelocity());i=r.applyDamping(i,this._opts.damping);this._phys.position(i);return this};l.prototype.update=function(e){e=e.originalEvent||e;var t=u.eventVector(e).sub(this._startPosition);this.position(t);return this};l.prototype.start=function(e){var t=this,n=e&&u.eventVector(e),r=this._phys.position();this._running=true;this._phys._startAnimation(this);this._startPosition=e&&n.sub(r);this._initialPosition=this._phys.position();this._veloX=new i;this._veloY=new i;this.position(r);return this._ended=new o(function(e,n){t._resolve=e;t._reject=n})};l.prototype.distance=function(){return this._initialPosition.sub(this._phys.position()).norm()};l.prototype.cancel=function(){this._running=false;this._reject(new Error("Canceled the interaction"))};l.prototype.running=function(){return this._running};l.prototype.end=function(){this._phys.velocity(this._veloX.getVelocity(),this._veloY.getVelocity());this._resolve({velocity:this._phys.velocity(),position:this._phys.position()});return this._ended}},{"./boundary":5,"./util":13,"./vector":14,"lodash.defaults":17,promise:24,"touch-velocity":28}],10:[function(e,t,n){function a(){o(function(){a();for(var e=i.length-1;e>=0;e--){i[e]()}})}function f(e){var t;for(var n=0;n.05)t=.05;p+=t;var n=0;while(p>=v){for(var r=0;r=0)i.splice(t,1)}},{"./vector":14,raf:26}],12:[function(e,t,n){var r=e("./body");var i=e("./simulation");var s=e("./boundary");var o=e("./animation");var u=t.exports=o({defaultOptions:{tension:100,damping:10},onStart:function(e,t,n,s,o){var u=this._body=new r(e,t,{accelerate:function(e,t){return e.position.selfSub(n).selfMult(-s.tension).selfSub(e.velocity.mult(s.damping))},update:function(e,t){if(u.atRest()&&u.atPosition(n)){o.done(n,{x:0,y:0})}else{o.state(e,t)}}});i.addBody(this._body)},onEnd:function(){i.removeBody(this._body)}})},{"./animation":2,"./body":4,"./boundary":5,"./simulation":11}],13:[function(e,t,n){function i(e,t){return-t/(2*e)}function s(e,t,n){return o(e,t,n,i(e,t))}function o(e,t,n,r){return e*r*r+t*r+n}function u(e){return r({x:e.touches&&e.touches[0].pageX||e.pageX,y:e.touches&&e.touches[0].pageY||e.pageY})}function a(e,t){return Math.abs(e-t)0===this.x>0&&this.y>0===e.y>0};r.prototype.dot=function(e){return this.x*e.x+this.y*e.y};r.prototype.negate=function(){return r(this.x,this.y).mult(-1)};r.prototype.norm=function(){return Math.sqrt(this.normsq())};r.prototype.clone=function(){return r(this.x,this.y)};r.prototype.normsq=function(){return this.x*this.x+this.y*this.y};r.prototype.normalize=function(){var e=this.norm();if(e===0){return this}e=1/e;this.x*=e;this.y*=e;return this};r.prototype.mult=function(e,t){if(e instanceof r){return new r(e.x*this.x,e.y*this.y)}if(typeof t==="undefined"){return new r(e*this.x,e*this.y)}return new r(e*this.x,t*this.y)};r.prototype.selfMult=function(e,t){if(e instanceof r){this.x*=e.x;this.y*=e.y;return this}if(typeof t==="undefined"){this.x*=e;this.y*=e;return this}this.x*=e;this.y*=t;return this};r.prototype.selfAdd=function(e,t){if(typeof e.x!=="undefined"){this.x+=e.x;this.y+=e.y;return this}if(typeof t==="undefined"){this.x+=e;this.y+=e;return this}this.x+=e;this.y+=t;return this};r.prototype.selfSub=function(e,t){if(typeof e.x!=="undefined"){this.x-=e.x;this.y-=e.y;return this}if(typeof t==="undefined"){this.x-=e;this.y-=e;return this}this.x-=e;this.y-=t;return this};r.prototype.sub=function(e,t){if(typeof e.x!=="undefined")return new r(this.x-e.x,this.y-e.y);if(typeof t==="undefined")return new r(this.x-e,this.y-e);return new r(this.x-e,this.y-t)};r.prototype.add=function(e,t){if(typeof e.x!=="undefined"){return new r(this.x+e.x,this.y+e.y)}if(typeof t==="undefined"){return new r(this.x+e,this.y+e)}return new r(this.x+e,this.y+t)};r.prototype.setv=function(e){this.x=e.x;this.y=e.y;return this};r.prototype.lerp=function(e,t){return this.mult(1-t).add(e.mult(t))}},{}],15:[function(e,t,n){function i(){}var r=t.exports={};r.nextTick=function(){var e=typeof window!=="undefined"&&window.setImmediate;var t=typeof window!=="undefined"&&window.MutationObserver;var n=typeof window!=="undefined"&&window.postMessage&&window.addEventListener;if(e){return function(e){return window.setImmediate(e)}}var r=[];if(t){var i=document.createElement("div");var s=new MutationObserver(function(){var e=r.slice();r.length=0;e.forEach(function(e){e()})});s.observe(i,{attributes:true});return function(t){if(!r.length){i.setAttribute("yes","no")}r.push(t)}}if(n){window.addEventListener("message",function(e){var t=e.source;if((t===window||t===null)&&e.data==="process-tick"){e.stopPropagation();if(r.length>0){var n=r.shift();n()}}},true);return function(t){r.push(t);window.postMessage("process-tick","*")}}return function(t){setTimeout(t,0)}}();r.title="browser";r.browser=true;r.env={};r.argv=[];r.on=i;r.addListener=i;r.once=i;r.off=i;r.removeListener=i;r.removeAllListeners=i;r.emit=i;r.binding=function(e){throw new Error("process.binding is not supported")};r.cwd=function(){return"/"};r.chdir=function(e){throw new Error("process.chdir is not supported")}},{}],16:[function(e,t,n){function r(e){if(e)return i(e)}function i(e){for(var t in r.prototype){e[t]=r.prototype[t]}return e}t.exports=r;r.prototype.on=r.prototype.addEventListener=function(e,t){this._callbacks=this._callbacks||{};(this._callbacks[e]=this._callbacks[e]||[]).push(t);return this};r.prototype.once=function(e,t){function r(){n.off(e,r);t.apply(this,arguments)}var n=this;this._callbacks=this._callbacks||{};r.fn=t;this.on(e,r);return this};r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(e,t){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var n=this._callbacks[e];if(!n)return this;if(1==arguments.length){delete this._callbacks[e];return this}var r;for(var i=0;it){i.pop()}i.push(function(e,t){if(e)s(e);else r(t)});e.apply(n,i)})}};r.nodeify=function(e){return function(){var t=Array.prototype.slice.call(arguments);var n=typeof t[t.length-1]==="function"?t.pop():null;try{return e.apply(this,arguments).nodeify(n)}catch(s){if(n===null||typeof n=="undefined"){return new r(function(e,t){t(s)})}else{i(function(){n(s)})}}}};r.all=function(){var e=arguments.length===1&&Array.isArray(arguments[0]);var t=Array.prototype.slice.call(e?arguments[0]:arguments);if(!e){var n=new Error("Promise.all should be called with a single array, calling it with multiple arguments is deprecated");n.name="Warning";console.warn(n.stack)}return new r(function(e,n){function i(s,o){try{if(o&&(typeof o==="object"||typeof o==="function")){var u=o.then;if(typeof u==="function"){u.call(o,function(e){i(s,e)},n);return}}t[s]=o;if(--r===0){e(t)}}catch(a){n(a)}}if(t.length===0)return e([]);var r=t.length;for(var s=0;s from.x) ? -Infinity : to.x, 29 | right: (to.x > from.x) ? to.x : Infinity, 30 | top: (to.y > from.y) ? -Infinity : to.y, 31 | bottom: (to.y > from.y) ? to.y : Infinity 32 | }) 33 | 34 | if(to.sub(from).norm() < .001 && velocity.norm() < .001) { 35 | return update.done(to, velocity) 36 | } 37 | 38 | var restitution = opts.restitution || opts.damping // TODO remove damping 39 | 40 | var body = this._body = Body(velocity, from, { 41 | accelerate: function(s, t) { 42 | if(bouncing) 43 | return bounceAcceleration 44 | else 45 | return acceleration 46 | }, 47 | update: function(position, velocity) { 48 | if(boundary.contains(position)) { 49 | update.state(position, velocity) 50 | } else { 51 | if(opts.bounce && 52 | Math.abs(height(bounceAcceleration.norm(), velocity.norm() * restitution, 0)) > opts.minBounceDistance) { 53 | bouncing = true 54 | body.position = Vector(to) 55 | body.velocity.selfMult(-opts.damping) 56 | update.state(to, body.velocity) 57 | } else { 58 | update.done(to, velocity) 59 | } 60 | } 61 | } 62 | }) 63 | simulation.addBody(this._body) 64 | }, 65 | onEnd: function() { 66 | simulation.removeBody(this._body) 67 | } 68 | }) 69 | 70 | },{"./animation":2,"./body":4,"./boundary":5,"./simulation":11,"./util":13,"./vector":14}],2:[function(require,module,exports){ 71 | var defaults = require('lodash.defaults') 72 | , Promise = window.Promise || require('promise') 73 | , Boundary = require('./boundary') 74 | , Vector = require('./vector') 75 | , Emitter = require('component-emitter') 76 | 77 | var proto = { 78 | to: function(x, y) { 79 | if(x instanceof Boundary) 80 | this._to = x 81 | else 82 | this._to = Vector(x, y) 83 | return this 84 | }, 85 | 86 | velocity: function(x, y) { 87 | this._velocity = Vector(x, y) 88 | return this 89 | }, 90 | 91 | from: function(x, y) { 92 | this._from = Vector(x, y) 93 | return this 94 | }, 95 | 96 | _updateState: function(position, velocity) { 97 | this._phys.position(position) 98 | this._phys.velocity(velocity) 99 | }, 100 | 101 | cancel: function() { 102 | this._onEnd() 103 | this._running = false 104 | this._reject() 105 | }, 106 | 107 | running: function() { 108 | return this._running || false 109 | }, 110 | 111 | start: function() { 112 | var that = this 113 | , from = (this._from) ? this._from : this._phys.position() 114 | , to = (this._to) ? this._to : this._phys.position() 115 | , velocity = (this._velocity) ? this._velocity : this._phys.velocity() 116 | , opts = defaults({}, this._opts || {}, this._defaultOpts) 117 | 118 | var update = { 119 | state: function(position, velocity) { 120 | that._updateState(position, velocity) 121 | }, 122 | done: function(position, velocity) { 123 | that._updateState(position, velocity) 124 | that._onEnd() 125 | that._running = false 126 | that._resolve({ position: position, velocity: velocity }) 127 | }, 128 | cancel: function(position, velocity) { 129 | that._updateState(position, velocity) 130 | that._onEnd() 131 | that._running = false 132 | that._reject() 133 | } 134 | } 135 | this._phys._startAnimation(this) 136 | 137 | this._running = true 138 | if(to instanceof Boundary) 139 | to = to.nearestIntersect(from, velocity) 140 | this._onStart(velocity, from, to, opts, update) 141 | 142 | return that._ended 143 | } 144 | } 145 | 146 | function Animation(callbacks) { 147 | var animation = function(phys, opts) { 148 | var that = this 149 | this._opts = opts 150 | this._phys = phys 151 | this._onStart = callbacks.onStart 152 | this._onEnd = callbacks.onEnd 153 | this._defaultOpts = callbacks.defaultOptions 154 | 155 | this._ended = new Promise(function(resolve, reject) { 156 | that._resolve = resolve 157 | that._reject = reject 158 | }) 159 | 160 | this.start = this.start.bind(this) 161 | } 162 | 163 | Emitter(animation.prototype) 164 | animation.prototype = proto 165 | 166 | return animation 167 | } 168 | 169 | 170 | 171 | 172 | 173 | module.exports = Animation 174 | 175 | },{"./boundary":5,"./vector":14,"component-emitter":16,"lodash.defaults":17,"promise":24}],3:[function(require,module,exports){ 176 | var defaults = require('lodash.defaults') 177 | , Vector = require('./vector') 178 | , simulation = require('./simulation') 179 | , Body = require('./body') 180 | 181 | var defaultOptions = { 182 | tension: 100, 183 | damping: 10, 184 | seperation: 0, 185 | offset: { x: 0, y: 0 } 186 | } 187 | 188 | module.exports = AttachSpring 189 | function AttachSpring(phys, attachment, opts) { 190 | this._phys = phys 191 | this._opts = defaults({}, opts || {}, defaultOptions) 192 | this._position = phys.position() 193 | this._velocity = phys.velocity() 194 | if(typeof attachment.position === 'function') 195 | this._attachment = attachment.position.bind(attachment) 196 | else 197 | this._attachment = attachment 198 | } 199 | 200 | AttachSpring.prototype.position = function(x, y) { 201 | if(arguments.length === 0) { 202 | return this._position 203 | } 204 | if(this._body) 205 | this._body.position = this._position = Vector(x, y) 206 | else 207 | this._position = Vector(x, y) 208 | } 209 | 210 | AttachSpring.prototype.velocity = function(x, y) { 211 | if(this._body) 212 | this._body.velocity = this._velocity = Vector(x, y) 213 | else 214 | this._velocity = Vector(x, y) 215 | } 216 | 217 | AttachSpring.prototype.cancel = function(x, y) { 218 | this._running = false 219 | simulation.removeBody(this._body) 220 | } 221 | 222 | AttachSpring.prototype.stop = function(x, y) { 223 | this._running = false 224 | simulation.removeBody(this._body) 225 | } 226 | 227 | AttachSpring.prototype.running = function(x, y) { 228 | return this._running 229 | } 230 | 231 | window.unit = 0 232 | AttachSpring.prototype.start = function() { 233 | var attachment = this._attachment 234 | , opts = this._opts 235 | , phys = this._phys 236 | , velocity = this._velocity 237 | , position = this._position 238 | , that = this 239 | 240 | phys._startAnimation(this) 241 | 242 | this._running = true 243 | 244 | var body = this._body = Body(velocity, position, { 245 | accelerate: function(state, t) { 246 | var distVec = state.position.selfSub(attachment()) 247 | , dist = distVec.norm() 248 | , distNorm = distVec.normalize() 249 | 250 | if(distNorm.x === 0 && distNorm.y === 0) { 251 | distNorm.x = distNorm.y = 1 252 | distNorm.normalize() 253 | } 254 | var accel = distNorm 255 | .selfMult(-opts.tension) 256 | .selfMult(dist - opts.seperation) 257 | .selfSub(state.velocity.selfMult(opts.damping)) 258 | 259 | return accel 260 | }, 261 | update: function(position, velocity) { 262 | that._position = body.position 263 | that._velocity = body.velocity 264 | if(opts.offset) { 265 | var pos = position.add(opts.offset) 266 | phys.position(pos) 267 | } else { 268 | phys.position(position) 269 | } 270 | phys.velocity(velocity) 271 | } 272 | }) 273 | simulation.addBody(body) 274 | return this 275 | } 276 | },{"./body":4,"./simulation":11,"./vector":14,"lodash.defaults":17}],4:[function(require,module,exports){ 277 | var Vector = require('./vector') 278 | 279 | module.exports = Body 280 | 281 | function Body(vel, from, fns) { 282 | if(!(this instanceof Body)) return new Body(vel, from, fns) 283 | 284 | this.previousPosition = this.position = Vector(from) 285 | this.velocity = Vector(vel) 286 | this._fns = fns 287 | } 288 | 289 | Body.prototype.update = function(alpha) { 290 | var pos = this.previousPosition.clone().lerp(this.position, alpha) 291 | this._fns.update(pos, this.velocity) 292 | } 293 | 294 | Body.prototype.accelerate = function(state, t) { 295 | return this._fns.accelerate(state, t) 296 | } 297 | 298 | Body.prototype.atRest = function() { 299 | return this.velocity.norm() < .01 300 | } 301 | 302 | Body.prototype.atPosition = function(pos) { 303 | //return whether the distance between this.position and pos is less than .1 304 | return this.position.sub(Vector(pos)).norm() < .01 305 | } 306 | 307 | },{"./vector":14}],5:[function(require,module,exports){ 308 | var Vector = require('./vector') 309 | module.exports = Boundary 310 | 311 | function pointBetween(p, p1, p2) { 312 | return p >= p1 && p <= p2 313 | } 314 | 315 | function yIntersect(y, point, direction) { 316 | var factor = (y - point.y) / direction.y 317 | return point.add(direction.clone().mult(factor)) 318 | } 319 | 320 | function xIntersect(x, point, direction) { 321 | var factor = (x - point.x) / direction.x 322 | return point.add(direction.clone().mult(factor)) 323 | } 324 | 325 | Boundary.prototype.applyDamping = function(position, damping) { 326 | var x = position.x 327 | , y = position.y 328 | 329 | if(x < this.left) 330 | x = this.left - (this.left - x) * damping 331 | 332 | if(y < this.top) 333 | y = this.top - (this.top - y) * damping 334 | 335 | if(x > this.right) 336 | x = this.right - (this.right - x) * damping 337 | 338 | if(y > this.bottom) 339 | y = this.bottom - (this.bottom - y) * damping 340 | 341 | return Vector(x, y) 342 | } 343 | 344 | function Boundary(boundary) { 345 | if(!(this instanceof Boundary)) 346 | return new Boundary(boundary) 347 | 348 | this.left = (typeof boundary.left !== 'undefined') ? boundary.left : -Infinity 349 | this.right = (typeof boundary.right !== 'undefined') ? boundary.right : Infinity 350 | this.top = (typeof boundary.top !== 'undefined') ? boundary.top : -Infinity 351 | this.bottom = (typeof boundary.bottom !== 'undefined') ? boundary.bottom : Infinity 352 | } 353 | 354 | Boundary.prototype.contains = function(pt) { 355 | return pt.x >= this.left && 356 | pt.x <= this.right && 357 | pt.y >= this.top && 358 | pt.y <= this.bottom 359 | } 360 | 361 | Boundary.prototype.nearestIntersect = function(point, velocity) { 362 | var direction = Vector(velocity).normalize() 363 | , point = Vector(point) 364 | , isect 365 | , distX 366 | , distY 367 | 368 | if(velocity.y < 0) 369 | isect = yIntersect(this.top, point, direction) 370 | if(velocity.y > 0) 371 | isect = yIntersect(this.bottom, point, direction) 372 | 373 | if(isect && pointBetween(isect.x, this.left, this.right)) 374 | return isect 375 | 376 | if(velocity.x < 0) 377 | isect = xIntersect(this.left, point, direction) 378 | if(velocity.x > 0) 379 | isect = xIntersect(this.right, point, direction) 380 | 381 | if(isect && pointBetween(isect.y, this.top, this.bottom)) 382 | return isect 383 | 384 | //if the velocity is zero, or it didn't intersect any lines (outside the box) 385 | //just send it it the nearest boundary 386 | distX = (Math.abs(point.x - this.left) < Math.abs(point.x - this.right)) ? this.left : this.right 387 | distY = (Math.abs(point.y - this.top) < Math.abs(point.y - this.bottom)) ? this.top : this.bottom 388 | 389 | return (distX < distY) ? Vector(distX, point.y) : Vector(point.x, distY) 390 | } 391 | 392 | },{"./vector":14}],6:[function(require,module,exports){ 393 | var Body = require('./body') 394 | var simulation = require('./simulation') 395 | var Boundary = require('./boundary') 396 | var Animation = require('./animation') 397 | 398 | var Decelerate = module.exports = Animation({ 399 | defaultOptions: { 400 | deceleration: 400 401 | }, 402 | onStart: function(velocity, from, to, opts, update, done) { 403 | var direction = to.sub(from).normalize() 404 | , deceleration = direction.mult(opts.deceleration).negate() 405 | , boundary = Boundary({ 406 | left: Math.min(to.x, from.x), 407 | right: Math.max(to.x, from.x), 408 | top: Math.min(to.y, from.y), 409 | bottom: Math.max(to.y, from.y) 410 | }) 411 | 412 | velocity = direction.mult(velocity.norm()) 413 | 414 | this._body = Body(velocity, from, { 415 | accelerate: function(s, t) { 416 | return deceleration 417 | }, 418 | update: function(position, velocity) { 419 | if(!direction.directionEqual(velocity)) { 420 | update.cancel(position, { x: 0, y: 0 }) 421 | } else if(boundary.contains(position)) { 422 | update.state(position, velocity) 423 | } else { 424 | update.done(to, velocity) 425 | } 426 | } 427 | }) 428 | simulation.addBody(this._body) 429 | }, 430 | 431 | onEnd: function() { 432 | simulation.removeBody(this._body) 433 | } 434 | }) 435 | 436 | },{"./animation":2,"./body":4,"./boundary":5,"./simulation":11}],7:[function(require,module,exports){ 437 | var Emitter = require('component-emitter') 438 | , defaults = require('lodash.defaults') 439 | 440 | var defaultOpts = {} 441 | 442 | module.exports = Drag 443 | 444 | function Drag(phys, opts, start) { 445 | var handles 446 | 447 | this._phys = phys 448 | if(typeof opts === 'function') { 449 | this._startFn = opts 450 | opts = {} 451 | } else { 452 | this._startFn = start 453 | } 454 | 455 | this._opts = defaults({}, defaultOpts, opts) 456 | 457 | //Warn of deprecated option 458 | if(this._opts.boundry){ 459 | console.warn("Warning: Misspelled option 'boundry' is being deprecated. Please use 'boundary' instead."); 460 | this._opts.boundary = this._opts.boundry; 461 | delete this._opts.boundry; 462 | } 463 | 464 | handles = this._opts.handle 465 | 466 | 467 | if(handles && !handles.length) { 468 | handles = [handles] 469 | } else if(handles && handles.length) { 470 | handles = [].slice.call(handles) 471 | } else { 472 | handles = phys.els 473 | } 474 | handles.forEach(this._setupHandle, this) 475 | } 476 | 477 | Emitter(Drag.prototype) 478 | 479 | Drag.prototype.moved = function() { 480 | return (this._interaction.distance() > 10) 481 | } 482 | 483 | Drag.prototype._setupHandle = function(el) { 484 | //start events 485 | el.addEventListener('touchstart', this._start.bind(this)) 486 | el.addEventListener('mousedown', this._start.bind(this)) 487 | 488 | //move events 489 | el.addEventListener('touchmove', this._move.bind(this)) 490 | //apply the move event to the window, so it keeps moving, 491 | //event if the handle doesn't 492 | window.addEventListener('mousemove', this._move.bind(this)) 493 | 494 | //end events 495 | el.addEventListener('touchend', this._end.bind(this)) 496 | window.addEventListener('mouseup', this._end.bind(this)) 497 | } 498 | 499 | Drag.prototype._start = function(evt) { 500 | this._startTime = Date.now() 501 | evt.preventDefault() 502 | this._mousedown = true 503 | this._interaction = this._phys.interact({ 504 | boundary: this._opts.boundary, 505 | damping: this._opts.damping, 506 | direction: this._opts.direction 507 | }) 508 | var promise = this._interaction.start(evt) 509 | this._startFn && this._startFn(promise) 510 | this.emit('start', evt) 511 | } 512 | 513 | Drag.prototype._move = function(evt) { 514 | if(!this._mousedown) return 515 | evt.preventDefault() 516 | 517 | this._interaction.update(evt) 518 | this.emit('move', evt) 519 | } 520 | 521 | Drag.prototype._end = function(evt) { 522 | if(!this._mousedown) return 523 | evt.preventDefault() 524 | 525 | this._mousedown = false 526 | 527 | this._interaction.end() 528 | this.emit('end', evt) 529 | } 530 | 531 | },{"component-emitter":16,"lodash.defaults":17}],8:[function(require,module,exports){ 532 | var simulation = require('./simulation') 533 | var Vector = require('./vector') 534 | var Renderer = require('./renderer') 535 | var defaults = require('lodash.defaults') 536 | var Spring = require('./spring') 537 | var AttachSpring = require('./attach-spring') 538 | var Decelerate = require('./decelerate') 539 | var Accelerate = require('./accelerate') 540 | var Drag = require('./drag') 541 | var Interact = require('./interact') 542 | var Boundary = require('./boundary') 543 | var Promise = window.Promise || require('promise') 544 | 545 | module.exports = Physics 546 | 547 | function Physics(rendererOrEls) { 548 | if(!(this instanceof Physics)) { 549 | return new Physics(rendererOrEls) 550 | } 551 | if(typeof rendererOrEls === 'function') { 552 | this._render = rendererOrEls 553 | this.els = [] 554 | } else { 555 | if(rendererOrEls.length) 556 | this.els = [].slice.call(rendererOrEls) 557 | else 558 | this.els = [rendererOrEls] 559 | 560 | this._renderer = new Renderer(this.els) 561 | this._render = this._renderer.update.bind(this._renderer) 562 | } 563 | 564 | this._position = Vector(0, 0) 565 | this._velocity = Vector(0, 0) 566 | } 567 | 568 | Physics.Boundary = Boundary 569 | Physics.Boundry = Boundary 570 | Physics.Vector = Vector 571 | Physics.Promise = Promise 572 | 573 | Physics.prototype.style = function() { 574 | this._renderer.style.apply(this._renderer, arguments) 575 | return this 576 | } 577 | 578 | Physics.prototype.visible = function() { 579 | this._renderer.visible.apply(this._renderer, arguments) 580 | return this 581 | } 582 | 583 | Physics.prototype.direction = function(d) { 584 | var velocity = this.velocity() 585 | , h, v, c 586 | 587 | if(velocity.x < 0) h = 'left' 588 | else if(velocity.x > 0) h = 'right' 589 | 590 | if(velocity.y < 0) v = 'up' 591 | else if(velocity.y > 0) v = 'down' 592 | 593 | var c = h + (v || '').toUpperCase() 594 | 595 | return d === h || d === v || d === c 596 | } 597 | 598 | Physics.prototype.forceRender = function() { 599 | if(this._renderer) { 600 | this._renderer.changed = true 601 | } 602 | } 603 | 604 | Physics.prototype.atRest = function() { 605 | var velocity = this.velocity() 606 | return velocity.x === 0 && velocity.y === 0 607 | } 608 | 609 | Physics.prototype._startAnimation = function(animation) { 610 | if(this._currentAnimation && this._currentAnimation.running()) { 611 | this._currentAnimation.cancel() 612 | } 613 | this._currentAnimation = animation 614 | } 615 | 616 | Physics.prototype.velocity = function(x, y) { 617 | if(!arguments.length) return this._velocity 618 | this._velocity = Vector(x, y) 619 | return this 620 | } 621 | 622 | Physics.prototype.position = function(x, y) { 623 | if(!arguments.length) return this._position.clone() 624 | this._position = Vector(x, y) 625 | this._render(this._position.x, this._position.y) 626 | return this 627 | } 628 | 629 | Physics.prototype.interact = function(opts) { 630 | return new Interact(this, opts) 631 | } 632 | 633 | Physics.prototype.drag = function(opts, start) { 634 | return new Drag(this, opts, start) 635 | } 636 | 637 | Physics.prototype.spring = function(opts) { 638 | return new Spring(this, opts) 639 | } 640 | 641 | Physics.prototype.decelerate = function(opts) { 642 | return new Decelerate(this, opts) 643 | } 644 | 645 | Physics.prototype.accelerate = function(opts) { 646 | return new Accelerate(this, opts) 647 | } 648 | 649 | Physics.prototype.attachSpring = function(attachment, opts) { 650 | return new AttachSpring(this, attachment, opts) 651 | } 652 | 653 | },{"./accelerate":1,"./attach-spring":3,"./boundary":5,"./decelerate":6,"./drag":7,"./interact":9,"./renderer":10,"./simulation":11,"./spring":12,"./vector":14,"lodash.defaults":17,"promise":24}],9:[function(require,module,exports){ 654 | var defaults = require('lodash.defaults') 655 | var Velocity = require('touch-velocity') 656 | var Vector = require('./vector') 657 | var Promise = require('promise') 658 | var util = require('./util') 659 | var Boundary = require('./boundary') 660 | 661 | module.exports = Interact 662 | 663 | var defaultOpts = { 664 | boundary: Boundary({}), 665 | damping: 0, 666 | direction: 'both' 667 | } 668 | 669 | function Interact(phys, opts) { 670 | this._phys = phys 671 | this._running = false 672 | this._opts = defaults({}, opts, defaultOpts) 673 | 674 | //Warn of deprecated option 675 | if(this._opts.boundry){ 676 | console.warn("Warning: Misspelled option 'boundry' is being deprecated. Please use 'boundary' instead."); 677 | this._opts.boundary = this._opts.boundry; 678 | delete this._opts.boundry; 679 | } 680 | } 681 | 682 | Interact.prototype.position = function(x, y) { 683 | var direction = this._opts.direction 684 | , boundary = this._opts.boundary 685 | , pos = Vector(x, y) 686 | 687 | if(direction !== 'both' && direction !== 'horizontal') pos.x = 0 688 | if(direction !== 'both' && direction !== 'vertical') pos.y = 0 689 | 690 | this._veloX.updatePosition(pos.x) 691 | this._veloY.updatePosition(pos.y) 692 | 693 | this._phys.velocity(this._veloX.getVelocity(), this._veloY.getVelocity()) 694 | 695 | pos = boundary.applyDamping(pos, this._opts.damping) 696 | 697 | this._phys.position(pos) 698 | 699 | return this 700 | } 701 | 702 | Interact.prototype.update = function(evt) { 703 | //for jquery and hammer.js 704 | evt = evt.originalEvent || evt 705 | var position = util.eventVector(evt).sub(this._startPosition) 706 | 707 | this.position(position) 708 | return this 709 | } 710 | 711 | Interact.prototype.start = function(evt) { 712 | var that = this 713 | , evtPosition = evt && util.eventVector(evt) 714 | , position = this._phys.position() 715 | 716 | this._running = true 717 | this._phys._startAnimation(this) 718 | this._startPosition = evt && evtPosition.sub(position) 719 | this._initialPosition = this._phys.position() 720 | 721 | this._veloX = new Velocity() 722 | this._veloY = new Velocity() 723 | 724 | this.position(position) 725 | 726 | return this._ended = new Promise(function(res, rej) { 727 | that._resolve = res 728 | that._reject = rej 729 | }) 730 | } 731 | 732 | Interact.prototype.distance = function() { 733 | return this._initialPosition.sub(this._phys.position()).norm() 734 | } 735 | 736 | Interact.prototype.cancel = function() { 737 | this._running = false 738 | this._reject(new Error('Canceled the interaction')) 739 | } 740 | 741 | Interact.prototype.running = function() { 742 | return this._running 743 | } 744 | 745 | Interact.prototype.end = function() { 746 | this._phys.velocity(this._veloX.getVelocity(), this._veloY.getVelocity()) 747 | this._resolve({ velocity: this._phys.velocity(), position: this._phys.position() }) 748 | return this._ended 749 | } 750 | 751 | },{"./boundary":5,"./util":13,"./vector":14,"lodash.defaults":17,"promise":24,"touch-velocity":28}],10:[function(require,module,exports){ 752 | var prefixes = ['Webkit', 'Moz', 'Ms', 'ms'] 753 | var calls = [] 754 | var transformProp 755 | var raf = require('raf') 756 | var floatEqual = require('./util').floatEqual 757 | 758 | function loop() { 759 | raf(function() { 760 | loop() 761 | for(var i = calls.length - 1; i >= 0; i--) { 762 | calls[i]() 763 | } 764 | }) 765 | } 766 | loop() 767 | 768 | function prefixed(prop) { 769 | var prefixed 770 | for (var i = 0; i < prefixes.length; i++) { 771 | prefixed = prefixes[i] + prop[0].toUpperCase() + prop.slice(1) 772 | if(typeof document.body.style[prefixed] !== 'undefined') 773 | return prefixed 774 | } 775 | return prop 776 | } 777 | 778 | var transformsProperties = ['translate', 'translateX', 'translateY', 'translateZ', 779 | 'rotate', 'rotateX', 'rotateY', 'rotate3d', 'rotateZ', 780 | 'scale', 'scaleX', 'scaleY', 'scaleZ', 781 | 'skew', 'skewX', 'skewY', 'skewZ'] 782 | 783 | module.exports = Renderer 784 | 785 | function Renderer(els) { 786 | if(typeof els.length === 'undefined') 787 | els = [els] 788 | this.els = els 789 | this.styles = {} 790 | this.invisibleEls = [] 791 | this.changed = false 792 | calls.push(this.render.bind(this)) 793 | } 794 | 795 | Renderer.prototype.render = function() { 796 | if(!this.changed) return 797 | 798 | if(!transformProp) 799 | transformProp = prefixed('transform') 800 | var transformsToApply 801 | , els = this.els 802 | , position = this.currentPosition 803 | , styles = this.styles 804 | , value 805 | , props = Object.keys(styles) 806 | , elsLength = els.length 807 | , propsLength = props.length 808 | , i, j 809 | , transforms 810 | 811 | this.changed = false 812 | 813 | for(i = 0 ; i < elsLength ; i++) { 814 | transformsToApply = [] 815 | if(this.visibleFn && !this.visibleFn(position, i)) { 816 | if(!this.invisibleEls[i]) { 817 | els[i].style.webkitTransform = 'translate3d(0, -99999px, 0)' 818 | } 819 | this.invisibleEls[i] = true 820 | } else { 821 | this.invisibleEls[i] = false 822 | for (j = 0; j < propsLength; j++) { 823 | prop = props[j] 824 | value = (typeof styles[prop] === 'function') ? styles[prop](position.x, position.y, i) : styles[prop] 825 | 826 | if(transformsProperties.indexOf(prop) !== -1) { 827 | transformsToApply.push(prop + '(' + value + ')') 828 | } else { 829 | els[i].style[prop] = value 830 | } 831 | } 832 | transforms = transformsToApply.join(' ') 833 | transforms += ' translateZ(0)' 834 | els[i].style[transformProp] = transforms 835 | } 836 | } 837 | } 838 | 839 | Renderer.prototype.style = function(property, value) { 840 | if(typeof property === 'object') { 841 | for(prop in property) { 842 | if(property.hasOwnProperty(prop)) { 843 | this.style(prop, property[prop]) 844 | } 845 | } 846 | } 847 | this.styles[property] = value 848 | return this 849 | } 850 | 851 | Renderer.prototype.visible = function(isVisible) { 852 | this.visibleFn = isVisible 853 | return this 854 | } 855 | 856 | Renderer.prototype.update = function(x, y) { 857 | if(this.currentPosition) { 858 | var equal = floatEqual(x, this.currentPosition.x) && floatEqual(y, this.currentPosition.y) 859 | this.changed = this.changed || !equal 860 | } else { 861 | this.changed = true 862 | } 863 | this.currentPosition = { x: x, y: y } 864 | } 865 | 866 | },{"./util":13,"raf":26}],11:[function(require,module,exports){ 867 | var Vector = require('./vector') 868 | , bodies = [] 869 | , raf = require('raf') 870 | 871 | function increment(a, b, c, d) { 872 | var vec = Vector(0, 0) 873 | vec.selfAdd(a) 874 | vec.selfAdd(b.add(c).selfMult(2)) 875 | vec.selfAdd(d) 876 | vec.selfMult(1/6) 877 | return vec 878 | } 879 | 880 | var positionVec = Vector(0, 0) 881 | var velocityVec = Vector(0, 0) 882 | 883 | function evaluate(initial, t, dt, d) { 884 | var state = {} 885 | 886 | state.position = positionVec.setv(d.dx).selfMult(dt).selfAdd(initial.position) 887 | state.velocity = velocityVec.setv(d.dv).selfMult(dt).selfAdd(initial.velocity) 888 | 889 | var next = { 890 | dx: state.velocity.clone(), 891 | dv: initial.accelerate(state, t).clone() 892 | } 893 | return next 894 | } 895 | 896 | var der = { dx: Vector(0, 0), dv: Vector(0, 0) } 897 | function integrate(state, t, dt) { 898 | var a = evaluate( state, t, 0, der ) 899 | var b = evaluate( state, t, dt*0.5, a ) 900 | var c = evaluate( state, t, dt*0.5, b ) 901 | var d = evaluate( state, t, dt, c ) 902 | 903 | var dxdt = increment(a.dx,b.dx,c.dx,d.dx) 904 | , dvdt = increment(a.dv,b.dv,c.dv,d.dv) 905 | 906 | state.position.selfAdd(dxdt.selfMult(dt)); 907 | state.velocity.selfAdd(dvdt.selfMult(dt)); 908 | } 909 | 910 | var currentTime = Date.now() / 1000 911 | , accumulator = 0 912 | , t = 0 913 | , dt = 0.015 914 | 915 | function simulate() { 916 | raf(function() { 917 | simulate() 918 | var newTime = Date.now() / 1000 919 | var frameTime = newTime - currentTime 920 | currentTime = newTime 921 | 922 | if(frameTime > 0.05) 923 | frameTime = 0.05 924 | 925 | 926 | accumulator += frameTime 927 | 928 | var j = 0 929 | 930 | while(accumulator >= dt) { 931 | for(var i = 0 ; i < bodies.length ; i++) { 932 | bodies[i].previousPosition = bodies[i].position.clone() 933 | integrate(bodies[i], t, dt) 934 | } 935 | t += dt 936 | accumulator -= dt 937 | } 938 | 939 | for(var i = 0 ; i < bodies.length ; i++) { 940 | bodies[i].update(accumulator / dt) 941 | } 942 | }, 16) 943 | } 944 | simulate() 945 | 946 | module.exports.addBody = function(body) { 947 | bodies.push(body) 948 | return body 949 | } 950 | 951 | module.exports.removeBody = function(body) { 952 | var index = bodies.indexOf(body) 953 | if(index >= 0) 954 | bodies.splice(index, 1) 955 | } 956 | 957 | },{"./vector":14,"raf":26}],12:[function(require,module,exports){ 958 | var Body = require('./body') 959 | var simulation = require('./simulation') 960 | var Boundary = require('./boundary') 961 | var Animation = require('./animation') 962 | 963 | var Spring = module.exports = Animation({ 964 | defaultOptions: { 965 | tension: 100, 966 | damping: 10 967 | }, 968 | onStart: function(velocity, from, to, opts, update) { 969 | var body = this._body = new Body(velocity, from, { 970 | accelerate: function(state, t) { 971 | return state.position.selfSub(to) 972 | .selfMult(-opts.tension) 973 | .selfSub(state.velocity.mult(opts.damping)) 974 | }, 975 | update: function(position, velocity) { 976 | if(body.atRest() && body.atPosition(to)) { 977 | update.done(to, { x: 0, y: 0 }) 978 | } else { 979 | update.state(position, velocity) 980 | } 981 | } 982 | }) 983 | simulation.addBody(this._body) 984 | }, 985 | onEnd: function() { 986 | simulation.removeBody(this._body) 987 | } 988 | }) 989 | 990 | },{"./animation":2,"./body":4,"./boundary":5,"./simulation":11}],13:[function(require,module,exports){ 991 | var Vector = require('./vector') 992 | 993 | function vertex(a, b) { 994 | return -b / (2 * a) 995 | } 996 | 997 | function height(a, b, c) { 998 | return parabola(a, b, c, vertex(a, b)) 999 | } 1000 | 1001 | function parabola(a, b, c, x) { 1002 | return a * x * x + b * x + c 1003 | } 1004 | 1005 | function eventVector(evt) { 1006 | return Vector({ 1007 | x: evt.touches && evt.touches[0].pageX || evt.pageX, 1008 | y: evt.touches && evt.touches[0].pageY || evt.pageY 1009 | }) 1010 | } 1011 | 1012 | function floatEqual(a, b) { 1013 | return Math.abs(a - b) < Number.EPSILON 1014 | } 1015 | 1016 | module.exports.height = height 1017 | module.exports.eventVector = eventVector 1018 | module.exports.floatEqual = floatEqual 1019 | 1020 | },{"./vector":14}],14:[function(require,module,exports){ 1021 | module.exports = Vector 1022 | 1023 | function Vector(x, y) { 1024 | if(!(this instanceof Vector)) 1025 | return new Vector(x, y) 1026 | 1027 | if(typeof x.x !== 'undefined') { 1028 | this.x = x.x 1029 | this.y = x.y 1030 | } else { 1031 | this.x = x || 0 1032 | this.y = y || 0 1033 | } 1034 | } 1035 | 1036 | Vector.prototype.equals = function(vec) { 1037 | return vec.x === this.x && vec.y === this.y 1038 | } 1039 | 1040 | Vector.prototype.directionEqual = function(vec) { 1041 | return vec.x > 0 === this.x > 0 && this.y > 0 === vec.y > 0 1042 | } 1043 | 1044 | Vector.prototype.dot = function (vec) { 1045 | return this.x * vec.x + this.y * vec.y; 1046 | } 1047 | 1048 | Vector.prototype.negate = function() { 1049 | return Vector(this.x, this.y).mult(-1) 1050 | } 1051 | 1052 | Vector.prototype.norm = function() { 1053 | return Math.sqrt(this.normsq()) 1054 | } 1055 | 1056 | Vector.prototype.clone = function() { 1057 | return Vector(this.x, this.y) 1058 | } 1059 | 1060 | Vector.prototype.normsq = function() { 1061 | return this.x * this.x + this.y * this.y 1062 | } 1063 | 1064 | Vector.prototype.normalize = function() { 1065 | var magnitude = this.norm() 1066 | 1067 | if(magnitude === 0) { 1068 | return this 1069 | } 1070 | 1071 | magnitude = 1 / magnitude 1072 | 1073 | this.x *= magnitude 1074 | this.y *= magnitude 1075 | 1076 | return this 1077 | } 1078 | 1079 | Vector.prototype.mult = function(x, y) { 1080 | if(x instanceof Vector) { 1081 | return new Vector(x.x * this.x, x.y * this.y) 1082 | } 1083 | if(typeof y === 'undefined') { //scalar 1084 | return new Vector(x * this.x, x * this.y) 1085 | } 1086 | return new Vector(x * this.x, y * this.y) 1087 | } 1088 | 1089 | Vector.prototype.selfMult = function(x, y) { 1090 | if(x instanceof Vector) { 1091 | this.x *= x.x 1092 | this.y *= x.y 1093 | return this 1094 | } 1095 | if(typeof y === 'undefined') { //scalar 1096 | this.x *= x 1097 | this.y *= x 1098 | return this 1099 | } 1100 | this.x *= x 1101 | this.y *= y 1102 | return this 1103 | } 1104 | 1105 | Vector.prototype.selfAdd = function(x, y) { 1106 | if(typeof x.x !== 'undefined') { 1107 | this.x += x.x 1108 | this.y += x.y 1109 | return this 1110 | } 1111 | if(typeof y === 'undefined') { //scalar 1112 | this.x += x 1113 | this.y += x 1114 | return this 1115 | } 1116 | this.x += x 1117 | this.y += y 1118 | return this 1119 | } 1120 | 1121 | Vector.prototype.selfSub = function(x, y) { 1122 | if(typeof x.x !== 'undefined') { 1123 | this.x -= x.x 1124 | this.y -= x.y 1125 | return this 1126 | } 1127 | if(typeof y === 'undefined') { //scalar 1128 | this.x -= x 1129 | this.y -= x 1130 | return this 1131 | } 1132 | this.x -= x 1133 | this.y -= y 1134 | 1135 | return this 1136 | } 1137 | 1138 | Vector.prototype.sub = function(x, y) { 1139 | 1140 | if(typeof x.x !== 'undefined') 1141 | return new Vector(this.x - x.x, this.y - x.y) 1142 | 1143 | if(typeof y === 'undefined')//scalar 1144 | return new Vector(this.x - x, this.y - x) 1145 | 1146 | return new Vector(this.x - x, this.y - y) 1147 | } 1148 | 1149 | Vector.prototype.add = function(x, y) { 1150 | if(typeof x.x !== 'undefined') { 1151 | return new Vector(this.x + x.x, this.y + x.y) 1152 | } 1153 | if(typeof y === 'undefined') { //scalar 1154 | return new Vector(this.x + x, this.y + x) 1155 | } 1156 | return new Vector(this.x + x, this.y + y) 1157 | } 1158 | 1159 | Vector.prototype.setv = function(vec) { 1160 | this.x = vec.x 1161 | this.y = vec.y 1162 | return this 1163 | } 1164 | 1165 | Vector.prototype.lerp = function(vector, alpha) { 1166 | return this.mult(1-alpha).add(vector.mult(alpha)) 1167 | } 1168 | 1169 | },{}],15:[function(require,module,exports){ 1170 | // shim for using process in browser 1171 | 1172 | var process = module.exports = {}; 1173 | 1174 | process.nextTick = (function () { 1175 | var canSetImmediate = typeof window !== 'undefined' 1176 | && window.setImmediate; 1177 | var canMutationObserver = typeof window !== 'undefined' 1178 | && window.MutationObserver; 1179 | var canPost = typeof window !== 'undefined' 1180 | && window.postMessage && window.addEventListener 1181 | ; 1182 | 1183 | if (canSetImmediate) { 1184 | return function (f) { return window.setImmediate(f) }; 1185 | } 1186 | 1187 | var queue = []; 1188 | 1189 | if (canMutationObserver) { 1190 | var hiddenDiv = document.createElement("div"); 1191 | var observer = new MutationObserver(function () { 1192 | var queueList = queue.slice(); 1193 | queue.length = 0; 1194 | queueList.forEach(function (fn) { 1195 | fn(); 1196 | }); 1197 | }); 1198 | 1199 | observer.observe(hiddenDiv, { attributes: true }); 1200 | 1201 | return function nextTick(fn) { 1202 | if (!queue.length) { 1203 | hiddenDiv.setAttribute('yes', 'no'); 1204 | } 1205 | queue.push(fn); 1206 | }; 1207 | } 1208 | 1209 | if (canPost) { 1210 | window.addEventListener('message', function (ev) { 1211 | var source = ev.source; 1212 | if ((source === window || source === null) && ev.data === 'process-tick') { 1213 | ev.stopPropagation(); 1214 | if (queue.length > 0) { 1215 | var fn = queue.shift(); 1216 | fn(); 1217 | } 1218 | } 1219 | }, true); 1220 | 1221 | return function nextTick(fn) { 1222 | queue.push(fn); 1223 | window.postMessage('process-tick', '*'); 1224 | }; 1225 | } 1226 | 1227 | return function nextTick(fn) { 1228 | setTimeout(fn, 0); 1229 | }; 1230 | })(); 1231 | 1232 | process.title = 'browser'; 1233 | process.browser = true; 1234 | process.env = {}; 1235 | process.argv = []; 1236 | 1237 | function noop() {} 1238 | 1239 | process.on = noop; 1240 | process.addListener = noop; 1241 | process.once = noop; 1242 | process.off = noop; 1243 | process.removeListener = noop; 1244 | process.removeAllListeners = noop; 1245 | process.emit = noop; 1246 | 1247 | process.binding = function (name) { 1248 | throw new Error('process.binding is not supported'); 1249 | }; 1250 | 1251 | // TODO(shtylman) 1252 | process.cwd = function () { return '/' }; 1253 | process.chdir = function (dir) { 1254 | throw new Error('process.chdir is not supported'); 1255 | }; 1256 | 1257 | },{}],16:[function(require,module,exports){ 1258 | 1259 | /** 1260 | * Expose `Emitter`. 1261 | */ 1262 | 1263 | module.exports = Emitter; 1264 | 1265 | /** 1266 | * Initialize a new `Emitter`. 1267 | * 1268 | * @api public 1269 | */ 1270 | 1271 | function Emitter(obj) { 1272 | if (obj) return mixin(obj); 1273 | }; 1274 | 1275 | /** 1276 | * Mixin the emitter properties. 1277 | * 1278 | * @param {Object} obj 1279 | * @return {Object} 1280 | * @api private 1281 | */ 1282 | 1283 | function mixin(obj) { 1284 | for (var key in Emitter.prototype) { 1285 | obj[key] = Emitter.prototype[key]; 1286 | } 1287 | return obj; 1288 | } 1289 | 1290 | /** 1291 | * Listen on the given `event` with `fn`. 1292 | * 1293 | * @param {String} event 1294 | * @param {Function} fn 1295 | * @return {Emitter} 1296 | * @api public 1297 | */ 1298 | 1299 | Emitter.prototype.on = 1300 | Emitter.prototype.addEventListener = function(event, fn){ 1301 | this._callbacks = this._callbacks || {}; 1302 | (this._callbacks[event] = this._callbacks[event] || []) 1303 | .push(fn); 1304 | return this; 1305 | }; 1306 | 1307 | /** 1308 | * Adds an `event` listener that will be invoked a single 1309 | * time then automatically removed. 1310 | * 1311 | * @param {String} event 1312 | * @param {Function} fn 1313 | * @return {Emitter} 1314 | * @api public 1315 | */ 1316 | 1317 | Emitter.prototype.once = function(event, fn){ 1318 | var self = this; 1319 | this._callbacks = this._callbacks || {}; 1320 | 1321 | function on() { 1322 | self.off(event, on); 1323 | fn.apply(this, arguments); 1324 | } 1325 | 1326 | on.fn = fn; 1327 | this.on(event, on); 1328 | return this; 1329 | }; 1330 | 1331 | /** 1332 | * Remove the given callback for `event` or all 1333 | * registered callbacks. 1334 | * 1335 | * @param {String} event 1336 | * @param {Function} fn 1337 | * @return {Emitter} 1338 | * @api public 1339 | */ 1340 | 1341 | Emitter.prototype.off = 1342 | Emitter.prototype.removeListener = 1343 | Emitter.prototype.removeAllListeners = 1344 | Emitter.prototype.removeEventListener = function(event, fn){ 1345 | this._callbacks = this._callbacks || {}; 1346 | 1347 | // all 1348 | if (0 == arguments.length) { 1349 | this._callbacks = {}; 1350 | return this; 1351 | } 1352 | 1353 | // specific event 1354 | var callbacks = this._callbacks[event]; 1355 | if (!callbacks) return this; 1356 | 1357 | // remove all handlers 1358 | if (1 == arguments.length) { 1359 | delete this._callbacks[event]; 1360 | return this; 1361 | } 1362 | 1363 | // remove specific handler 1364 | var cb; 1365 | for (var i = 0; i < callbacks.length; i++) { 1366 | cb = callbacks[i]; 1367 | if (cb === fn || cb.fn === fn) { 1368 | callbacks.splice(i, 1); 1369 | break; 1370 | } 1371 | } 1372 | return this; 1373 | }; 1374 | 1375 | /** 1376 | * Emit `event` with the given args. 1377 | * 1378 | * @param {String} event 1379 | * @param {Mixed} ... 1380 | * @return {Emitter} 1381 | */ 1382 | 1383 | Emitter.prototype.emit = function(event){ 1384 | this._callbacks = this._callbacks || {}; 1385 | var args = [].slice.call(arguments, 1) 1386 | , callbacks = this._callbacks[event]; 1387 | 1388 | if (callbacks) { 1389 | callbacks = callbacks.slice(0); 1390 | for (var i = 0, len = callbacks.length; i < len; ++i) { 1391 | callbacks[i].apply(this, args); 1392 | } 1393 | } 1394 | 1395 | return this; 1396 | }; 1397 | 1398 | /** 1399 | * Return array of callbacks for `event`. 1400 | * 1401 | * @param {String} event 1402 | * @return {Array} 1403 | * @api public 1404 | */ 1405 | 1406 | Emitter.prototype.listeners = function(event){ 1407 | this._callbacks = this._callbacks || {}; 1408 | return this._callbacks[event] || []; 1409 | }; 1410 | 1411 | /** 1412 | * Check if this emitter has `event` handlers. 1413 | * 1414 | * @param {String} event 1415 | * @return {Boolean} 1416 | * @api public 1417 | */ 1418 | 1419 | Emitter.prototype.hasListeners = function(event){ 1420 | return !! this.listeners(event).length; 1421 | }; 1422 | 1423 | },{}],17:[function(require,module,exports){ 1424 | /** 1425 | * Lo-Dash 2.4.1 (Custom Build) 1426 | * Build: `lodash modularize modern exports="npm" -o ./npm/` 1427 | * Copyright 2012-2013 The Dojo Foundation 1428 | * Based on Underscore.js 1.5.2 1429 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 1430 | * Available under MIT license 1431 | */ 1432 | var keys = require('lodash.keys'), 1433 | objectTypes = require('lodash._objecttypes'); 1434 | 1435 | /** 1436 | * Assigns own enumerable properties of source object(s) to the destination 1437 | * object for all destination properties that resolve to `undefined`. Once a 1438 | * property is set, additional defaults of the same property will be ignored. 1439 | * 1440 | * @static 1441 | * @memberOf _ 1442 | * @type Function 1443 | * @category Objects 1444 | * @param {Object} object The destination object. 1445 | * @param {...Object} [source] The source objects. 1446 | * @param- {Object} [guard] Allows working with `_.reduce` without using its 1447 | * `key` and `object` arguments as sources. 1448 | * @returns {Object} Returns the destination object. 1449 | * @example 1450 | * 1451 | * var object = { 'name': 'barney' }; 1452 | * _.defaults(object, { 'name': 'fred', 'employer': 'slate' }); 1453 | * // => { 'name': 'barney', 'employer': 'slate' } 1454 | */ 1455 | var defaults = function(object, source, guard) { 1456 | var index, iterable = object, result = iterable; 1457 | if (!iterable) return result; 1458 | var args = arguments, 1459 | argsIndex = 0, 1460 | argsLength = typeof guard == 'number' ? 2 : args.length; 1461 | while (++argsIndex < argsLength) { 1462 | iterable = args[argsIndex]; 1463 | if (iterable && objectTypes[typeof iterable]) { 1464 | var ownIndex = -1, 1465 | ownProps = objectTypes[typeof iterable] && keys(iterable), 1466 | length = ownProps ? ownProps.length : 0; 1467 | 1468 | while (++ownIndex < length) { 1469 | index = ownProps[ownIndex]; 1470 | if (typeof result[index] == 'undefined') result[index] = iterable[index]; 1471 | } 1472 | } 1473 | } 1474 | return result 1475 | }; 1476 | 1477 | module.exports = defaults; 1478 | 1479 | },{"lodash._objecttypes":18,"lodash.keys":19}],18:[function(require,module,exports){ 1480 | /** 1481 | * Lo-Dash 2.4.1 (Custom Build) 1482 | * Build: `lodash modularize modern exports="npm" -o ./npm/` 1483 | * Copyright 2012-2013 The Dojo Foundation 1484 | * Based on Underscore.js 1.5.2 1485 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 1486 | * Available under MIT license 1487 | */ 1488 | 1489 | /** Used to determine if values are of the language type Object */ 1490 | var objectTypes = { 1491 | 'boolean': false, 1492 | 'function': true, 1493 | 'object': true, 1494 | 'number': false, 1495 | 'string': false, 1496 | 'undefined': false 1497 | }; 1498 | 1499 | module.exports = objectTypes; 1500 | 1501 | },{}],19:[function(require,module,exports){ 1502 | /** 1503 | * Lo-Dash 2.4.1 (Custom Build) 1504 | * Build: `lodash modularize modern exports="npm" -o ./npm/` 1505 | * Copyright 2012-2013 The Dojo Foundation 1506 | * Based on Underscore.js 1.5.2 1507 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 1508 | * Available under MIT license 1509 | */ 1510 | var isNative = require('lodash._isnative'), 1511 | isObject = require('lodash.isobject'), 1512 | shimKeys = require('lodash._shimkeys'); 1513 | 1514 | /* Native method shortcuts for methods with the same name as other `lodash` methods */ 1515 | var nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys; 1516 | 1517 | /** 1518 | * Creates an array composed of the own enumerable property names of an object. 1519 | * 1520 | * @static 1521 | * @memberOf _ 1522 | * @category Objects 1523 | * @param {Object} object The object to inspect. 1524 | * @returns {Array} Returns an array of property names. 1525 | * @example 1526 | * 1527 | * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); 1528 | * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) 1529 | */ 1530 | var keys = !nativeKeys ? shimKeys : function(object) { 1531 | if (!isObject(object)) { 1532 | return []; 1533 | } 1534 | return nativeKeys(object); 1535 | }; 1536 | 1537 | module.exports = keys; 1538 | 1539 | },{"lodash._isnative":20,"lodash._shimkeys":21,"lodash.isobject":22}],20:[function(require,module,exports){ 1540 | /** 1541 | * Lo-Dash 2.4.1 (Custom Build) 1542 | * Build: `lodash modularize modern exports="npm" -o ./npm/` 1543 | * Copyright 2012-2013 The Dojo Foundation 1544 | * Based on Underscore.js 1.5.2 1545 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 1546 | * Available under MIT license 1547 | */ 1548 | 1549 | /** Used for native method references */ 1550 | var objectProto = Object.prototype; 1551 | 1552 | /** Used to resolve the internal [[Class]] of values */ 1553 | var toString = objectProto.toString; 1554 | 1555 | /** Used to detect if a method is native */ 1556 | var reNative = RegExp('^' + 1557 | String(toString) 1558 | .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') 1559 | .replace(/toString| for [^\]]+/g, '.*?') + '$' 1560 | ); 1561 | 1562 | /** 1563 | * Checks if `value` is a native function. 1564 | * 1565 | * @private 1566 | * @param {*} value The value to check. 1567 | * @returns {boolean} Returns `true` if the `value` is a native function, else `false`. 1568 | */ 1569 | function isNative(value) { 1570 | return typeof value == 'function' && reNative.test(value); 1571 | } 1572 | 1573 | module.exports = isNative; 1574 | 1575 | },{}],21:[function(require,module,exports){ 1576 | /** 1577 | * Lo-Dash 2.4.1 (Custom Build) 1578 | * Build: `lodash modularize modern exports="npm" -o ./npm/` 1579 | * Copyright 2012-2013 The Dojo Foundation 1580 | * Based on Underscore.js 1.5.2 1581 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 1582 | * Available under MIT license 1583 | */ 1584 | var objectTypes = require('lodash._objecttypes'); 1585 | 1586 | /** Used for native method references */ 1587 | var objectProto = Object.prototype; 1588 | 1589 | /** Native method shortcuts */ 1590 | var hasOwnProperty = objectProto.hasOwnProperty; 1591 | 1592 | /** 1593 | * A fallback implementation of `Object.keys` which produces an array of the 1594 | * given object's own enumerable property names. 1595 | * 1596 | * @private 1597 | * @type Function 1598 | * @param {Object} object The object to inspect. 1599 | * @returns {Array} Returns an array of property names. 1600 | */ 1601 | var shimKeys = function(object) { 1602 | var index, iterable = object, result = []; 1603 | if (!iterable) return result; 1604 | if (!(objectTypes[typeof object])) return result; 1605 | for (index in iterable) { 1606 | if (hasOwnProperty.call(iterable, index)) { 1607 | result.push(index); 1608 | } 1609 | } 1610 | return result 1611 | }; 1612 | 1613 | module.exports = shimKeys; 1614 | 1615 | },{"lodash._objecttypes":18}],22:[function(require,module,exports){ 1616 | /** 1617 | * Lo-Dash 2.4.1 (Custom Build) 1618 | * Build: `lodash modularize modern exports="npm" -o ./npm/` 1619 | * Copyright 2012-2013 The Dojo Foundation 1620 | * Based on Underscore.js 1.5.2 1621 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 1622 | * Available under MIT license 1623 | */ 1624 | var objectTypes = require('lodash._objecttypes'); 1625 | 1626 | /** 1627 | * Checks if `value` is the language type of Object. 1628 | * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 1629 | * 1630 | * @static 1631 | * @memberOf _ 1632 | * @category Objects 1633 | * @param {*} value The value to check. 1634 | * @returns {boolean} Returns `true` if the `value` is an object, else `false`. 1635 | * @example 1636 | * 1637 | * _.isObject({}); 1638 | * // => true 1639 | * 1640 | * _.isObject([1, 2, 3]); 1641 | * // => true 1642 | * 1643 | * _.isObject(1); 1644 | * // => false 1645 | */ 1646 | function isObject(value) { 1647 | // check if the value is the ECMAScript language type of Object 1648 | // http://es5.github.io/#x8 1649 | // and avoid a V8 bug 1650 | // http://code.google.com/p/v8/issues/detail?id=2291 1651 | return !!(value && objectTypes[typeof value]); 1652 | } 1653 | 1654 | module.exports = isObject; 1655 | 1656 | },{"lodash._objecttypes":18}],23:[function(require,module,exports){ 1657 | 'use strict'; 1658 | 1659 | var asap = require('asap') 1660 | 1661 | module.exports = Promise 1662 | function Promise(fn) { 1663 | if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new') 1664 | if (typeof fn !== 'function') throw new TypeError('not a function') 1665 | var state = null 1666 | var value = null 1667 | var deferreds = [] 1668 | var self = this 1669 | 1670 | this.then = function(onFulfilled, onRejected) { 1671 | return new Promise(function(resolve, reject) { 1672 | handle(new Handler(onFulfilled, onRejected, resolve, reject)) 1673 | }) 1674 | } 1675 | 1676 | function handle(deferred) { 1677 | if (state === null) { 1678 | deferreds.push(deferred) 1679 | return 1680 | } 1681 | asap(function() { 1682 | var cb = state ? deferred.onFulfilled : deferred.onRejected 1683 | if (cb === null) { 1684 | (state ? deferred.resolve : deferred.reject)(value) 1685 | return 1686 | } 1687 | var ret 1688 | try { 1689 | ret = cb(value) 1690 | } 1691 | catch (e) { 1692 | deferred.reject(e) 1693 | return 1694 | } 1695 | deferred.resolve(ret) 1696 | }) 1697 | } 1698 | 1699 | function resolve(newValue) { 1700 | try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure 1701 | if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.') 1702 | if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { 1703 | var then = newValue.then 1704 | if (typeof then === 'function') { 1705 | doResolve(then.bind(newValue), resolve, reject) 1706 | return 1707 | } 1708 | } 1709 | state = true 1710 | value = newValue 1711 | finale() 1712 | } catch (e) { reject(e) } 1713 | } 1714 | 1715 | function reject(newValue) { 1716 | state = false 1717 | value = newValue 1718 | finale() 1719 | } 1720 | 1721 | function finale() { 1722 | for (var i = 0, len = deferreds.length; i < len; i++) 1723 | handle(deferreds[i]) 1724 | deferreds = null 1725 | } 1726 | 1727 | doResolve(fn, resolve, reject) 1728 | } 1729 | 1730 | 1731 | function Handler(onFulfilled, onRejected, resolve, reject){ 1732 | this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null 1733 | this.onRejected = typeof onRejected === 'function' ? onRejected : null 1734 | this.resolve = resolve 1735 | this.reject = reject 1736 | } 1737 | 1738 | /** 1739 | * Take a potentially misbehaving resolver function and make sure 1740 | * onFulfilled and onRejected are only called once. 1741 | * 1742 | * Makes no guarantees about asynchrony. 1743 | */ 1744 | function doResolve(fn, onFulfilled, onRejected) { 1745 | var done = false; 1746 | try { 1747 | fn(function (value) { 1748 | if (done) return 1749 | done = true 1750 | onFulfilled(value) 1751 | }, function (reason) { 1752 | if (done) return 1753 | done = true 1754 | onRejected(reason) 1755 | }) 1756 | } catch (ex) { 1757 | if (done) return 1758 | done = true 1759 | onRejected(ex) 1760 | } 1761 | } 1762 | 1763 | },{"asap":25}],24:[function(require,module,exports){ 1764 | 'use strict'; 1765 | 1766 | //This file contains then/promise specific extensions to the core promise API 1767 | 1768 | var Promise = require('./core.js') 1769 | var asap = require('asap') 1770 | 1771 | module.exports = Promise 1772 | 1773 | /* Static Functions */ 1774 | 1775 | function ValuePromise(value) { 1776 | this.then = function (onFulfilled) { 1777 | if (typeof onFulfilled !== 'function') return this 1778 | return new Promise(function (resolve, reject) { 1779 | asap(function () { 1780 | try { 1781 | resolve(onFulfilled(value)) 1782 | } catch (ex) { 1783 | reject(ex); 1784 | } 1785 | }) 1786 | }) 1787 | } 1788 | } 1789 | ValuePromise.prototype = Object.create(Promise.prototype) 1790 | 1791 | var TRUE = new ValuePromise(true) 1792 | var FALSE = new ValuePromise(false) 1793 | var NULL = new ValuePromise(null) 1794 | var UNDEFINED = new ValuePromise(undefined) 1795 | var ZERO = new ValuePromise(0) 1796 | var EMPTYSTRING = new ValuePromise('') 1797 | 1798 | Promise.resolve = function (value) { 1799 | if (value instanceof Promise) return value 1800 | 1801 | if (value === null) return NULL 1802 | if (value === undefined) return UNDEFINED 1803 | if (value === true) return TRUE 1804 | if (value === false) return FALSE 1805 | if (value === 0) return ZERO 1806 | if (value === '') return EMPTYSTRING 1807 | 1808 | if (typeof value === 'object' || typeof value === 'function') { 1809 | try { 1810 | var then = value.then 1811 | if (typeof then === 'function') { 1812 | return new Promise(then.bind(value)) 1813 | } 1814 | } catch (ex) { 1815 | return new Promise(function (resolve, reject) { 1816 | reject(ex) 1817 | }) 1818 | } 1819 | } 1820 | 1821 | return new ValuePromise(value) 1822 | } 1823 | 1824 | Promise.from = Promise.cast = function (value) { 1825 | var err = new Error('Promise.from and Promise.cast are deprecated, use Promise.resolve instead') 1826 | err.name = 'Warning' 1827 | console.warn(err.stack) 1828 | return Promise.resolve(value) 1829 | } 1830 | 1831 | Promise.denodeify = function (fn, argumentCount) { 1832 | argumentCount = argumentCount || Infinity 1833 | return function () { 1834 | var self = this 1835 | var args = Array.prototype.slice.call(arguments) 1836 | return new Promise(function (resolve, reject) { 1837 | while (args.length && args.length > argumentCount) { 1838 | args.pop() 1839 | } 1840 | args.push(function (err, res) { 1841 | if (err) reject(err) 1842 | else resolve(res) 1843 | }) 1844 | fn.apply(self, args) 1845 | }) 1846 | } 1847 | } 1848 | Promise.nodeify = function (fn) { 1849 | return function () { 1850 | var args = Array.prototype.slice.call(arguments) 1851 | var callback = typeof args[args.length - 1] === 'function' ? args.pop() : null 1852 | try { 1853 | return fn.apply(this, arguments).nodeify(callback) 1854 | } catch (ex) { 1855 | if (callback === null || typeof callback == 'undefined') { 1856 | return new Promise(function (resolve, reject) { reject(ex) }) 1857 | } else { 1858 | asap(function () { 1859 | callback(ex) 1860 | }) 1861 | } 1862 | } 1863 | } 1864 | } 1865 | 1866 | Promise.all = function () { 1867 | var calledWithArray = arguments.length === 1 && Array.isArray(arguments[0]) 1868 | var args = Array.prototype.slice.call(calledWithArray ? arguments[0] : arguments) 1869 | 1870 | if (!calledWithArray) { 1871 | var err = new Error('Promise.all should be called with a single array, calling it with multiple arguments is deprecated') 1872 | err.name = 'Warning' 1873 | console.warn(err.stack) 1874 | } 1875 | 1876 | return new Promise(function (resolve, reject) { 1877 | if (args.length === 0) return resolve([]) 1878 | var remaining = args.length 1879 | function res(i, val) { 1880 | try { 1881 | if (val && (typeof val === 'object' || typeof val === 'function')) { 1882 | var then = val.then 1883 | if (typeof then === 'function') { 1884 | then.call(val, function (val) { res(i, val) }, reject) 1885 | return 1886 | } 1887 | } 1888 | args[i] = val 1889 | if (--remaining === 0) { 1890 | resolve(args); 1891 | } 1892 | } catch (ex) { 1893 | reject(ex) 1894 | } 1895 | } 1896 | for (var i = 0; i < args.length; i++) { 1897 | res(i, args[i]) 1898 | } 1899 | }) 1900 | } 1901 | 1902 | Promise.reject = function (value) { 1903 | return new Promise(function (resolve, reject) { 1904 | reject(value); 1905 | }); 1906 | } 1907 | 1908 | Promise.race = function (values) { 1909 | return new Promise(function (resolve, reject) { 1910 | values.forEach(function(value){ 1911 | Promise.resolve(value).then(resolve, reject); 1912 | }) 1913 | }); 1914 | } 1915 | 1916 | /* Prototype Methods */ 1917 | 1918 | Promise.prototype.done = function (onFulfilled, onRejected) { 1919 | var self = arguments.length ? this.then.apply(this, arguments) : this 1920 | self.then(null, function (err) { 1921 | asap(function () { 1922 | throw err 1923 | }) 1924 | }) 1925 | } 1926 | 1927 | Promise.prototype.nodeify = function (callback) { 1928 | if (typeof callback != 'function') return this 1929 | 1930 | this.then(function (value) { 1931 | asap(function () { 1932 | callback(null, value) 1933 | }) 1934 | }, function (err) { 1935 | asap(function () { 1936 | callback(err) 1937 | }) 1938 | }) 1939 | } 1940 | 1941 | Promise.prototype['catch'] = function (onRejected) { 1942 | return this.then(null, onRejected); 1943 | } 1944 | 1945 | },{"./core.js":23,"asap":25}],25:[function(require,module,exports){ 1946 | (function (process){ 1947 | 1948 | // Use the fastest possible means to execute a task in a future turn 1949 | // of the event loop. 1950 | 1951 | // linked list of tasks (single, with head node) 1952 | var head = {task: void 0, next: null}; 1953 | var tail = head; 1954 | var flushing = false; 1955 | var requestFlush = void 0; 1956 | var isNodeJS = false; 1957 | 1958 | function flush() { 1959 | /* jshint loopfunc: true */ 1960 | 1961 | while (head.next) { 1962 | head = head.next; 1963 | var task = head.task; 1964 | head.task = void 0; 1965 | var domain = head.domain; 1966 | 1967 | if (domain) { 1968 | head.domain = void 0; 1969 | domain.enter(); 1970 | } 1971 | 1972 | try { 1973 | task(); 1974 | 1975 | } catch (e) { 1976 | if (isNodeJS) { 1977 | // In node, uncaught exceptions are considered fatal errors. 1978 | // Re-throw them synchronously to interrupt flushing! 1979 | 1980 | // Ensure continuation if the uncaught exception is suppressed 1981 | // listening "uncaughtException" events (as domains does). 1982 | // Continue in next event to avoid tick recursion. 1983 | if (domain) { 1984 | domain.exit(); 1985 | } 1986 | setTimeout(flush, 0); 1987 | if (domain) { 1988 | domain.enter(); 1989 | } 1990 | 1991 | throw e; 1992 | 1993 | } else { 1994 | // In browsers, uncaught exceptions are not fatal. 1995 | // Re-throw them asynchronously to avoid slow-downs. 1996 | setTimeout(function() { 1997 | throw e; 1998 | }, 0); 1999 | } 2000 | } 2001 | 2002 | if (domain) { 2003 | domain.exit(); 2004 | } 2005 | } 2006 | 2007 | flushing = false; 2008 | } 2009 | 2010 | if (typeof process !== "undefined" && process.nextTick) { 2011 | // Node.js before 0.9. Note that some fake-Node environments, like the 2012 | // Mocha test runner, introduce a `process` global without a `nextTick`. 2013 | isNodeJS = true; 2014 | 2015 | requestFlush = function () { 2016 | process.nextTick(flush); 2017 | }; 2018 | 2019 | } else if (typeof setImmediate === "function") { 2020 | // In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate 2021 | if (typeof window !== "undefined") { 2022 | requestFlush = setImmediate.bind(window, flush); 2023 | } else { 2024 | requestFlush = function () { 2025 | setImmediate(flush); 2026 | }; 2027 | } 2028 | 2029 | } else if (typeof MessageChannel !== "undefined") { 2030 | // modern browsers 2031 | // http://www.nonblocking.io/2011/06/windownexttick.html 2032 | var channel = new MessageChannel(); 2033 | channel.port1.onmessage = flush; 2034 | requestFlush = function () { 2035 | channel.port2.postMessage(0); 2036 | }; 2037 | 2038 | } else { 2039 | // old browsers 2040 | requestFlush = function () { 2041 | setTimeout(flush, 0); 2042 | }; 2043 | } 2044 | 2045 | function asap(task) { 2046 | tail = tail.next = { 2047 | task: task, 2048 | domain: isNodeJS && process.domain, 2049 | next: null 2050 | }; 2051 | 2052 | if (!flushing) { 2053 | flushing = true; 2054 | requestFlush(); 2055 | } 2056 | }; 2057 | 2058 | module.exports = asap; 2059 | 2060 | 2061 | }).call(this,require('_process')) 2062 | },{"_process":15}],26:[function(require,module,exports){ 2063 | var now = require('performance-now') 2064 | , global = typeof window === 'undefined' ? {} : window 2065 | , vendors = ['moz', 'webkit'] 2066 | , suffix = 'AnimationFrame' 2067 | , raf = global['request' + suffix] 2068 | , caf = global['cancel' + suffix] || global['cancelRequest' + suffix] 2069 | , native = true 2070 | 2071 | for(var i = 0; i < vendors.length && !raf; i++) { 2072 | raf = global[vendors[i] + 'Request' + suffix] 2073 | caf = global[vendors[i] + 'Cancel' + suffix] 2074 | || global[vendors[i] + 'CancelRequest' + suffix] 2075 | } 2076 | 2077 | // Some versions of FF have rAF but not cAF 2078 | if(!raf || !caf) { 2079 | native = false 2080 | 2081 | var last = 0 2082 | , id = 0 2083 | , queue = [] 2084 | , frameDuration = 1000 / 60 2085 | 2086 | raf = function(callback) { 2087 | if(queue.length === 0) { 2088 | var _now = now() 2089 | , next = Math.max(0, frameDuration - (_now - last)) 2090 | last = next + _now 2091 | setTimeout(function() { 2092 | var cp = queue.slice(0) 2093 | // Clear queue here to prevent 2094 | // callbacks from appending listeners 2095 | // to the current frame's queue 2096 | queue.length = 0 2097 | for(var i = 0; i < cp.length; i++) { 2098 | if(!cp[i].cancelled) { 2099 | try{ 2100 | cp[i].callback(last) 2101 | } catch(e) { 2102 | setTimeout(function() { throw e }, 0) 2103 | } 2104 | } 2105 | } 2106 | }, Math.round(next)) 2107 | } 2108 | queue.push({ 2109 | handle: ++id, 2110 | callback: callback, 2111 | cancelled: false 2112 | }) 2113 | return id 2114 | } 2115 | 2116 | caf = function(handle) { 2117 | for(var i = 0; i < queue.length; i++) { 2118 | if(queue[i].handle === handle) { 2119 | queue[i].cancelled = true 2120 | } 2121 | } 2122 | } 2123 | } 2124 | 2125 | module.exports = function(fn) { 2126 | // Wrap in a new function to prevent 2127 | // `cancel` potentially being assigned 2128 | // to the native rAF function 2129 | if(!native) { 2130 | return raf.call(global, fn) 2131 | } 2132 | return raf.call(global, function() { 2133 | try{ 2134 | fn.apply(this, arguments) 2135 | } catch(e) { 2136 | setTimeout(function() { throw e }, 0) 2137 | } 2138 | }) 2139 | } 2140 | module.exports.cancel = function() { 2141 | caf.apply(global, arguments) 2142 | } 2143 | 2144 | },{"performance-now":27}],27:[function(require,module,exports){ 2145 | (function (process){ 2146 | // Generated by CoffeeScript 1.6.3 2147 | (function() { 2148 | var getNanoSeconds, hrtime, loadTime; 2149 | 2150 | if ((typeof performance !== "undefined" && performance !== null) && performance.now) { 2151 | module.exports = function() { 2152 | return performance.now(); 2153 | }; 2154 | } else if ((typeof process !== "undefined" && process !== null) && process.hrtime) { 2155 | module.exports = function() { 2156 | return (getNanoSeconds() - loadTime) / 1e6; 2157 | }; 2158 | hrtime = process.hrtime; 2159 | getNanoSeconds = function() { 2160 | var hr; 2161 | hr = hrtime(); 2162 | return hr[0] * 1e9 + hr[1]; 2163 | }; 2164 | loadTime = getNanoSeconds(); 2165 | } else if (Date.now) { 2166 | module.exports = function() { 2167 | return Date.now() - loadTime; 2168 | }; 2169 | loadTime = Date.now(); 2170 | } else { 2171 | module.exports = function() { 2172 | return new Date().getTime() - loadTime; 2173 | }; 2174 | loadTime = new Date().getTime(); 2175 | } 2176 | 2177 | }).call(this); 2178 | 2179 | /* 2180 | //@ sourceMappingURL=performance-now.map 2181 | */ 2182 | 2183 | }).call(this,require('_process')) 2184 | },{"_process":15}],28:[function(require,module,exports){ 2185 | module.exports = Velocity 2186 | 2187 | function Velocity() { 2188 | this.positionQueue = [] 2189 | this.timeQueue = [] 2190 | } 2191 | 2192 | Velocity.prototype.reset = function() { 2193 | this.positionQueue.splice(0) 2194 | this.timeQueue.splice(0) 2195 | } 2196 | 2197 | Velocity.prototype.pruneQueue = function(ms) { 2198 | //pull old values off of the queue 2199 | while(this.timeQueue.length && this.timeQueue[0] < (Date.now() - ms)) { 2200 | this.timeQueue.shift() 2201 | this.positionQueue.shift() 2202 | } 2203 | } 2204 | 2205 | Velocity.prototype.updatePosition = function(position) { 2206 | this.positionQueue.push(position) 2207 | this.timeQueue.push(Date.now()) 2208 | this.pruneQueue(50) 2209 | } 2210 | 2211 | Velocity.prototype.getVelocity = function() { 2212 | this.pruneQueue(1000) 2213 | var length = this.timeQueue.length 2214 | if(length < 2) return 0 2215 | 2216 | var distance = this.positionQueue[length-1] - this.positionQueue[0] 2217 | , time = (this.timeQueue[length-1] - this.timeQueue[0]) / 1000 2218 | 2219 | return distance / time 2220 | } 2221 | 2222 | },{}]},{},[8])(8) 2223 | }); --------------------------------------------------------------------------------