/* * timeline.js */ tm.namespace("tm.app", function() { /** * @class tm.app.Timeline * タイムラインクラス * @extends tm.event.EventDispatcher */ tm.define("tm.app.Timeline", { superClass: "tm.app.Element", /** * @constructor * @param {Object} elm */ init: function(elm) { this.superInit(); this.setTarget(elm || {}); this.currentFrame = 0; this.currentTime = 0; this.prevTime = 0; this.duration = 0; this.isPlay = true; this._tweens = []; this._actions = []; }, /** * 更新 * @param {Object} app */ update: function(app) { if (!this.isPlay) return ; if (this.prevTime <= this.duration) { this._updateTween(); this._updateAction(); } this.currentFrame++; this.prevTime = this.currentTime; this.currentTime = ((this.currentFrame/app.fps)*1000)|0; }, /** * トゥイーンを更新 * @private */ _updateTween: function() { var tweens = this._tweens; for (var i=0,len=tweens.length; i<len; ++i) { var tween = tweens[i]; if (tween.delay > this.currentTime) { continue ; } var time = this.currentTime - tween.delay; tween._setTime(time); if (tween.time >= tween.duration) { } else { tween.update(); } } }, /** * アクションを更新 * @private */ _updateAction: function() { var actions = this._actions; for (var i=0,len=actions.length; i<len; ++i) { var action = actions[i]; if (this.prevTime <= action.delay && action.delay < this.currentTime) { if (action.type == "call") { action.func.call(action.self); // action.func(); } else if (action.type == "set") { var props = action.props; for (var key in props) { this.element[key] = props[key]; } } } } }, /** * 指定した値までアニメーション * @param {Object} delay * @param {Object} props * @param {Object} duration * @param {Function} func */ to: function(delay, props, duration, fn) { console.assert(typeof delay == "number", "to の第一引数はdelayに変わりました"); this._addTween({ props: props, duration: duration, fn: fn, delay: delay }); return this; }, /** * 指定した値を足した値までアニメーション * @param {Object} delay * @param {Object} props * @param {Object} duration * @param {Function} func */ by: function(delay, props, duration, fn) { console.assert(typeof delay == "number", "by の第一引数はdelayに変わりました"); for (var key in props) { props[key] += this.element[key] || 0; } this._addTween({ props: props, duration: duration, fn: fn, delay: delay }); return this; }, /** * 関数を実行 * @param {Object} delay * @param {Function} func */ call: function(delay, func, self) { console.assert(typeof delay == "number", "call の第一引数はdelayに変わりました"); this._addAction({ "type": "call", func: func, self: self || this, delay: delay, }); return this; }, /** * プロパティをセット * @param {Object} delay * @param {Object} props */ set: function(delay, props) { console.assert(typeof delay == "number", "set の第一引数はdelayに変わりました"); this._addAction({ "type": "set", props: props, delay: delay, }); return this; }, /** * ターゲットのセット * @param {Object} target */ setTarget: function(target) { this.element = target; return this; }, /** * ターゲットをゲット */ getTarget: function() { return this.element; }, /** * アニメーション開始 * アニメーションが終了したら再度アニメーションを行う * @param {Number} frame */ gotoAndPlay: function(frame) { this.isPlay = true; this.currentFrame = frame; this._updateTween(); }, /** * アニメーション開始 * アニメーションが終了したらストップする * @param {Number} frame */ gotoAndStop: function(frame) { this.currentFrame = frame; this.isPlay = false; this._updateTween(); }, /** * tween を追加 * @private * @param {Object} tween */ _addTween: function(tween) { tween.duration = tween.duration || 1000; tween.duration = this._dirty(tween.duration); tween.delay = tween.delay || 0; tween.delay = this._dirty(tween.delay); var tweenObj = tm.anim.Tween(); tweenObj.to(this.element, tween.props, tween.duration, tween.fn); tweenObj.delay = tween.delay; this._tweens.push(tweenObj); this._updateDuration(tweenObj); }, /** * アニメーションを追加 * @private * @param {Object} action */ _addAction: function(action) { action.delay = action.delay || 0; action.delay = this._dirty(action.delay); this._actions.push(action); this._updateDuration(action); }, /** * 時間を更新 * @private * @param {Object} task */ _updateDuration: function(task) { var duration = task.delay + (task.duration ? task.duration : 0); if (this.duration < duration) this.duration = duration; return this; }, /** * dirty method * @private * @param {Object} t */ _dirty: function(t) { return t; // return (t/this.fps).toInt(); }, /** * ロード * @param {Object} data */ load: function(data) { for (var key in data.timeline) { var value = data.timeline[key]; } return this; }, /** * アニメーションをクリア */ clear: function() { this.currentFrame = 0; this.prevTime = 0; this.currentTime = 0; this.duration = 0; this.isPlay = true; this._tweens = []; this._actions = []; return this; } }); /** * @member tm.app.Element * @property timeline * タイムラインアニメーション */ tm.app.Element.prototype.getter("timeline", function() { if (!this._timeline) { this._timeline = tm.app.Timeline(this); this.on("enterframe", function(e) { this._timeline.update(e.app); }); } return this._timeline; }); });