/* * tweener.js */ (function() { /** * @class tm.app.Tweener * トゥイーナークラス * @extends tm.event.EventDispatcher */ tm.define("tm.app.Tweener", { superClass: "tm.app.Element", /** * @constructor * @param {Object} elm */ init: function(elm) { this.superInit(); this.setTarget(elm || {}); this.loop = false; this._init(); }, /** * 初期化 */ _init: function() { this._index = 0; this._tasks = []; this._func = this._updateTask; this.isPlaying = true; }, /** * ターゲットのセット * @param {Object} target */ setTarget: function(target) { this.element = target; return this; }, /** * 更新 * @param {Object} app */ update: function(app) { this._func(app); return ; var tweens = this.tweens.clone(); for (var i=0,len=tweens.length; i<len; ++i) { var tween = tweens[i]; // 待ちチェック if (tween.delay > 0) { tween.delay -= 1000/app.fps; continue; } var time = tween.time + 1000/app.fps; tween._setTime(time); if (tween.time >= tween.duration) { // 削除 this.tweens.erase(tween); // 全てのアニメーション終了チェック if (this.tweens.length <= 0) { this.isAnimation = false; var e = tm.event.Event("finish"); this.element.fire(e); this.dispatchEvent(e); } } else { tween.update(); } } }, /** * タスクの更新 * @private * @param {Object} app */ _updateTask: function(app) { if (!this.isPlaying) return ; var task = this._tasks[this._index]; if (!task) { if (this.loop === true) { this._index = 0; } else { this.isPlaying = false; } return ; } this._index++; if (task.type == "tween") { var data = task.data; var fnStr= task.data.type; var args = task.data.args; this._tween = tm.anim.Tween(); this._tween[fnStr].apply(this._tween, args); this._func = this._updateTween; this._func(app); } else if (task.type == "wait") { this._wait = task.data; this._wait.time = 0; this._func = this._updateWait; this._func(app); } else if (task.type == "call") { task.data.func.apply(task.data.self, task.data.args); // 1フレーム消費しないよう再帰 this._updateTask(app); } else if (task.type == "set") { this.element.$extend(task.data.values); // 1フレーム消費しないよう再帰 this._updateTask(app); } }, /** * Tween の更新 * @private * @param {Object} elm */ _updateTween: function(app) { var tween = this._tween; var time = tween.time + 1000/app.fps; tween._setTime(time); if (tween.time >= tween.duration) { // 削除 delete this._tween; this._tween = null; this._func = this._updateTask; } else { tween.update(); } }, /** * 時間の更新 * @private * @param {Object} elm */ _updateWait: function(app) { var wait = this._wait; wait.time += 1000/app.fps; if (wait.time >= wait.limit) { delete this._wait; this._wait = null; this._func = this._updateTask; } }, /** * 追加 * @param {Object} param */ add: function(param) { if (!param.target) param.target = this.element; this._tasks.push({ type: "tween", data: param }); if (this.isAnimation == false) { this.isAnimation = true; var e = tm.event.Event("animationstart"); this.element.dispatchEvent(e); } return this; }, /** * 指定した値を足した値までアニメーション * @param {Object} props * @param {Object} duration * @param {Function} fn */ by: function(props, duration, fn) { this._addTweenTask({ props: props, duration: duration, fn: fn, type: "by" }); return this; }, /** * 指定した値までアニメーション * @param {Object} props * @param {Object} duration * @param {Function} fn */ to: function(props, duration, fn) { this._addTweenTask({ props: props, duration: duration, fn: fn, type: "to" }); return this; }, from: function(props, duration, fn) { this._addTweenTask({ props: props, duration: duration, fn: fn, type: "from" }); return this; }, /** * 移動アニメーション * @param {Number} x * @param {Number} y * @param {Object} duration * @param {Function} fn */ move: function(x, y, duration, fn) { return this.to({x:x, y:y}, duration, fn); }, /** * 指定した値を足した座標までアニメーション * @param {Number} x * @param {Number} y * @param {Object} duration * @param {Function} fn */ moveBy: function(x, y, duration, fn) { return this.by({x:x, y:y}, duration, fn); }, /** * 回転アニメーション * @param {Number} rotation * @param {Object} duration * @param {Function} fn */ rotate: function(rotation, duration, fn) { return this.to({rotation:rotation}, duration, fn); }, /** * 拡縮アニメーション * @param {Number} scale * @param {Object} duration * @param {Function} fn */ scale: function(scale, duration, fn) { return this.to({scaleX:scale, scaleY:scale}, duration, fn); }, /** * フェードアニメーション * @param {Object} value * @param {Object} duration */ fade: function(value, duration) { this.to({"alpha":value}, duration); return this; }, /** * フェードイン * @param {Object} duration */ fadeIn: function(duration) { this.fade(1.0, duration); return this; }, /** * フェードアウト * @param {Object} duration */ fadeOut: function(duration) { this.fade(0.0, duration); return this; }, /** * Tween のタスクを追加 * @private * @param {Object} param */ _addTweenTask: function(param) { param.target = (param.target !== undefined) ? param.target : this.element; param.duration = (param.duration !== undefined) ? param.duration : 1000; this._tasks.push({ type: "tween", data: { args: [param.target, param.props, param.duration, param.fn], type: param.type } }); if (this.isAnimation == false) { this.isAnimation = true; var e = tm.event.Event("animationstart"); this.element.dispatchEvent(e); } return this; }, /** * 待ち時間 * @param {Object} time */ wait: function(time) { this._tasks.push({ type: "wait", data: { limit: time } }); return this; }, /** * コールバックを登録 * @param {Function} fn * @param {Object} args */ call: function(fn, self, args) { this._tasks.push({ type: "call", data: { func: fn, self: self || this, args: args, }, }); return this; }, /** * プロパティをセット * @param {Object} key * @param {Object} value */ set: function(key, value) { var values = null; if (arguments.length == 2) { values = {}; values[key] = value; } else { values = key; } this._tasks.push({ type: "set", data: { values: values } }); return this; }, /** * アニメーション開始 */ play: function() { this.isPlaying = true; return this; }, /** * アニメーションを一時停止 */ pause: function() { this.isPlaying = false; return this; }, /** * アニメーションを巻き戻す */ rewind: function() { this._func = this._updateTask; this._index = 0; this.play(); return this; }, /** * アニメーションループ設定 * @param {Boolean} flag */ setLoop: function(flag) { this.loop = flag; return this; }, /** * アニメーションをクリア */ clear: function() { this._init(); return this; } }); /** * @member tm.app.Element * @property tweener * トゥイーンアニメーション */ tm.app.Element.prototype.getter("tweener", function() { if (!this._tweener) { this._tweener = tm.app.Tweener(this); this.on("enterframe", function(e) { this._tweener.update(e.app); }); } return this._tweener; }); })();