Kazuma Labolatory's

Nothing is Impossible. ✿

Menu

【js/前半】window.requestAnimationFrame()を解説してみた🌟

思考の整理も兼ねて。分かりやすい説明を心がけて。。

window.requestAnimationFrame(Callback)

JavaScript でアニメーションを描写したい時に使います。

JavaScript でアニメーションを描写するには、 window.setInterval()window.setTimeOut()などの、タイマー系メソッドを使ってアニメーションを実現します。後発で実装されたwindow.requestAnimationFrame()は、こちらもタイマー系メソッドでsetTimeout()に近いですが、アニメーション描写に特化されており、色々な点が改良されたメソッドとなっています。特徴としては、

  • デバイス毎に最適なフレームレートになるよう自動でcallbackをupdateするタイミングを計算・実行してくれる
  • フレームの不足・超過がなくなる → (スムーズなアニメーション描写 | CPU・GPUの浪費の削減)

などです。

 

ではまず、W3C のサンプルコードから。。

CSS

#ani {
   position: absolute;
   left: 10px;
   padding: 50px;
   margin: 100px;
   width: 100px;
   height: 80px;
   background: crimson;
   color: #fff;
   }

 

HTML

<div id="ani"></div>
<button onclick="start()">Click me to start!</button>
<button onclick="stop()">Click me to stop!</button>

 

JavaScript

var requestId = 0;

function animate(time) {
   document.getElementById("ani").style.left =
      (time - animationStartTime) % 2000 / 4 + "px";
   requestId = window.requestAnimationFrame(animate);
}
function start() {
   animationStartTime = window.performance.now();
   requestId = window.requestAnimationFrame(animate);
}
function stop() {
   if (requestId)
      window.cancelAnimationFrame(requestId);
   requestId = 0;
}

 

 

 Timing control for script-based animations -W3C

 

JS Bin on jsbin.com

 

JavaScriptのコードを一見して、分かるようなわからないような…。Statement Block が複数に分かれているため、少し分かりにくいですね。少なくとも、僕は初見ですんなりとは理解できませんでしたw(僕の知識不足もありますが…😅💦w) そこで、これを分かりやすくするため、限りなくシンプルなコードにしてみました。

 

基礎編

CSS

#ani {
   position: absolute;
   width: 100px;
   height: 100px;
   background: crimson;
   }

 

HTML

<div id="ani"></div>

JavaScript

var elm = document.getElementById("ani");
var n = 0;

function animate() {

   elm.style.left = 2*n + "px";
   if (parseInt(elm.style.left) > 200) {
      cancelAnimationFrame(id);
   } else {
      n++;
      requestAnimationFrame(animate);
   }
   
}

var id = requestAnimationFrame(animate);
var elm = document.getElementById("ani");
var n = 0;

var id = requestAnimationFrame(function animate() {

   elm.style.left =  2*n + "px";
   if (parseInt(elm.style.left) > 200) {
      cancelAnimationFrame(id);
   } else {
      n++;
      requestAnimationFrame(animate);
   }

});

❶(通常版)requestAnimationFrame(Callback)(Callback) を別々に記述

❷(合体版)

requestAnimationFrame(Callback)(Callback)の部分に、直接 Callback (Function)コールバック(関数) を記述

 

 

❷: Demo

JS Bin on jsbin.com

 

大分コードがまとまり、どの部分が何の働きをするのか、分かりやすくなったのではないでょうか。

❶と❷で記述の仕方が少し違いますが、実行結果は同じです。

ここでは、コードが上から順に実行されていき、理解しやすい❷(合体版) の方を見本に解説していきます。

それではいよいよ、

  • requestAnimationFrame()
  • callback function であるfunction animate(){}の中身

を理解し、アニメーションが実現される仕組みをみていきましょう🌟

 

ポイント1 - Callback function 内で、requestAni...(Callback) の再要請re-invocation

requestAni...()は、大雑把に言うと、アニメーションの1フレーム分を呼び出します。先ほど書いた様に、そのJavaScriptが実行されるデバイス環境によって、最適化された1フレーム分です。

