web-dev-qa-db-ja.com

イージング関数とは何ですか?

アニメーションのコンテキストで関数をイージングするとはどういう意味ですか。 dojo、jquery、silverlight、flex、その他のUIシステムには、イージング機能の概念があるようです。イージング関数の良い説明が見つかりませんでしたか?誰かが関数を緩和する概念を説明したり、それらの良い説明を指摘したりできますか?私はフレームワークの特定の詳細ではなく概念に興味がありますか?

イージングは​​場所に厳密に使用されていますか、それとも一般的で、オブジェクトの任意のプロパティに適用できますか?

46
ams

イージング関数は、通常、完全性のパーセンテージが与えられたプロパティの値を説明する関数です。異なるフレームワークはわずかに異なるバリエーションを使用しますが、アイデアが分かればコンセプトは簡単に理解できますが、いくつかの例を見るのがおそらく最善です。

まず、すべてのイージング関数が従うインターフェースを見てみましょう。

イージング関数はいくつかの引数を取ります。

  • percentComplete:(0.01.0)。
  • elaspedTime:アニメーションが実行されているミリ秒数
  • startValue:開始する値(または完了率が0%のときの値)
  • endValue:終了する値(または完了率が100%のときの値)
  • totalDuration:アニメーションの希望する合計の長さ(ミリ秒)

プロパティが設定する値を表す数値を返します。

注:これは、jQueryがイージング関数に使用するのと同じシグネチャです。例として借用します。

理解するのが最も簡単なのは直線的な簡単さです。

var linear = function(percent,elapsed,start,end,total) {
    return start+(end-start)*percent;
}

そして、これを使用するために:

1000ミリ秒続くアニメーションがあり、0で始まり50で終わるはずだったとします。これらの値をイージング関数に渡すと、実際の値がどのようになるかがわかります。

linear(0, 0, 0,50, 1000)        // 0
linear(0.25, 250, 0, 50, 1000)  // 12.5
linear(0.5, 500, 0, 50, 1000)   // 25
linear(0.75, 750, 0, 50, 1000)  // 37.5
linear(1.0, 1000, 0, 50, 1000)  // 50

これはかなり単純な(しゃれが意図されていない)トゥイーンです。単純な線形補間です。時間に対して値をグラフ化すると、直線になります。

Linear ease

もう少し複雑なイージング関数を見てみましょう。

var easeInQuad = function (x, t, b, c, d) {
    return c*(t/=d)*t + b;
}

そして、以前と同じ入力を使用して、同じ結果を見てみましょう。

easeInQuad(0, 0, 0, 50, 1000)      // 0
easeInQuad(0.25, 250, 0, 50, 1000) // 3.125
easeInQuad(0.5, 500, 0, 50, 1000)  // 12.5
easeInQuad(0.75, 750, 0, 50, 1000) // 28.125
easeInQuad(1, 1000, 0, 50, 1000)   // 50

値が線形の容易さとは大きく異なることに注意してください。最初は非常に遅く、その後終点まで加速します。アニメーションが50%完了したときの値は12.5になりました。これは、指定したstart値とend値の間の実際の距離の4分の1です。

この関数をグラフ化すると、次のようになります。

Quad-Ease-In

次に、基本的なイーズアウトを見てみましょう。

var easeOutQuad = function (x, t, b, c, d) {
    return -c *(t/=d)*(t-2) + b;
};

これは基本的に、イーズインの「反対の」加速曲線を実行します。最初は速く始まり、その後、その終了値まで減速します。

Ease out

そして、インとアウトの両方を容易にする関数があります。

var easeInOutQuad = function (x, t, b, c, d) {
    if ((t/=d/2) < 1) return c/2*t*t + b;
    return -c/2 * ((--t)*(t-2) - 1) + b;
};

EaseInOut

この機能は、最初は遅く、最後は遅く、途中で最大速度に達します。

使用できるイージング/補間はたくさんあります:線形、四次、三次、四分、五、正弦。また、バウンスやエラスティックなど、独自の特殊なイージング関数があります。

たとえば、次の点での弾力的な緩和:

var easeInElastic = function (x, t, b, c, d) {
    var s=1.70158;var p=0;var a=c;
    if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
    if (a < Math.abs(c)) { a=c; var s=p/4; }
    else var s = p/(2*Math.PI) * Math.asin (c/a);
    return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
},

Elastic ease in

正直なところ、私は数学の専門家ではないので、おそらく誰かが補間の背後にある実際の数学の部分を説明できます。しかし、それがイージング関数自体の基本原理です。

トゥイーン/アニメーションを開始すると、アニメーションエンジンは必要な開始値と終了値を記憶します。その後、更新するたびに、経過した時間からの数字が表示されます。プロパティが設定されるべき値を把握するために、提供されたイージング関数を値で呼び出します。すべてのイージング関数が同じシグネチャを実装している限り、それらは簡単に入れ替えることができ、コアアニメーションエンジンは違いを知る必要はありません。 (これは、懸念の分離に優れています)。

イージングは​​位置per seとは特に関係がないため、xyの位置については明示的に説明していません。イージング関数は、開始値と終了値の間の遷移を定義するだけです。それらはx座標、色、またはオブジェクトの透明度です。

そして実際、理論的には、さまざまなイージング関数を適用して、さまざまなプロパティを補間することができます。うまくいけば、これは基本的な考えにいくつかの光を当てるのに役立ちます。

そして、これは本当に クールな例 (少し異なるシグネチャを使用しますが、同じ原理です)で、イージングが位置にどのように関係するかを理解します。


編集

これが少し jsFiddle です。JavaScriptの基本的な使用法のいくつかを示すために一緒に投げました。 topプロパティはバウンスを使用してトゥイーンされ、leftプロパティはクワッドを使用してトゥイーンされていることに注意してください。スライダーを使用して、レンダーループをシミュレートします。

easingオブジェクト内のすべての関数は同じシグネチャを持っているので、それらのいずれかを相互に交換できます。現在、これらのほとんどはハードコーディングされています(開始値と終了値、使用されるトゥイーン関数、アニメーションの長さなど)が、アニメーションヘルパーの実際の例では、次のプロパティで:

  • 変更するプロパティ
  • 開始値(またはundefinedのままの場合、現在の値を使用)
  • 最終値
  • アニメーションの長さ
  • 使用するトゥイーン関数への参照。

アニメーションエンジンは、アニメーションの期間中これらの設定を追跡し、更新サイクルごとにトゥイーン引数を使用してプロパティの新しい値を計算します。

101
J. Holmes

イージング関数は、アニメーションの速度を制御して、望ましい効果(バウンス、ズームイン、スローなど)を与えるアルゴリズムです。

もう少し詳しくは MSDNがそれらについて述べなければならない を確認してください。

11
Justin Niessner

受け入れられた回答があるにもかかわらず、この古い質問に対する私の回答を投稿したいと思います。 2bitkid は必要な説明をしました。追加するのは、基本的な実用的な実装です。これが見つからなかったためです(これについても question を投稿しました)。

たとえば、この単純な線形アニメーションを考えてみましょう。コードは自明であるので、説明は必要ないでしょう。時間の経過に伴って変化しない一定の増分値を計算し、各反復でボックスの位置を増やします。位置変数を直接変更してから、ボックスに適用しています。

JSFiddle

var box = document.getElementById("box");

var fps           = 60;
var duration      = 2;                                   // seconds
var iterations    = fps * duration;                      // 120 frames
var startPosition = 0;                                   // left end of the screen
var endPosition   = window.innerWidth - box.clientWidth; // right end of the screen
var distance      = endPosition - startPosition;         // total distance
var posIncrement  = distance / iterations;               // change per frame
var position      = startPosition;                       // current position

function move() {
  position += posIncrement;              // increase position
  if (position >= endPosition) {         // check if reached endPosition
    clearInterval(handler);              // if so, stop interval
    box.style.left = endPosition + "px"; // jump to endPosition
    return;                              // exit function
  }
  box.style.left = position + "px";      // move to the new position
}

var handler = setInterval(move, 1000/fps); // run move() every 16~ millisecond
body {
        background: gainsboro;
}
#box {
        width: 100px;
        height: 100px;
        background: white;
        box-shadow: 1px 1px 1px rgba(0,0,0,.2);
        position: absolute;
        left: 0;
}
<div id="box"></div>

では、イージングを追加しましょう。 linear(緩和なし)を使用して簡単に始めます。上記と同じアニメーションになりますが、アプローチは異なります。今回は、位置変数を直接変更しません。修正するのは時間です。

