JavaScript
jQuery

物理的な減衰をするイージング関数とeaseOutExpo

More than 1 year has passed since last update.

減衰を表すために使う式について

減衰をする数式について勉強したのでメモします。
減衰のモデルは放射性物質が崩壊する時のモデルを使ってみます。
下記のような式で表され、$N$ は残りの量で $t$ が時間、$-λ$が減衰率です

 \frac{dN}{dt} = -λN 

あとの計算のため右辺から$N$を消去します。

 \frac{1}{N}\frac{dN}{dt} = -λ

これの両辺を$t$(時間)で積分します。

 \int\frac{1}{N}\frac{dN}{dt}\,dt = -\intλ\,dt

左辺を整理。

 \int\frac{1}{N}\,dN = -\intλ\,dt

$\int\frac{1}{x}\,dx = \log |x| + C$ なので

 \log N = -λt + C
 N = e^{-λt+C}

時間($t$)が0秒で、残り量の初期値が$N_0$とすると

 N_0 = e^C

なので

 N(t) = N_0e^{-λt} \tag{1}

という式が出来上がります。

イージングにこの式を使うことを考える

10秒かけて0まで減衰する場合を考えます。

この式は$t$が増加すると限りなく0に近づいていきますが0にはならないので終了は0でなく0.0001まで減衰したら終了というにことします。
$(1)$の式から

 N(10) = N_0e^{-10\lambda}

$N(10)$は初期値$N_0$の1/10000であれば良いので、下記のような式になります。

 \frac{N_0}{10000} = N_0e^{-10\lambda}

両辺の$\log$をとります

 \log N_0 - \log 10000 = \log N_0 + \log e^{-10\lambda}
 - \log 10000 = -10\lambda
 \log 10000 = 10\lambda

$\lambda = $ の式にすると

 \lambda = \frac{1}{10} \log 10000

と減衰率を出すことができました。
コードに落とす場合、アニメーションの開始時の値と終了時の値の差が初期値$N_0$で、アニメーションの時間が$t$になります。
次は実際にコードに落としてみたいと思います。

jQuery.animateのイージングを作ってみる

実際にイージング関数をつくってみます。jQueryのイージング関数は、与えられた引数から開始地点を0、終了地点を1とした場合、今どの辺りにいるかを計算してreturnする仕組みになっています。なので$e^{-\lambda t}$を計算して1から引いた値を返せばOKです。

var ln10000 = Math.log(10000);

jQuery.extend( jQuery.easing, {
  //x: 時間の進捗具合
  //t: 経過時間
  //b: 0固定
  //c: 1固定
  //d: optionで指定したアニメーション時間
  easeCustom: function(x, t, b, c, d) {
    var e = Math.E; //e
    var l = (1/d) * ln10000 //λ
    var p = Math.pow(e, (-l*t)); //e^-λt

    return (t!=d) ? 1 - p : c;
  }
});

そして実際に動かしてをeaseOutExpoと比較したものがこちらです。
http://codepen.io/bukurocci/pen/mVzeWP

easeOutExpoよりも少し急な動きになっていますね。
しかし試しに減衰率を出すときに使う終了地点のパラメータを0.0001から0.001にしてみると...
http://codepen.io/bukurocci/pen/KVGvrO

全く同じ動きをしていました!

結論

結論としてはeaseOutExpoが物理的な動きのイージングになっているということで物理的な減衰の動きをする場合はeaseOutExpoを使うで良いと思いますが、気になったのでもうすこし調べてみます。

余談:easeOutExpoについて

jQuery Easing PluginのeaseOutExpoのコードを見てみると以下のようになっています。

easeOutExpo: function (x, t, b, c, d) {
 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
}

同じ動きをしているのに計算式が全く違いますね不思議です。
$t=d$のときの式を考えてみると

easeOutExpo

2^{-10\frac{d}{d}} = 2^{-10}

easeCustom

e^{-\frac{d}{d} \log 1000} = e^{-\log1000} = (2^{\log_2 e})^{-\log 1000} = 2^{-\log 1000 \times \log_2 e}

$-\log 1000 \times \log_2 e$を計算すると-6.907x1.442で大体-10になるので
easeOutExpoの式は、この式の近似式になっているようにみられます。

Reference

  1. 対数の計算
  2. 微分方程式で数学モデルを作ろう