-> 09 { 04 / 08 }
JavaScript での easing 関数を使ったトィーンアニメーションの基礎
のエントリーを読んで、JS で特定時間の間隔でモーション・アニメーションしたい場合の easing 関数の基礎の話をちょっと。Flash などの Web のアニメーションでは、Penner さんが考えた easing 関数が広く使われていて、解説や実装が公開されている。
- http://www.robertpenner.com/easing/
- http://www.robertpenner.com/easing/penner_chapter7_tweening.pdf
- 解説。この PDF は読んでおかないともったい無い
easing 関数はざっくりというと
- 動き始めてから何秒たったか
- 最初の値
- 変動する値
- 完了までの秒数
を引数として与えれば、その時間に応じた値を返してくれる、という関数。追記・c は最後の値ではなく変動値でした。すいません…。tsukkeeさんありがとうございますコードに落とすとこんな感じ
// 0 =< t =< d のとき
function(t, b, c, d) {};
t = 現在秒 (現在
b = 最初の値
c = 変動する値
d = 何秒かけて動くか
で、例えば直線的な動きは
function(t, b, c, d) {
return c * t / d + b;
}
な関数で表現できる。これのパターン関数がたくさんあり、自前で実装することもできるし、penner さんが作った関数を元に利用するのも良いし、誰かが公開しているのを利用するのも良い。
この easing 関数を利用するためのコードだけど、理解してればすぐスクラッチで書ける。
var easing = function(t, b, c, d) {
return c * t / d + b;
};
var now = ((new Date()) * 1);
var b = 0; // 最初の値
var c = 100; // 変動する値
var d = 3; // 何秒かけてアニメーションするか
var wait = 100;
var motion = (function() {
var t = (((new Date()) * 1) - now) / 1000;
var value = easing(t, b, c, d);
document.body.style.fontSize = '' + Math.round(value) + 'px';
if (value < c) return setTimeout(arguments.callee, wait);
})();
ブックマークレット化したのが以下。google の検索結果などのページで実行すると効果が解ると思う。
javascript:(function(){var%20easing=function(t,b,c,d){return%20c*t/d+b;};var%20now=((new%20Date())*1);var%20b=0;var%20c=100;var%20d=3;var%20wait=100;var%20motion=(function(){var%20t=(((new%20Date())*1)-now)/1000;var%20value=easing(t,b,c,d);document.body.style.fontSize=''+Math.round(value)+'px';if(value<c)return%20setTimeout(arguments.callee,wait);})();})();
で、この easing 関数を差し替えると、モーションに変化を与えることができる
// OutBounce
var easing = 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 + .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;
}
};
この easing 関数で作ったブックマークレットが以下。IE だと文字数的に動かないかも。
javascript:(function(){var%20easing=function(t,b,c,d){if((t/=d)<(1/2.75)){return%20c*(7.5625*t*t)+b;}else%20if(t<(2/2.75)){return%20c*(7.5625*(t-=(1.5/2.75))*t+.75)+b;}else%20if(t<(2.5/2.75)){return%20c*(7.5625*(t-=(2.25/2.75))*t+.9375)+b;}else{return%20c*(7.5625*(t-=(2.625/2.75))*t+.984375)+b;}};var%20now=((new%20Date())*1);var%20b=0;var%20c=100;var%20d=3;var%20wait=100;var%20motion=(function(){var%20t=(((new%20Date())*1)-now)/1000;var%20value=easing(t,b,c,d);document.body.style.fontSize=''+Math.round(value)+'px';if(value<c)return%20setTimeout(arguments.callee,wait);})();})();
easing 関数を差し替えられるコードにしておくと、様々な easing 関数を利用できたり、広く知られている easing 関数を使うため汎用性が増す。
で、JS でこの easing 関数を使ったライブラリとしては os0x さん作の
を使うと、20行程度のコードですむので、自分の作っている物に組み込むのには便利。また JSTweener という Tweener (as3 のモーショントィーンライブラリ) 互換のライブラリを使うと、標準で様々な easing 関数が利用できたり、タイマーが一つなので、数百, 数千オブジェクトをモーションさせるときにはだいぶ高速になる。
また JSTweener のコードには、Tweener から JavaScript へと移植した easing 関数が含まれているので、コピペ利用に便利。
そうだ最初は piro たんのエントリー読んで、xpcom の API で、どれだけ負荷がかかっているか調べられる API ってないのかなー、と思ってエントリー書いたつもりがなぜか easing 関数の話になってしまったのでした…。Firefox 拡張で wait を挟みたい処理の場合、クライアントの処理速度にあわせたいけど、そういう指針となる物ないのかなぁ、と思っていた物で
だとしたら、Venkman JavaScript Debuggerにプロファイラ機能がついてますよー
https://developer.mozilla.org/ja/nsIIdleService
知りませんでした、ありがとうございます。
最後の値だと全然意味と挙動が違ってしまいますね…。
C++…未知の言語…。