[69-14] Canvasのアニメーションの基本を見てみよう

最終更新日:2019年02月06日  (初回投稿日:2015年06月18日)

ここまで Canvasの 図形・ライン・画像・テキストなどを描画をしてみました。
今回はとうとう(笑)これらのエレメントを動かして、基本的なアニメーションを作ってみます。

javaScriptを使いこなせる人ならラクチンかもしれませんが、javaScriptがサッパリの私は、けっこう難業でした。でもまあ基本を調べてどうにか動かしてみた様子を、どうぞご覧ください。

本日のINDEX
  1. Canvasをクリアするのがアニメーションの基本だって
    1. Canvasのクリアの方法
    2. save() とrestore() を使う
  2. アニメーションのタイミングの指定
    1. setInterval()
    2. setTimeout()
    3. requestAnimationFrame()
  3. setInterval() で簡単なアニメーションを作ってみる(サンプル1)
  4. setTimeout() と、new Date()、 getSeconds() で秒針を動かしてみた(サンプル2)
    1. new Date()
    2. getSeconds()
    3. getMinutes()
    4. getHours()
  5. requestAnimationFrame() でアナログ時計を作ってみた(サンプル3)
  6. Canvasの基礎を学んでみて「ライブラリを活用しよう」と思いました(笑)

今回のサンプルはコチラ。2ファイル、3サンプルに分かれています。
setInterval() と setTimeout() で作ったもの1つずつ(サンプル1、サンプル2)
requestAnimationFrame() で作ったアナログ時計(サンプル3)

サンプル1

setInterval() で Canvasの範囲で壁にバウンドして動く円を描画。 まずはアニメーションの基本のソースを書いてみます。

サンプル2

setTimeout() で繰り返しを作ってみました。 new Date()、getSeconds() で秒針を動かしています。

サンプル3

requestAnimationFrame() で短針、長針もあるアナログ時計を、MDN(Mozilla Developer Network)Basic animations のサンプルを参考に、アレンジしてみました。

Canvasをクリアするのがアニメーションの基本

Canvasでアニメーションは、ストップモーションムービー(コマ撮り)のように1コマ1コマを描いていくイメージです。

Canvasに1度描いたグラフィックスは動かせないので、
描いて全部消し、描いて全部消し...を繰り返す。
・再描画のときに動かしたいものだけをずらす
・繰り返しは、javaScriptのメソッド(setInterval()など)を使う。
というのが基本みたい。

例えば時計のアニメーションだったら、動かす針だけ消して、時計のフレームや文字盤は残しておきたいところですが、そうするとソースコードがめっちゃ長くて面倒なことになるので、
全部消して全部再描画するのだそうです。

図にするとこんなかんじです。

Canvasのクリアの方法

で、Canvasの全面をクリアする方法ですが、以下の2つの方法があるようです。

  • clearRect(0,0,canvas.width,canvas.height) を使う
    (四角の領域を透明にするアレね。「[69-2] Canvasに基本的な図形を描こう」で詳細)
  • canvas.width = canvas.width
    または canvas.height = canvas.height
    (widthかheightに、自分自身の値をセットし直す)

ここで「canvas.width」とかで使ってる canvas って<canvas>要素につけた id 名です。ご自分がつけたid名に変えてね。
2dコンテキストを取得する時に、getElementById で<canvas>要素を id で指定する、あの id ですよ。
例えば、canvasのidを「myCanvas」にしたのなら、「myCanvas.width」や「myCanvas.height」ということ。

2つめの「canvas.width = canvas.width」って、おまじないみたいですが、
全面をクリアする Canvas特有の裏技だそうです。
width か height に自身の値をセットし直すと、Canvas全体の描画が無くなるんだって。

サンプル2で「clearRect」ではどうにもならず、ハマったのですが、色々調べた挙げ句、この「canvas.width = canvas.width」を使ったら、あ〜ら不思議、できちゃった。裏技スゲ〜(笑)

save() とrestore() を使う

「アニメーション = 描画ソースの繰り返し」なので、Canvasの「1度指定した設定はそのまま踏襲される」特徴がアダになることがあります。
そこで save と restore を繰り返し使うことが大事なんだそうです。

*save と restore については、コチラをご覧ください。
 「[69-10] Canvasの描画コンテキストの状態を保存・復元する(save() と restore() )」
