Hatena::Groupsubtech

#生存戦略 、それは

-> 09 { 04 / 08 }

JavaScript での easing 関数を使ったトィーンアニメーションの基礎

15:31 | はてなブックマーク - JavaScript での easing 関数を使ったトィーンアニメーションの基礎  - #生存戦略 、それは

エントリーを読んで、JS で特定時間の間隔でモーション・アニメーションしたい場合の easing 関数の基礎の話をちょっと。Flash などの Web のアニメーションでは、Penner さんが考えた easing 関数が広く使われていて、解説や実装が公開されている。

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 を挟みたい処理の場合、クライアントの処理速度にあわせたいけど、そういう指針となる物ないのかなぁ、と思っていた物で

piro_orpiro_or2009/04/08 18:24負荷というのはプロファイリングとかの話でしょうか。
だとしたら、Venkman JavaScript Debuggerにプロファイラ機能がついてますよー

secondlifesecondlife2009/04/08 18:32やや、piro たんのエントリーのように、リアルタイムでの性能(クライアントマシンにあわせて、処理の wait を変えたい、Firefox 以外のプロセスが CPU 使ってて割り込みがあまりできない等)にあわせて挙動変えたいときに、どうすればいいのかなぁ、と。

piro_orpiro_or2009/04/08 19:14なるほど。アイドリング中(ユーザがぼけっとしてる)かどうかを知るAPIならあるんですけどねぇ……
https://developer.mozilla.org/ja/nsIIdleService

secondlifesecondlife2009/04/08 21:30おおお、こんな API が!
知りませんでした、ありがとうございます。

tsukkeetsukkee2009/04/10 03:11easing関数の引数(t, b, c, d)のcは最後の値じゃなくて変位でしょうか?参照先のPDFもtime, begin, change, durationとなってますし.

secondlifesecondlife2009/04/10 09:27oh, そうです、コメントありがとうございます。
最後の値だと全然意味と挙動が違ってしまいますね…。

ku0522ku05222009/04/14 09:07extension前提ならC++でCPU使用率取るXPCOM書くっていう手もありますよ。

secondlifesecondlife2009/04/14 09:50そうなんですよねー。
C++…未知の言語…。

トラックバック - http://subtech.g.hatena.ne.jp/secondlife/20090408