JavaScript によるアニメーションscript-based animationの原理としては、実際のアニメやパラパラマンガの原理を想像すると分かりやすいかもしれません。いくつもフレームが順番に1, 2, 3, 4毎目と変化していくことによって、アニメーションになる訳です。

このリクアニメソッドもその方法と同じ原理です。そのめくるタイミングはrequestAni...()が、観覧デバイスに最適になるように実行してくれます。後はその一枚一枚をどの様に描写するかをCallback(function)で記述します。

Callback とは正確にはcallback functionコールバック関数の事であり、「Event発生後や、とあるコード終了後にinvoke要請されるfunction」です。callback とは、日常では「折り返し電話」の事ですが、programmingの場合は、上記の意味で使います。

この場合、requestAnimationFrameで1フレーム分を呼び出した後に実行されるfunctionの事で、そのCallback Function で各フレーム毎の描写をどの様にするか記述します。

requestAni...(Callback)Callbackを繰り返す事でアニメーションを実現する

1フレームを呼び出し、そのフレーム内をどう記述するかも書いたとします。ですが、これは1フレーム分です。パラパラマンガのようにアニメーションにするにはこれを連続して繰り返す必要があります。
その為、(callback)内に再度requestAni...(callback)を記述し、1番始めに記述した(callback)内をループさせる形になるます。そして、このままだと永久にアニメーションが実行されてしまうので、ある条件を満たした際にアニメーションが停止するよう、if文if statementで定義しておきます。これでアニメーションの完成という訳です。

var id = requestAnimationFrame(function animate() {

   elm.style.left =  2*n + "px";
   if (parseInt(elm.style.left) > 200) {
      cancelAnimationFrame(id);
   } else {
      n++;
      requestAnimationFrame(animate);
   }

});

因みに、アニメーションを実現するポイントとして、1回目のrequestAnimationFrame(callback)のcallback function内に、2回目のrequestAni...(callback)(上記の例ではrequestAni...(animate))を記述する点です。

どういうことか理解するため、もう一度コードの実行プロセスを考えてみましょう。

最初のrequestAni..で1フレーム呼び出し、elementの振る舞いが実行された後、再びもう1フレーム分を呼び出し実行→ さらに次の1フレーム分を呼び出し実行 →... となりアニメーションが実現される訳です。もし、先の見本コードのようにcallback内に次のフレーム呼び出すrequestAni...(callback) を記述する方法ではなく、それ以外でアニメーションを実現しようとすると、コードが非常に煩雑になってしまうのです。

var elm = document.getElementById('d');
var n = 0;

function animate() {

   elm.style.left =  2*n + "px";
   n++;
   
   if (parseInt(elm.style.left) > 200) {
      cancelAnimationFrame(id);
   }
}

var id = requestAnimationFrame(function() {
   animate();
   requestAnimationFrame(function() {
      animate();
      requestAnimationFrame(function() {
         animate();
         requestAnimationFrame(function() {
            animate();
            requestAnimationFrame(function() {
               animate();
               requestAnimationFrame(function() {
               animate();
                  requestAnimationFrame(function() {
                     animate();
                     ...
                        ...  
                        
                                            
                  });
               });
            });
         });
      });
   });
});

コードが実行される流れExcution processを追ってみると分かりますが、1度目のrequestAni..()は一回実行されただけで終わってしまいます。再び実行して次のフレームを呼び出し・描写するには、その回数分だけrequestAni..()と書かなければなりません。欲しいフレーム分だけ、requestAni...(callback)を書く必要が出てきてしまいます。これは事実上不可能ですね😅w

ということで、callback内の 「loop is cool!✨;)」 という訳なのですね🤗🌟

 

 

 

  • Function Declaration関数宣言 & Function Expression関数式

サンプルコードで❶通常版, ❷合体版 は、どちらも関数宣言Function Declarationで関数を定義Function Definitionしています。

function の定義の仕方には、大きく分けて2つ、
 - Function Declaration
 - Function Expression
