From 622041aeafb9b5bfe4108b89e9f6c156c4f55ec8 Mon Sep 17 00:00:00 2001 From: Eric Rowell Date: Fri, 10 May 2013 22:10:05 -0700 Subject: [PATCH] added Tween class which replaces the old Transition class --- Thorfile | 2 +- src/Animation.js | 11 +- src/Tween.js | 387 ++++++++++++++++++++++++++++++++++++++++ tests/js/manualTests.js | 23 ++- 4 files changed, 410 insertions(+), 13 deletions(-) create mode 100644 src/Tween.js diff --git a/Thorfile b/Thorfile index 9cd9d073..84eaefb8 100644 --- a/Thorfile +++ b/Thorfile @@ -5,7 +5,7 @@ class Build < Thor # This is the list of files to concatenate. The first file will appear at the top of the final file. All files are relative to the lib directory. FILES = [ "src/Global.js", "src/Util.js", "src/Canvas.js", - "src/Node.js", "src/Animation.js", "src/DragAndDrop.js", "src/Container.js", "src/Shape.js", "src/Stage.js", "src/Layer.js", "src/Group.js", + "src/Node.js", "src/Animation.js", "src/Tween.js", "src/DragAndDrop.js", "src/Container.js", "src/Shape.js", "src/Stage.js", "src/Layer.js", "src/Group.js", "src/shapes/Rect.js", "src/shapes/Circle.js", "src/shapes/Wedge.js", "src/shapes/Ellipse.js", "src/shapes/Image.js", "src/shapes/Polygon.js", "src/shapes/Text.js", "src/shapes/Line.js", "src/shapes/Spline.js", "src/shapes/Blob.js", "src/shapes/Sprite.js", "src/plugins/Path.js", "src/plugins/TextPath.js", "src/plugins/RegularPolygon.js", "src/plugins/Star.js", "src/plugins/Label.js", "src/filters/Grayscale.js", "src/filters/Brighten.js", "src/filters/Invert.js", "src/filters/Blur.js", "src/filters/Mask.js" diff --git a/src/Animation.js b/src/Animation.js index 0e33e3bf..109f955d 100644 --- a/src/Animation.js +++ b/src/Animation.js @@ -126,8 +126,12 @@ this._handleAnimation(); }; Kinetic.Animation._removeAnimation = function(anim) { - var id = anim.id, animations = this.animations, len = animations.length; - for(var n = 0; n < len; n++) { + var id = anim.id, + animations = this.animations, + len = animations.length, + n; + + for(n = 0; n < len; n++) { if(animations[n].id === id) { this.animations.splice(n, 1); break; @@ -138,7 +142,6 @@ Kinetic.Animation._runFrames = function() { var layerHash = {}, animations = this.animations, - len = animations.length, anim, layers, func, n, i, layersLen, layer, key; /* * loop through all animations and execute animation @@ -151,7 +154,7 @@ * WARNING: don't cache animations.length because it could change while * the for loop is running, causing a JS error */ - for(n = 0; n < len; n++) { + for(n = 0; n < animations.length; n++) { anim = animations[n]; layers = anim.layers; func = anim.func; diff --git a/src/Tween.js b/src/Tween.js new file mode 100644 index 00000000..adbb705d --- /dev/null +++ b/src/Tween.js @@ -0,0 +1,387 @@ +(function() { + var blacklist = { + node: 1, + duration: 1, + ease: 1, + onFinished: 1, + yoyo: 1 + }, + + PAUSED = 1, + PLAYING = 2, + REVERSING = 3; + + function createTween(node, key, ease, end, duration, yoyo) { + return new Tween(function(i) { + node['set' + Kinetic.Util._capitalize(key)](i); + }, ease, node['get' + Kinetic.Util._capitalize(key)](), end, duration * 1000, yoyo); + } + + Kinetic.Tween = function(config) { + var that = this, + node = config.node, + duration = config.duration || 1, + ease = config.ease || Kinetic.Ease.Linear, + yoyo = !!config.yoyo, + key, tween; + + this.tweens = []; + + for (key in config) { + if (blacklist[key] === undefined) { + this.tweens.push(createTween(node, key, ease, config[key], duration, yoyo)); + } + } + + this.anim = new Kinetic.Animation(function() { + that.onEnterFrame(); + }, node.getLayer()); + + this._listenToLastTween(); + this.reset(); + }; + + Kinetic.Tween.prototype = { + _getLastTween: function() { + var that = this, + tweens = this.tweens, + lastIndex = this.tweens.length - 1; + return lastTween = tweens[lastIndex]; + + }, + _listenToLastTween: function() { + var that = this, + tweens = this.tweens, + lastIndex = this.tweens.length - 1, + lastTween = tweens[lastIndex], + anim = this.anim; + + this._getLastTween().onPause = function() { + anim.stop(); + } + }, + _run: function(method, param) { + var tweens = this.tweens, + len = tweens.length, + n; + + for (n=0; n this.duration) { + if(this.yoyo) { + this._time = this.duration; + this.reverse(); + } + else { + this.finish(); + } + } + else if(t < 0) { + if(this.yoyo) { + this._time = 0; + this.play(); + } + else { + this.reset(); + } + } + else { + this._time = t; + this.update(); + } + }, + getTime: function() { + return this._time; + }, + setPosition: function(p) { + this.prevPos = this._pos; + this.propFunc(p); + this._pos = p; + this.broadcastMessage('onChange', { + target: this, + type: 'onChange' + }); + }, + getPosition: function(t) { + if(t === undefined) { + t = this._time; + } + return this.func(t, this.begin, this._change, this.duration); + }, + play: function() { + this.state = PLAYING; + this._startTime = this.getTimer() - this._time; + this.onEnterFrame(); + this.broadcastMessage('onPlay', { + target: this, + type: 'onPlay' + }); + }, + reverse: function() { + this.state = REVERSING; + this._time = this.duration - this._time; + this._startTime = this.getTimer() - this._time; + this.onEnterFrame(); + this.broadcastMessage('onReverse', { + target: this, + type: 'onReverse' + }); + }, + goto: function(t) { + this._time = t; + this.update(); + }, + reset: function() { + this.pause(); + this._time = 0; + this.update(); + }, + finish: function() { + this.pause(); + this._time = this.duration; + this.update(); + }, + update: function() { + this.setPosition(this.getPosition(this._time)); + }, + onEnterFrame: function() { + var t = this.getTimer() - this._startTime; + if(this.state === PLAYING) { + this.setTime(t); + } + else if (this.state === REVERSING) { + this.setTime(this.duration - t); + } + }, + pause: function() { + this.state = PAUSED; + this.broadcastMessage('onPause', { + target: this, + type: 'onPause' + }); + }, + addListener: function(o) { + this.removeListener(o); + return this._listeners.push(o); + }, + removeListener: function(o) { + var a = this._listeners, + i = a.length; + while(i--) { + if(a[i] === o) { + a.splice(i, 1); + return true; + } + } + return false; + }, + broadcastMessage: function() { + var arr = [], + len = arguments.length, + i, e, a, l; + + for(i = 0; i < len; i++) { + arr.push(arguments[i]); + } + e = arr.shift(); + a = this._listeners; + l = a.length; + for(i = 0; i < l; i++) { + if(a[i][e]) { + a[i][e].apply(a[i], arr); + } + } + }, + getTimer: function() { + return new Date().getTime(); + } + }; + + /* + * These easings were ported from an Adobe Flash tweening library to JavaScript + * by Xaric + */ + Kinetic.Ease = { + 'BackEaseIn': function(t, b, c, d, a, p) { + var s = 1.70158; + return c * (t /= d) * t * ((s + 1) * t - s) + b; + }, + 'BackEaseOut': function(t, b, c, d, a, p) { + var s = 1.70158; + return c * (( t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; + }, + 'BackEaseInOut': function(t, b, c, d, a, p) { + var 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; + }, + 'ElasticEaseIn': function(t, b, c, d, a, p) { + // added s = 0 + var s = 0; + if(t === 0) { + return b; + } + if((t /= d) == 1) { + return b + c; + } + if(!p) { + p = d * 0.3; + } + if(!a || 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; + }, + 'ElasticEaseOut': function(t, b, c, d, a, p) { + // added s = 0 + var s = 0; + if(t === 0) { + return b; + } + if((t /= d) == 1) { + return b + c; + } + if(!p) { + p = d * 0.3; + } + if(!a || 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); + }, + 'ElasticEaseInOut': function(t, b, c, d, a, p) { + // added s = 0 + var s = 0; + if(t === 0) { + return b; + } + if((t /= d / 2) == 2) { + return b + c; + } + if(!p) { + p = d * (0.3 * 1.5); + } + if(!a || a < Math.abs(c)) { + a = c; + s = p / 4; + } + else { + s = p / (2 * Math.PI) * Math.asin(c / a); + } + if(t < 1) { + return -0.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) * 0.5 + c + b; + }, + 'BounceEaseOut': function(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 + 0.75) + b; + } + else if(t < (2.5 / 2.75)) { + return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b; + } + else { + return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b; + } + }, + 'BounceEaseIn': function(t, b, c, d) { + return c - Kinetic.Ease['bounce-ease-out'](d - t, 0, c, d) + b; + }, + 'BounceEaseInOut': function(t, b, c, d) { + if(t < d / 2) { + return Kinetic.Ease['bounce-ease-in'](t * 2, 0, c, d) * 0.5 + b; + } + else { + return Kinetic.Ease['bounce-ease-out'](t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b; + } + }, + 'EaseIn': function(t, b, c, d) { + return c * (t /= d) * t + b; + }, + 'EaseOut': function(t, b, c, d) { + return -c * (t /= d) * (t - 2) + b; + }, + 'EaseInOut': function(t, b, c, d) { + if((t /= d / 2) < 1) { + return c / 2 * t * t + b; + } + return -c / 2 * ((--t) * (t - 2) - 1) + b; + }, + 'StrongEaseIn': function(t, b, c, d) { + return c * (t /= d) * t * t * t * t + b; + }, + 'StrongEaseOut': function(t, b, c, d) { + return c * (( t = t / d - 1) * t * t * t * t + 1) + b; + }, + 'StrongEaseIn': function(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; + }, + 'Linear': function(t, b, c, d) { + return c * t / d + b; + } + }; +})(); \ No newline at end of file diff --git a/tests/js/manualTests.js b/tests/js/manualTests.js index 3f027511..7a6cc217 100644 --- a/tests/js/manualTests.js +++ b/tests/js/manualTests.js @@ -194,14 +194,21 @@ Test.Modules.TRANSITION = { layer.add(greenBox); stage.add(layer); - TweenLite.to(greenBox, 2, { - setX: 200, - setScaleX: 2, - setScaleY: 2, - ease: Linear.easeNone, - onUpdate: function() { - layer.batchDraw(); - } + var tween = new Kinetic.Tween({ + node: greenBox, + duration: 2, + x: 400, + scaleX: 2, + scaleY: 2, + ease: Kinetic.Ease.BounceEaseOut, + yoyo: false + }); + + tween.play(); + + document.getElementById(containerId).addEventListener('click', function() { + tween.goto(1.5); + tween.reverse(); }); } };