Created
May 4, 2015 11:26
-
-
Save terion-name/5e8afdfd1dcb45b742dc to your computer and use it in GitHub Desktop.
Simple object properties (including nested) animator for timed frame animations with easings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Animator | |
| constructor: (obj)-> | |
| @obj = obj | |
| @stack = [] | |
| console.log this | |
| add: (property, to, duration, callback, easing)-> | |
| @stack.push { | |
| property: property | |
| from: parseFloat @getProperty @obj, property | |
| to: parseFloat to | |
| duration: duration or 250 | |
| callback: callback | |
| easing: easing | |
| } | |
| getProperty: (o, s) -> | |
| s = s.replace(/\[(\w+)\]/g, '.$1') # convert indexes to properties | |
| s = s.replace(/^\./, '') # strip a leading dot | |
| a = s.split('.') | |
| i = 0 | |
| n = a.length | |
| while i < n | |
| k = a[i] | |
| if o[k]? | |
| o = o[k] | |
| else | |
| return | |
| ++i | |
| return o | |
| setProperty: (o, s, v) -> | |
| s = s.replace(/\[(\w+)\]/g, '.$1') | |
| # convert indexes to properties | |
| s = s.replace(/^\./, '') | |
| # strip a leading dot | |
| a = s.split('.') | |
| i = 0 | |
| n = a.length | |
| while i < n-1 | |
| k = a[i] | |
| if o[k]? | |
| o = o[k] | |
| else | |
| return | |
| ++i | |
| o[a[i]] = v | |
| run: (frame)-> | |
| # frame.count - the number of times the frame event was fired | |
| # frame.time - The total amount of time passed since the first frame event in seconds | |
| # frame.delta - The time passed in seconds since the last frame event | |
| currentTime = new Date() | |
| index = 0 | |
| for task in @stack | |
| if task | |
| task.startTime = currentTime unless task.startTime? | |
| delta = currentTime - task.startTime | |
| #console.log task.property | |
| #console.log @getProperty(@obj, task.property) | |
| if delta > task.duration | |
| @setProperty(@obj, task.property, task.to) | |
| task.callback() if task.callback? | |
| @stack.splice(index, 1) | |
| else | |
| if task.easing and Animator.easings[task.easing]? | |
| value = Animator.easings[task.easing](null, delta, task.from, task.to - task.from, task.duration) | |
| else | |
| value = task.from + ((task.to - task.from) / task.duration * delta) | |
| @setProperty(@obj, task.property, value) | |
| ++index | |
| @easings: | |
| # jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ | |
| # t: current time, b: begInnIng value, c: change In value, d: duration | |
| easeInQuad: (x, t, b, c, d) -> | |
| c * (t /= d) * t + b | |
| easeOutQuad: (x, t, b, c, d) -> | |
| -c * (t /= d) * (t - 2) + b | |
| easeInOutQuad: (x, t, b, c, d) -> | |
| if (t /= d / 2) < 1 | |
| return c / 2 * t * t + b | |
| -c / 2 * (--t * (t - 2) - 1) + b | |
| easeInCubic: (x, t, b, c, d) -> | |
| c * (t /= d) * t * t + b | |
| easeOutCubic: (x, t, b, c, d) -> | |
| c * ((t = t / d - 1) * t * t + 1) + b | |
| easeInOutCubic: (x, t, b, c, d) -> | |
| if (t /= d / 2) < 1 | |
| return c / 2 * t * t * t + b | |
| c / 2 * ((t -= 2) * t * t + 2) + b | |
| easeInQuart: (x, t, b, c, d) -> | |
| c * (t /= d) * t * t * t + b | |
| easeOutQuart: (x, t, b, c, d) -> | |
| -c * ((t = t / d - 1) * t * t * t - 1) + b | |
| easeInOutQuart: (x, t, b, c, d) -> | |
| if (t /= d / 2) < 1 | |
| return c / 2 * t * t * t * t + b | |
| -c / 2 * ((t -= 2) * t * t * t - 2) + b | |
| easeInQuint: (x, t, b, c, d) -> | |
| c * (t /= d) * t * t * t * t + b | |
| easeOutQuint: (x, t, b, c, d) -> | |
| c * ((t = t / d - 1) * t * t * t * t + 1) + b | |
| easeInOutQuint: (x, t, b, c, d) -> | |
| if (t /= d / 2) < 1 | |
| return c / 2 * t * t * t * t * t + b | |
| c / 2 * ((t -= 2) * t * t * t * t + 2) + b | |
| easeInSine: (x, t, b, c, d) -> | |
| -c * Math.cos(t / d * Math.PI / 2) + c + b | |
| easeOutSine: (x, t, b, c, d) -> | |
| c * Math.sin(t / d * Math.PI / 2) + b | |
| easeInOutSine: (x, t, b, c, d) -> | |
| -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b | |
| easeInExpo: (x, t, b, c, d) -> | |
| if t == 0 then b else c * 2 ** (10 * (t / d - 1)) + b | |
| easeOutExpo: (x, t, b, c, d) -> | |
| if t == d then b + c else c * (-2 ** (-10 * t / d) + 1) + b | |
| easeInOutExpo: (x, t, b, c, d) -> | |
| if t == 0 | |
| return b | |
| if t == d | |
| return b + c | |
| if (t /= d / 2) < 1 | |
| return c / 2 * 2 ** (10 * (t - 1)) + b | |
| c / 2 * (-2 ** (-10 * --t) + 2) + b | |
| easeInCirc: (x, t, b, c, d) -> | |
| -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b | |
| easeOutCirc: (x, t, b, c, d) -> | |
| c * Math.sqrt(1 - (t = t / d - 1) * t) + b | |
| easeInOutCirc: (x, t, b, c, d) -> | |
| if (t /= d / 2) < 1 | |
| return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b | |
| c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b | |
| easeInElastic: (x, t, b, c, d) -> | |
| s = 1.70158 | |
| p = 0 | |
| a = c | |
| if t == 0 | |
| return b | |
| if (t /= d) == 1 | |
| return b + c | |
| if !p | |
| p = d * .3 | |
| if a < Math.abs(c) | |
| a = c | |
| s = p / 4 | |
| else | |
| s = p / (2 * Math.PI) * Math.asin(c / a) | |
| -(a * 2 ** (10 * (t -= 1)) * Math.sin((t * d - s) * 2 * Math.PI / p)) + b | |
| easeOutElastic: (x, t, b, c, d) -> | |
| s = 1.70158 | |
| p = 0 | |
| a = c | |
| if t == 0 | |
| return b | |
| if (t /= d) == 1 | |
| return b + c | |
| if !p | |
| p = d * .3 | |
| if a < Math.abs(c) | |
| a = c | |
| s = p / 4 | |
| else | |
| s = p / (2 * Math.PI) * Math.asin(c / a) | |
| a * 2 ** (-10 * t) * Math.sin((t * d - s) * 2 * Math.PI / p) + c + b | |
| easeInOutElastic: (x, t, b, c, d) -> | |
| s = 1.70158 | |
| p = 0 | |
| a = c | |
| if t == 0 | |
| return b | |
| if (t /= d / 2) == 2 | |
| return b + c | |
| if !p | |
| p = d * .3 * 1.5 | |
| if a < Math.abs(c) | |
| a = c | |
| s = p / 4 | |
| else | |
| s = p / (2 * Math.PI) * Math.asin(c / a) | |
| if t < 1 | |
| return -.5 * a * 2 ** (10 * (t -= 1)) * Math.sin((t * d - s) * 2 * Math.PI / p) + b | |
| a * 2 ** (-10 * (t -= 1)) * Math.sin((t * d - s) * 2 * Math.PI / p) * .5 + c + b | |
| easeInBack: (x, t, b, c, d, s) -> | |
| if s == undefined | |
| s = 1.70158 | |
| c * (t /= d) * t * ((s + 1) * t - s) + b | |
| easeOutBack: (x, t, b, c, d, s) -> | |
| if s == undefined | |
| s = 1.70158 | |
| c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b | |
| easeInOutBack: (x, t, b, c, d, s) -> | |
| if s == undefined | |
| s = 1.70158 | |
| if (t /= d / 2) < 1 | |
| return c / 2 * t * t * (((s *= 1.525) + 1) * t - s) + b | |
| c / 2 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b | |
| easeInBounce: (x, t, b, c, d) => | |
| c - @easings.easeOutBounce(x, d - t, 0, c, d) + b | |
| easeOutBounce: (x, t, b, c, d) -> | |
| if (t /= d) < 1 / 2.75 | |
| c * 7.5625 * t * t + b | |
| else if t < 2 / 2.75 | |
| c * (7.5625 * (t -= 1.5 / 2.75) * t + .75) + b | |
| else if t < 2.5 / 2.75 | |
| c * (7.5625 * (t -= 2.25 / 2.75) * t + .9375) + b | |
| else | |
| c * (7.5625 * (t -= 2.625 / 2.75) * t + .984375) + b | |
| easeInOutBounce: (x, t, b, c, d) => | |
| if t < d / 2 | |
| return @easings.easeInBounce(x, t * 2, 0, c, d) * .5 + b | |
| @easings.easeOutBounce(x, t * 2 - d, 0, c, d) * .5 + c * .5 + b |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var Animator; | |
| Animator = (function() { | |
| function Animator(obj) { | |
| this.obj = obj; | |
| this.stack = []; | |
| console.log(this); | |
| } | |
| Animator.prototype.add = function(property, to, duration, callback, easing) { | |
| return this.stack.push({ | |
| property: property, | |
| from: parseFloat(this.getProperty(this.obj, property)), | |
| to: parseFloat(to), | |
| duration: duration || 250, | |
| callback: callback, | |
| easing: easing | |
| }); | |
| }; | |
| Animator.prototype.getProperty = function(o, s) { | |
| var a, i, k, n; | |
| s = s.replace(/\[(\w+)\]/g, '.$1'); | |
| s = s.replace(/^\./, ''); | |
| a = s.split('.'); | |
| i = 0; | |
| n = a.length; | |
| while (i < n) { | |
| k = a[i]; | |
| if (o[k] != null) { | |
| o = o[k]; | |
| } else { | |
| return; | |
| } | |
| ++i; | |
| } | |
| return o; | |
| }; | |
| Animator.prototype.setProperty = function(o, s, v) { | |
| var a, i, k, n; | |
| s = s.replace(/\[(\w+)\]/g, '.$1'); | |
| s = s.replace(/^\./, ''); | |
| a = s.split('.'); | |
| i = 0; | |
| n = a.length; | |
| while (i < n - 1) { | |
| k = a[i]; | |
| if (o[k] != null) { | |
| o = o[k]; | |
| } else { | |
| return; | |
| } | |
| ++i; | |
| } | |
| return o[a[i]] = v; | |
| }; | |
| Animator.prototype.run = function(frame) { | |
| var currentTime, delta, index, j, len, ref, results, task, value; | |
| currentTime = new Date(); | |
| index = 0; | |
| ref = this.stack; | |
| results = []; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| task = ref[j]; | |
| if (task) { | |
| if (task.startTime == null) { | |
| task.startTime = currentTime; | |
| } | |
| delta = currentTime - task.startTime; | |
| if (delta > task.duration) { | |
| this.setProperty(this.obj, task.property, task.to); | |
| if (task.callback != null) { | |
| task.callback(); | |
| } | |
| this.stack.splice(index, 1); | |
| } else { | |
| if (task.easing && (Animator.easings[task.easing] != null)) { | |
| value = Animator.easings[task.easing](null, delta, task.from, task.to - task.from, task.duration); | |
| } else { | |
| value = task.from + ((task.to - task.from) / task.duration * delta); | |
| } | |
| this.setProperty(this.obj, task.property, value); | |
| } | |
| results.push(++index); | |
| } else { | |
| results.push(void 0); | |
| } | |
| } | |
| return results; | |
| }; | |
| Animator.easings = { | |
| easeInQuad: function(x, t, b, c, d) { | |
| return c * (t /= d) * t + b; | |
| }, | |
| easeOutQuad: function(x, t, b, c, d) { | |
| return -c * (t /= d) * (t - 2) + b; | |
| }, | |
| easeInOutQuad: function(x, t, b, c, d) { | |
| if ((t /= d / 2) < 1) { | |
| return c / 2 * t * t + b; | |
| } | |
| return -c / 2 * (--t * (t - 2) - 1) + b; | |
| }, | |
| easeInCubic: function(x, t, b, c, d) { | |
| return c * (t /= d) * t * t + b; | |
| }, | |
| easeOutCubic: function(x, t, b, c, d) { | |
| return c * ((t = t / d - 1) * t * t + 1) + b; | |
| }, | |
| easeInOutCubic: function(x, t, b, c, d) { | |
| if ((t /= d / 2) < 1) { | |
| return c / 2 * t * t * t + b; | |
| } | |
| return c / 2 * ((t -= 2) * t * t + 2) + b; | |
| }, | |
| easeInQuart: function(x, t, b, c, d) { | |
| return c * (t /= d) * t * t * t + b; | |
| }, | |
| easeOutQuart: function(x, t, b, c, d) { | |
| return -c * ((t = t / d - 1) * t * t * t - 1) + b; | |
| }, | |
| easeInOutQuart: function(x, t, b, c, d) { | |
| if ((t /= d / 2) < 1) { | |
| return c / 2 * t * t * t * t + b; | |
| } | |
| return -c / 2 * ((t -= 2) * t * t * t - 2) + b; | |
| }, | |
| easeInQuint: function(x, t, b, c, d) { | |
| return c * (t /= d) * t * t * t * t + b; | |
| }, | |
| easeOutQuint: function(x, t, b, c, d) { | |
| return c * ((t = t / d - 1) * t * t * t * t + 1) + b; | |
| }, | |
| easeInOutQuint: function(x, t, b, c, d) { | |
| if ((t /= d / 2) < 1) { | |
| return c / 2 * t * t * t * t * t + b; | |
| } | |
| return c / 2 * ((t -= 2) * t * t * t * t + 2) + b; | |
| }, | |
| easeInSine: function(x, t, b, c, d) { | |
| return -c * Math.cos(t / d * Math.PI / 2) + c + b; | |
| }, | |
| easeOutSine: function(x, t, b, c, d) { | |
| return c * Math.sin(t / d * Math.PI / 2) + b; | |
| }, | |
| easeInOutSine: function(x, t, b, c, d) { | |
| return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b; | |
| }, | |
| easeInExpo: function(x, t, b, c, d) { | |
| if (t === 0) { | |
| return b; | |
| } else { | |
| return c * Math.pow(2, 10 * (t / d - 1)) + b; | |
| } | |
| }, | |
| easeOutExpo: function(x, t, b, c, d) { | |
| if (t === d) { | |
| return b + c; | |
| } else { | |
| return c * (-(Math.pow(2, -10 * t / d)) + 1) + b; | |
| } | |
| }, | |
| easeInOutExpo: function(x, t, b, c, d) { | |
| if (t === 0) { | |
| return b; | |
| } | |
| if (t === d) { | |
| return b + c; | |
| } | |
| if ((t /= d / 2) < 1) { | |
| return c / 2 * Math.pow(2, 10 * (t - 1)) + b; | |
| } | |
| return c / 2 * (-(Math.pow(2, -10 * --t)) + 2) + b; | |
| }, | |
| easeInCirc: function(x, t, b, c, d) { | |
| return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b; | |
| }, | |
| easeOutCirc: function(x, t, b, c, d) { | |
| return c * Math.sqrt(1 - (t = t / d - 1) * t) + b; | |
| }, | |
| easeInOutCirc: function(x, t, b, c, d) { | |
| if ((t /= d / 2) < 1) { | |
| return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b; | |
| } | |
| return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b; | |
| }, | |
| easeInElastic: function(x, t, b, c, d) { | |
| var a, p, s; | |
| s = 1.70158; | |
| p = 0; | |
| a = c; | |
| if (t === 0) { | |
| return b; | |
| } | |
| if ((t /= d) === 1) { | |
| return b + c; | |
| } | |
| if (!p) { | |
| p = d * .3; | |
| } | |
| if (a < Math.abs(c)) { | |
| a = c; | |
| s = p / 4; | |
| } else { | |
| s = p / (2 * Math.PI) * Math.asin(c / a); | |
| } | |
| return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * 2 * Math.PI / p)) + b; | |
| }, | |
| easeOutElastic: function(x, t, b, c, d) { | |
| var a, p, s; | |
| s = 1.70158; | |
| p = 0; | |
| a = c; | |
| if (t === 0) { | |
| return b; | |
| } | |
| if ((t /= d) === 1) { | |
| return b + c; | |
| } | |
| if (!p) { | |
| p = d * .3; | |
| } | |
| if (a < Math.abs(c)) { | |
| a = c; | |
| s = p / 4; | |
| } else { | |
| s = p / (2 * Math.PI) * Math.asin(c / a); | |
| } | |
| return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * 2 * Math.PI / p) + c + b; | |
| }, | |
| easeInOutElastic: function(x, t, b, c, d) { | |
| var a, p, s; | |
| s = 1.70158; | |
| p = 0; | |
| a = c; | |
| if (t === 0) { | |
| return b; | |
| } | |
| if ((t /= d / 2) === 2) { | |
| return b + c; | |
| } | |
| if (!p) { | |
| p = d * .3 * 1.5; | |
| } | |
| if (a < Math.abs(c)) { | |
| a = c; | |
| s = p / 4; | |
| } else { | |
| s = p / (2 * Math.PI) * Math.asin(c / a); | |
| } | |
| if (t < 1) { | |
| return -.5 * a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * 2 * Math.PI / p) + b; | |
| } | |
| return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * 2 * Math.PI / p) * .5 + c + b; | |
| }, | |
| easeInBack: function(x, t, b, c, d, s) { | |
| if (s === void 0) { | |
| s = 1.70158; | |
| } | |
| return c * (t /= d) * t * ((s + 1) * t - s) + b; | |
| }, | |
| easeOutBack: function(x, t, b, c, d, s) { | |
| if (s === void 0) { | |
| s = 1.70158; | |
| } | |
| return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; | |
| }, | |
| easeInOutBack: function(x, t, b, c, d, s) { | |
| if (s === void 0) { | |
| s = 1.70158; | |
| } | |
| if ((t /= d / 2) < 1) { | |
| return c / 2 * t * t * (((s *= 1.525) + 1) * t - s) + b; | |
| } | |
| return c / 2 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b; | |
| }, | |
| easeInBounce: function(x, t, b, c, d) { | |
| return c - Animator.easings.easeOutBounce(x, d - t, 0, c, d) + b; | |
| }, | |
| easeOutBounce: function(x, t, b, c, d) { | |
| if ((t /= d) < 1 / 2.75) { | |
| return c * 7.5625 * t * t + b; | |
| } else if (t < 2 / 2.75) { | |
| return c * (7.5625 * (t -= 1.5 / 2.75) * t + .75) + b; | |
| } else if (t < 2.5 / 2.75) { | |
| return c * (7.5625 * (t -= 2.25 / 2.75) * t + .9375) + b; | |
| } else { | |
| return c * (7.5625 * (t -= 2.625 / 2.75) * t + .984375) + b; | |
| } | |
| }, | |
| easeInOutBounce: function(x, t, b, c, d) { | |
| if (t < d / 2) { | |
| return Animator.easings.easeInBounce(x, t * 2, 0, c, d) * .5 + b; | |
| } | |
| return Animator.easings.easeOutBounce(x, t * 2 - d, 0, c, d) * .5 + c * .5 + b; | |
| } | |
| }; | |
| return Animator; | |
| })(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class SomeClass | |
| constructor: (@paperjs_project)-> | |
| @ring = new @paperjs_project.Path.Circle | |
| center: [200, 200] | |
| radius: 100 | |
| @ringAnimator = new Animator @ring | |
| @paperjs_project.view.on 'frame', (e)=> @ringAnimator.run(e) | |
| @animator.add 'center._x', 400, 250, (-> console.log('center._x ready')), 'easeOutCubic' | |
| @animator.add 'center._y', 400, 250, (-> console.log('center._y ready')), 'easeOutBounce' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment