2017-06-08 11 views
0

Javascriptのアニメーションを作成しようとしているときに問題が発生しました。私はStackoverflowや他のウェブサイトで同様の質問を見つけることができないので、皆さんが私を助けてくれることを願っています。警告:私は執筆が好きなので、おそらくこのトピックは少し長いです、そして、私はそれを残念です。私はすべてを明確にしたい。 TL; DR版はこの記事の一番下にあります。タイミングのJavaScriptのアニメーション:最後にゆっくりとしてください

何を作成しようとしていますか?
私は自分自身のJavascriptライブラリを構築しています(学習目的のため、jQueryや他のライブラリをこの問題に使用したくありません)。ライブラリには多くの機能があり、アニメーションもその1つです。アニメーションは、特定の要素のCSSの変更ですが、円滑な方法で行います。要素の幅が200pxで、それを400pxにしたいとしたら、それは絶対に変わらないが、やや穏やかに変わっていればもっと良く見えます。私はアニメーションを作りましたので、それは問題ではありません。

私の問題は何ですか?
アニメーションには特定の期間があります。この時間枠内で、cssはある値から別の値に変更されます。 startanimate()メソッドが呼び出された開始時間である

let timeFraction = (time - start)/this.duration; 

(あなたは少しのコードが表示されます):私はそれを作ったような時間枠では、次の計算を持っています。時間は、アニメーションの実行中の時間であり、時間と開始がdurationの量と異なる場合、アニメーションは終了します。
timeFractionは、アニメーションが呼び出されてから経過した時間です。このammountには変更されたCSS値が乗算されます。

私は200pxから400pxに、再び、ammountを変更したい:これはので、私は例をあげてみましょう、私が知っている、少し奇妙に聞こえます。これら2つの値の差は200pxです。したがって、要素はこの値を変更する必要があります。
アニメーションの時間枠は3000msです。したがって、アニメーションは3秒で完了する必要があります。 1.5秒が経過している(3秒の半分)と、200pxの半分は、既存の幅である200pxを加算する必要があります。

let timeFraction = (1500 - 0)/3000; // is 0.5 
let cssAdded = timeFraction * 200; // 100px 

3Sは過去あるときに、timeFraction1であるべきであり、それは完全な200pxになります。
これは魅力的です。アニメーションは滑らかに実行されますが、終了するときにはアニメーションの速度が大幅に遅くなります。ここでの例である:

See a GIF

計算は依然として同じです。時間枠が過ぎるまでスムーズに変更したいだけです。

私のコードは何ですか?
私はEcmaScript 6とvanilla JSで作業しています。

アニメイト方法:

animate(css) { 
    if(this !== undefined && css) { 
     this.css = css; 
    } 

    let start = performance.now(); 

    requestAnimationFrame(function animate(time) { 
     let timeFraction = (time - start)/this.duration; 

     if(timeFraction > 1) timeFraction = 1; 

     let timing = this.timer(timeFraction); 

     this.draw(timing); 

     if (timing < 1) { 
      requestAnimationFrame(animate.bind(this)); 
     } 
    }.bind(this)); 
} 

タイマー方法:

timer(timeFraction) { 
    return timeFraction; 
} 

drawメソッド:

draw(timing) { 
    for(let property in this.css) { 

     let newValue = window.getComputedStyle(this.element)[property]; 
     let match = /\d+(px|em|%|rem)/.exec(newValue); 

     if(match !== null) { 
      newValue = match[0].replace(match[1], ''); 
      this.element.style[property] = Math.floor(parseInt(window.getComputedStyle(this.element)[property].replace('px', '')) - (timing * (newValue - parseInt(this.css[property].replace('px', ''))))) + match[1]; 
     } 
     else { 
      this.element.style[property] -= timing * (window.getComputedStyle(this.element)[property] - this.css[property]); 
     } 
    } 
} 

私が何をしようとしたのですか?
まず、JavaScriptアニメーションを作っている人の例を検索しようとしました。アニメーションの時間枠内でCSSを計算する方法を試しましたが、問題は解決されませんでした。私はperformance.now()new Date().getTime()に変更しようとしましたが、そこからさらに計算しましたが、同じ問題が発生しました。だから私はなぜアニメーションがいつも同じスピードであるとは限りませんが、それはすべきではありません。みんな助けてくれますか?

TL; DRバージョン
私はJavaScriptでアニメーションを作成しています。アニメーションは線形です(常に同じ速度です)が、アニメーションがアニメーションの最後で遅くなることがあります(このトピックのGIFを参照)。

私の具体的な質問
最後にアニメーションが遅くなるのはなぜですか?それと何が関係していますか?上記で説明した計算や何か他の計算?それとも、私は何か重要なものを逃していますか助けてください、私はこれを引き起こしているのか分かりません。

+0

'(time-start)/ this.duration'で各フレームの時刻を再計算しているようですが、' timer'を呼び出すとその数は大きくなります毎回 'time'が' start'から遠ざかるにつれて –

+0

[あなたのタイミング関数はグラフで表示されます](https://jsfiddle.net/hovu5jvq/)。これは、アニメーションフレームがタイムリーに実行されている限り線形に見えます。おそらくあなたの問題は、CSS値を操作するロジックにあります。 –

+0

パフォーマンスタブでdevtoolsでタイムラインを使用してみましたが、DOMがあなたを遅らせる何かをしていないかどうかを確認しましたか?あなたが提供したコードに間違ったものは何も見えません。それはCSSオブジェクトの反復回数によって異なります。そして、 'timer(timeFraction){ return timeFraction; } '??? – Blindman67

答えて

0

なぜアニメーションが最初よりも遅くなったのか分かりました。

私の質問で述べたように、drawメソッドが呼び出されるたびに計算が行われます。この計算では、既存のcssプロパティのアニメーション化と、変数timing(変数はアニメーションの時間枠を保持しています)を掛け合わせて比較しました。アニメーション時間の半分が経過すると、timingは0.5になり、アニメーションが完了した場合、timingは1です)。

ただし、毎にと計算されるため、drawというメソッドが呼び出されても、その都度の違いがあります。結局のところ、アニメーションがほぼ完了すると、その差はごくわずかです。そしてその差は小さくなるが、timing * differenceも小さくなる。
この結果、毎回加算される差は小さくなります。 (だから最初からそれは遅くなりますが、気付かないでしょう)。

アニメーションの開始時に差分を計算するようにコードを変更し、すべてのループをもう一度フェッチするのではなく、timingにその差を乗算しました。 (それ以外にも、コードはより洗練され、読みやすく理解しやすくなります。

アニメイト方法:

animate(css) { 
    if(typeof css === 'object') { 
     for(let property in css) { 
      this.cssDiff[property] = this.calculateDifference(property, css[property]) 
     } 
    } 
    else if(arguments.length === 2) { 
     this.cssDiff[arguments[0]] = this.calculateDifference(arguments[0], arguments[1]); 
    } 
    else { 
     return; 
    } 

    //The rest of the code, same as in my question... 
} 

drawメソッド:

draw(timing) { 
    for(let property in this.cssDiff) { 
     this.element.style[property] = this.cssDiff[property].start + (timing * this.cssDiff[property].value) + this.cssDiff[property].unit; 
    } 
} 

そして、私は違いを計算する方法を追加しました:

calculateDifference(property, cssValue) { 
    let existingCSS = window.getComputedStyle(this.element)[property]; 
    let match = /(\d+)(px|em|%|rem)/.exec(existingCSS); 
    let differenceMap = {value: 0, unit: 0, start: 0}; 

    if(match !== null) { 
     differenceMap.start = Number(existingCSS.replace(/px|em|%|rem/g, '')); 
     differenceMap.value = Number(cssValue.replace(/px|em|%|rem/g, '')) - Number(match[1]); 
     differenceMap.unit = match[2]; 
    } 
    else { 
     differenceMap.start = Number(existingCSS); 
     differenceMap.value = (typeof cssValue === 'string' ? Number(cssValue.replace(/px|em|%|rem/g, '')) : cssValue) - Number(existingCSS); 
    } 

    return differenceMap; 
} 

コードのこの作品は、一度呼び出されますすべてがアニメーションのCSSプロパティであるため、このコードはもっと速くなり、アニメーションごとの違いを計算しますフレーム。

とリーンするonther人々のために、これはtimer方法である(@ Blindman67の質問への答えとして)

timer(timeFraction) { 
    switch(this.easing) { 
     case 'ease-in': 
      return timeFraction * timeFraction; 
      break; 
     case 'ease-out': 
      return timeFraction * (2 - timeFraction); 
      break; 
     case 'circ': 
      return 1 - Math.sin(Math.acos(timeFraction)); 
      break; 
     case 'bounce': 
      for (let a = 0, b = 1; 1; a += b, b /= 2) { 
       if (timeFraction >= (7 - 4 * a)/11) { 
        return -Math.pow((11 - 6 * a - 11 * timeFraction)/4, 2) + Math.pow(b, 2) 
       } 
      } 
      break; 
     default: 
      return timeFraction; 
      break; 
    } 
} 

私は、JSのアニメーションを作りたい、他の人は、この質問+答えを見つけることを願って有用。皆さんありがとうございます。私には解決策を考えてもらいました。

関連する問題