function linear(time, begin, change, duration) {
    return change * (time / duration) + start;
}

まず、パラメータについて話しましょう。

  • time:経過時間
  • begin:プロパティの初期値(幅、左、マージン、不透明度など)
  • change:変位、(終了値-開始値)
  • duration:アニメーションにかかる合計時間

timedurationは直接関連しています。 2秒のアニメーションがある場合は、timeを増やし、それをイージング関数linearに渡します。関数は、ボックスが指定された時間にその位置にあることを示す位置を返します。

2秒でボックスを0から100に移動するとします。ボックスの位置、たとえば700ミリ秒を取得したい場合は、linear関数を次のように呼び出します。

linear(0.7, 0, 100, 2);

35を返します。アニメーションが開始してから700ミリ秒後、ボックスの位置は35pxになります。これを実際に見てみましょう。

JSFiddle

var box = document.getElementById("box");

var fps           = 60;
var duration      = 2;                                   // seconds
var iterations    = fps * duration;                      // 120 frames
var startPosition = 0;                                   // left end of the screen
var endPosition   = window.innerWidth - box.clientWidth; // right end of the screen
var distance      = endPosition - startPosition;         // total distance
var timeIncrement = duration / iterations;
var position      = 0;
var time          = 0;

function move() {
        time += timeIncrement;
        position = linear(time, startPosition, distance, duration);
        if (position >= endPosition) {
                clearInterval(handler);
                box.style.left = endPosition + "px";
                return;
        }
        box.style.left = position + "px";
}

var handler = setInterval(move, 1000/fps);

function linear(time, begin, change, duration) {
        return change * (time / duration) + begin;
}
body {
        background: gainsboro;
}
#box {
        width: 100px;
        height: 100px;
        background: white;
        box-shadow: 1px 1px 1px rgba(0,0,0,.2);
        position: absolute;
        left: 0;
}
<div id="box"></div>

このコードで注意が必要な部分は次のとおりです。

var timeIncrement = duration / iterations;
var time = 0;

function move() {
    time += timeIncrement;
    position = linear(time, startPosition, distance, duration);
    // ...

最初のアニメーションでは、位置変数を直接変更しました。一定の位置増分値が必要でした。計算方法はposIncrement = distance / iterationsです。イージングにより、位置変数は変更されなくなり、時間変数が変更されます。したがって、時間増分値が必要です。位置の増分と同じ方法で計算しますが、今回はdurationiterationsで除算します。時間を増やして時間を増やし、時間をイージング関数に渡します。イージング関数は、ボックスが占める次の位置を返します。

total distance / iterations (frames) = position change per frame
total duration / iterations (frames) = time change per frame

これが目のグラフです。

Ease function graph


最後に、easeInOutQuadの例を示します。

JSFiddle

var box = document.getElementById("box");

var fps           = 60;
var duration      = 2;                                   // seconds
var iterations    = fps * duration;                      // 120 frames
var startPosition = 0;                                   // left end of the screen
var endPosition   = window.innerWidth - box.clientWidth; // right end of the screen
var distance      = endPosition - startPosition;         // total distance
var timeIncrement = duration / iterations;
var time          = 0;
var position      = 0;

function move() {
  time += timeIncrement;
  position = easeInOutQuad(time, startPosition, distance, duration);
  if (position >= endPosition) {
    clearInterval(handler);
    box.style.left = endPosition + "px";
    return;
  }
  box.style.left = position + "px";
}

var handler = setInterval(move, 1000 / fps);

function easeInOutQuad(t, b, c, d) {
  if ((t /= d / 2) < 1) {
    return c / 2 * t * t + b;
  } else {
    return -c / 2 * ((--t) * (t - 2) - 1) + b;
  }
}
body {
        background: gainsboro;
}
#box {
        width: 100px;
        height: 100px;
        background: white;
        box-shadow: 1px 1px 1px rgba(0,0,0,.2);
        position: absolute;
        left: 0;
}
<div id="box"></div>
2
akinuri

これは、ある状態から別の状態へのプロパティ(サイズ、形状、場所)の遷移です。

以下は、jquery uiによって提供されるイージング関数を説明するきちんとした小さなグラフです。

http://jqueryui.com/demos/effect/easing.html

0
Chris Lacasse