*アニメーションでの save と restore の使用についてはサンプル1の解説で具体的に↓

アニメーションのタイミングの指定

Canvasのアニメーションと言っても、繰り返しのソースは javaScriptで書きます。
javaScriptの繰り返し実行するメソッドを使ってアニメーションを作ります。
(描画をCanvasが担当)
繰り返しのためのメソッドは「setInterval」「setTimeout」「requestAnimationFrame」があるようです。今回それぞれを使ってみましたので、ざっとそれぞれの内容をまとめておきます。

setInterval()

interval」って間隔の意味。
setInterval() は一定間隔で関数を繰り返し呼び出します。
setInterval(●,△) というカタチで使い、△はミリセコンド(millisecond ミリ秒)で指定。
「△ミリセコンドの間隔で●を繰り返す」という指令です。(1000ミリセコンド = 1秒

繰り返しを解除する「clearInterval()」もあります。
詳しくはMDN | WindowOrWorkerGlobalScope.setInterval()で。

この setInterval() はサンプル1で使っています。

function Draw() {
  //ここに描画したい処理
};
setInterval(Draw,100);  //0.1秒間隔で「Draw」を繰り返します

setTimeout()

「Timeout」は時間切れって意味だけど、setTimeout() は一定時間後に関数を呼び出します。なので、コレ自体では繰り返しはせず「△秒後に●をする」的な使い方になります。

こちらも解除用の「clearTimeout()」があります。
詳しくはMDN | WindowOrWorkerGlobalScope.setTimeout()を。

で、この setTimeout() を使った繰り返しなんですが、
「関数自身の中に 自分(関数)を setTimeoutで入れれば繰り返す」んだって。
う〜〜ん、なんかカオス。
コレでサンプル2を作っています。

function Draw() {
  //ここに描画したい処理
  setTimeout(Draw,100);  //Draw自身の中にsetTimeoutで自分=Draw を入れます
};

上のソースの書き方 setTimeout(Draw,100); で、setInterval() と同じように「0.1秒ごとに繰り返す」ようになったようですが、
setTimeout()を使った繰り返しは、setInterval() より遅延がでるんだそうです。
setInterval() は「関数を呼び出す間隔を指定」するだけですが、setTimeout()を使った繰り返しは「関数を呼び出し実行 → setTimeoutの呼び出し → 関数を呼び出し実行...」と面倒くさいことをしてるから...ということだそうです。
遅れがあっちゃダメなアニメーションなら、setInterval() のほうを使おうってことですかね。

requestAnimationFrame()

使い方は setTimeout() に似てるんですけど、特徴は第2引数が無いこと。タイミングはブラウザにおまかせ、およそ60回/秒(60fps)で再描画されるそうです。

「およそ」って、なんだかいい加減だけど、メリットはこちら↓
●ブラウザの準備ができたら実行(setIntervalやsetTimeoutはおかまい無しに実行)
●タブ(ブラウザウィンドウ)がアクティブじゃなかったらスピード(fps)を落とす(setIntervalやsetTimeoutはおかまい無しに実行)
fpsをばっちり指定したいなら不向きですが、メモリの消費を抑えるユーザに優しいメソッドだって。
この requestAnimationFrame() はサンプル3で使っています。
(サンプル3はアナログ時計なんですが、ブラウザにおまかせでも別に問題なく正確な時間を表示しているようです)

function Draw(){
  //ここに描画したい処理
  window.requestAnimationFrame(Draw);  //setTimeoutと同じで自分の中に自分を入れます
}

requestAnimationFrame() の詳細はこちらで。
MOZILLA DEVELOPER NETWORK
LIG inc.「requestAnimationFrame の使い方」

上記のタイミングの指定をそれぞれ使ってサンプルを作ってみました↓

setInterval() で簡単なアニメーションを作ってみる

サンプル1(クリックで別ウィンドウで開きます)

setInterval() を使用して、グリーンの円を動かしています。
Canvasの範囲(300×300px)内で、円の中心点の x,y座標がそれ以上になったら跳ね返るように指定しています。

このアニメーションは、初期化のclearRectを使わずに、透明度の低い黒地を重ねることで軌跡を作っています。

参考サイト:http://yoppa.org
同様の動きでより詳細なのはこちら:http://www.cynetlab.com/

save() とrestore()の具体例

このサンプル1では、グリーンの円の描画に「globalCompositeOperation = "lighter"」を使っています。重なるほど明るくなるヤツね。

でも、繰り返しのはじめに描画する透明度の低い黒の四角の描画のときに(9,10行目)コレが効いてたらダメです。globalCompositeOperationのデフォはsource-overで、普通の描画ですから、これに戻しておく必要があります。

というわけで、11行目の save() で globalCompositeOperationのデフォ状態を保存しといて、グリーンの円が描き終わった後に restore() (28行目)しています。

function Draw1(){
  var canvas = document.getElementById('canvas1');
  var ctx = canvas.getContext('2d');
  var speedX = 3.0;
  var speedY = 3.2; //speedXと少しずらす(同じ値だと一直線に行ったり来たりするだけ)
  var locationX = canvas.width/2;
  var locationY = canvas.height/2;
  setInterval(function(){
  ctx.fillStyle = "rgba(0,0,0,0.1)"; //透明度の低い黒地を重ねることで軌跡を作っている
  ctx.fillRect(0,0,canvas.width,canvas.height);
  ctx.save();  /*ここで保存(次の↓globalCompositeOperationのため)*/
	
  ctx.globalCompositeOperation = "lighter";
  //位置を移動させる設定
  locationX += speedX;
  locationY += speedY;
  if(locationX < 0 || locationX > 300){
	    speedX *= -1;
	}
  if(locationY < 0 || locationY > 300){
	    speedY *= -1;
	}
  //上で設定した座標で円を描く
  ctx.beginPath();
  ctx.fillStyle = '#060';
  ctx.arc(locationX, locationY, 6, 0, Math.PI*2, true);
  ctx.fill();
  ctx.restore(); //globalCompositeOperationをsave状態に戻しています

  }, 20);
};

setTimeout() と、new Date()、 getSeconds() で秒針を動かしてみた

サンプル2(クリックで別ウィンドウで開きます)

こちらは setTimeout() で繰り返しています。
new Date() の getSeconds() という「時間(getSeconds なら秒)をゲットする」メソッドを使って、秒針を表示しています。

ラインを回転させるのですが、rotate() はcanvasの左上を中心点にするため、全体を translate() で移動して、回転の中心点がcanvasの真ん中になるようにしています。

クリアは clearRect() では不可で、「canvas2.width = canvas2.width」ではOK。
理由はわかんないけど結果オーライだ(笑)このクリアだけで何時間もハマったので、できて感激〜

function Draw2() {
  var canvas2 = document.getElementById('canvas2');
  var ctx2 = canvas2.getContext('2d');
  //ctx2.clearRect(0,0,canvas2.width,canvas2.height); ←これはダメだった
  canvas2.width = canvas2.width; //canvas特有の全体をクリアする裏技だそうです 
  ctx2.translate(150,150);     //回転の起点をcanvasの中心にする
  ctx2.lineWidth = 3;
  ctx2.strokeStyle = "#999";
  // 回転の設定(1秒に6度ずつ回転させる)
  var sec = new Date().getSeconds();
  ctx2.rotate(sec * Math.PI/30);
  // 秒針の描画
  ctx2.beginPath();
  ctx2.moveTo(0,0);
  ctx2.lineTo(130,0);
  ctx2.stroke();
  // 時計のフレームの描画
  ctx2.beginPath();
  ctx2.arc(0,0,145,0,Math.PI*2,true);
  ctx2.stroke();
  setTimeout(Draw2,100);
};

時計のアニメーションでは日付や時刻に関するオブジェクトを使ったので、以下にまとめておきます。

●new Date()

Date は、日付や時刻を扱うことができるオブジェクト。
new Date() というカタチで引数無しなら、現在のローカルタイムでDateオブジェクトが作られます。詳細はMDN | Dateで。

●getSeconds()

new Date().getSeconds() で現在の「秒」をゲットすることができます。
詳細はMDN | Date.getSecondsで。

●getMinutes()

new Date().getMinutes() で現在の「分」をゲットすることができます。
詳細はMDN | Date.getMinutesで。

●getHours()

new Date().getHours() で現在の「時」をゲットすることができます。
詳細はMDN | Date.prototype.getHoursで。

requestAnimationFrame() でアナログ時計を作ってみた

サンプル3(クリックで別ウィンドウで開きます)

秒針が動かせたんだから、Dateオブジェクトを使ってアナログ時計を作れるだろう! と意気込んでやってみましたが、自力では...なかなかうまく描画ができなくて...(苦笑)、
いつもお世話になってるMDNのサンプルを参考にさせていただき、若干アレンジしただけです。(コードはサンプル上で)

最後の「restore();」が2行無いとダメなのが結局理解できず、解明は諦めました。
1行だとダメ。描画が壊れるんですよ。いつかわかる日が来るかな〜?(笑)

Canvasの基礎を学んでみて「ライブラリを活用しよう」と思いました(笑)

さて、今回で Canvasに関しての学習は一段落です。
内容がほぼjavaScriptで「ほんっとに...」の記事としてはムリがありましたが、やってみてオモシロかったです。

Canvasの基本をざっと学んでみてわかったのは、
Canvasは javaScriptの描画部分を強化するモノだということ。
Canvasは、javaScriptでベクター画像を扱えるようにしたり、ビットマップ画像をピクセル単位で操作できたりする画期的なもの。専用ソフト無しでブラウザに描画できるのですから、スゴイですね。

なので、Canvasで単に静的な描画をするだけならあんまり意味が無い。
(Canvasで複雑なグラフィックを作って貼るだけなら、素直にjpgやpngを貼ったほうが軽くて早いですから)
javaScriptで作る動的な表現の中での描画部分に使用されるべきモノ。それがCanvasだと思う。

ということで、
Canvasを使いこなす==javaScriptを使いこなす、というコト。ですので、私のようなjavaScriptに疎い人が気軽に使いこなせるモノではないな...というのが実感です。

デザイナーの守備範囲がプログラミングまで広がるべき時代なのでしょうかね。
天性のデザイナー的素養(ビジュアルセンスや発想力・色彩感覚)と、プログラマー的素養(数学的センス)が、同時に求められるというのは、けっこうハードルが高い気がしますが。

でもね、あきらめるのはまだ早い(笑!)
以前にもご紹介した Canvas用のライブラリ ってモノがあります。

今後、このような「Canvasライブラリ」が増えていき、JavaScriptを使いこなせなくても、ライブラリを使えば Canvasでけっこうなことができるようになるんじゃないかな。たぶん。
これからは、ライブラリを探して活用しようと思っています。
(他力本願ですが。お世話になります!笑)

次回予告

さて次回は、HTML5 の API について調べた事をメモっておきます。
APIって何だろう?なんて思いながら、もうけっこう使ってた。という話です。
Canvasも「Canvas API」というものを利用していろいろ描画していたんですね。

関連記事
このエントリーをはてなブックマークに追加

やる気を保つためにランキングに参加しています。
応援してくださると すっごいやる気を出します! (笑)

初心者にも使いやすい(と思う)レンタルサーバー

「初心者ですがレンタルサーバーはどこがいい?」というご質問をよくいただきます。
自由にファイルをアップロードできる自分のサーバがあると便利ですよね。ローカル環境じゃなくサーバ上で試してみたい時がありますからね。
私が使っているのは、 スターサーバーロリポップ!です。どちらも管理画面がわかりやすく、マニュアルも充実していて、料金も安い。どちらもライトプラン以上で WordPress が使えます。
初心者が始めやすいサーバだと思います。

ちょっと料金は高いけど、さくらのレンタルサーバや、エックスサーバー は、やはり老舗なのでおすすめです。
両方とも高スペックでコスパが良く、老舗でユーザーが多いので、質問する場がたくさんあります。初心者だけど仕事でサーバが欲しい場合は、安心なのではないかと思います。

スポンサーリンク

コメントの投稿

ご注意:メールアドレスは書かないで
「コメントを送信する」ボタンを押した後の「確認画面」で、メールアドレス・URL などを入力できるようになっており、メールアドレス・URL は、そのままオートリンクになる仕様です。
当方でメールアドレスだけ削除することも、メールアドレスを非公開にすることもできません
メールアドレスは書かないでください。詳しくはこちらにまとめましたのでご覧ください。

スポンサーリンク
最新記事
Category
オススメの本
Links
Calendar
11 | 2023/12 | 01
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 - - - - - -
Archive
Profile

yuki★hata

Author : yuki★hata
せめて月1回の更新をめざします~。

メールフォームはこちら

スポンサーリンク
スポンサーリンク
Copyright © ほんっとにはじめてのHTML5とCSS3 All Rights Reserved.