があります。どちらもでもほぼ同じですが、正確には少し違いがあります。少し踏み込んだ内容であり、普段は気にしなくてOKです。気になる方は、書籍等ご参照下さい(•ᵕᴗᵕ•)⁾⁾🌟

Function Declaration, Function Expression って? という方は、こちらの記事をご参照下さい(* ˊ˘ˋ)*_ _))🌟
 -

  • Callback Functionコールバック関数

requestAnima...(callback) の Callback (function) って何? という方は、こちらの記事をご参照下さい(* ˊ˘ˋ)*_ _))🌟
 - Understand JavaScript Callback Functions and Use Them -JavaScript Is Sexy.com

"Webサイト解説(en)・free books"で、 Callback についての正確な説明は少ないように見受けられました。日本語のWebページも少し検索してみましたが…💩✨←(コラコラw)でした。
元々callback の概念は、Functional Programming(FP) に由来するものらしいです🌟⁽⁽φ(・д・。)ホォホォ←(これから学習予定ですw)

*1

  • window.requestAnimationFrame()

window.requestAnimationFrame()requestAnimationFrame() と記述し、window.は見易さのため省略しています。書かなくても作動はしますが、window.requestAnimathonFrame()から分かるように、requestAnimationFrame()はwindow objectのメソッドです。

オブジェクトのプロパティ(property)・メソッド(method)は、JavaScript の基幹部分の一つです。しかしながら、"Webサイト解説(en)"や"free books"でも、この辺りを明確に解説しているものはほとんどない印象でした。市販の本で、かつComputer Scienceを学ばれた方の書籍を参照した方が良いかもしれません。

ちなみにこのブログで何度も書いている「JavaScript Ninja」にはバッチリ分かりやすく解説されてましたので超絶オススメです|*´-`)✨←(回し者)w 知って間もないですが、Manning pub さんはIT 関連を専門にされている出版社らしく、サンプルを幾つかか読んでみたり購入*2してみましたが、良さそうな書籍が多そうな印象でした。

他のIT関連書籍の出版社だと、定番の O'Reilly(オライリー) でしょうか。日本語の翻訳本も多数出ています🌟

 

:: Reference

:: 応用編(次回): requestAni...()のcallback function の argument(引数)

 

後半解説:17.03.20追加

ddramonqssecret.hatenadiary.jp

 

 

 

*1:後、これはこの事項だけに限りませんが、「誤った説明」「本質から外れている説明」というのは読まない方がよいと最近感じました。意欲が削がれ、余計に「それ」が分からなくなる事があると感じました。分からない →「それ全体」への興味が削がれてしまう。
これは誰が悪い訳でもないと僕は考えています。ただもし、今後そういう説明媒体に出会った場合は、「読むのをやめる」→「他に分かりやすいと感じる説明媒体がないか探してみる」をお勧めします。的を射ない説明は、読者の頭が悪いからでもなんでもなく、的を射ないからであり、何度読んでも分かりません。他の可能性を探るのが吉だと最近ひしひし感じています(現在進行系)。ご多分に漏れず、この記事も分かりにくいと感じる場合は、即刻斬り捨て御免! でおなしゃすですw0(:3 )~ ('、3_ヽ)_ 精進いたします(꜆꜄•௰•)꜆꜄꜆»💦シュシュシュッ

*2:『Get Programming With JavaScript』Author: John R. Larsen

This Blog uses M+ Font, Logo Type Gothic, Google Fonts and FontAwesome. It"s free & Designed cool font. Greatful for Koji Morishita of M+ Fonts Designer( Creator) and "フォントな" , Google, Adobe, and Dave Gandy!
Background Photos is downloaded by Unsplash.com. Thanks!
|*´-`)チラッ
Please Click Me
本ブログ全てにおいて、アフィリエイトプログラムには参加しておりません(•ᵕᴗᵕ•) 詳しくはこちらをご覧下さい。また、 以下のバナーは、私が「質が高い・あら素敵(ˊo̶̶̷ᴗo̶̶̷`)✨」と感じたサイト様を掲載させて頂いておます_(( _๑´ω`))_⭐️