質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

Q&A

解決済

3回答

8893閲覧

Canvasで複数の箇所に同一アニメーションを設置する方法

kkrg24

総合スコア7

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

0グッド

1クリップ

投稿2017/04/26 17:48

###前提・実現したいこと
Canvasを使った波のアニメーションを実装したいと考えています。
実装することはできたのですが、これを同じページに複数設置する場合、
どう修正したら良いのかご教示いただきたいです。
(類似の質問は見つけたのですが、私には難しく…)

具体的には下記の項目を実現したいと思っています。

  • 同一アニメショーンのCanvasを同一ページに複数設置したい。
  • 色をCanvas毎に変更したい。

###該当のソースコード
下記のサイトを参考にしています。
http://sterfield.co.jp/designer/canvasで波のアニメーションを描画する/
→デモ
http://sterfield.co.jp/demo/ninomiya/104/index2.html

html

1<canvas id="sineCanvas" width="800" height="300"></canvas>

javascript

1(function () { 2 3var unit = 100, 4 canvas, context, canvas2, context2, 5 height, width, xAxis, yAxis, 6 draw; 7 8/** 9 * Init function. 10 * 11 * Initialize variables and begin the animation. 12 */ 13function init() { 14 15 canvas = document.getElementById("sineCanvas"); 16 17 canvas.width = document.documentElement.clientWidth; //Canvasのwidthをウィンドウの幅に合わせる 18 canvas.height = 300; 19 20 context = canvas.getContext("2d"); 21 22 height = canvas.height; 23 width = canvas.width; 24 25 xAxis = Math.floor(height/2); 26 yAxis = 0; 27 28 draw(); 29} 30 31/** 32 * Draw animation function. 33 * 34 * This function draws one frame of the animation, waits 20ms, and then calls 35 * itself again. 36 */ 37function draw() { 38 39 // キャンバスの描画をクリア 40 context.clearRect(0, 0, width, height); 41 42 //波を描画 43 drawWave('#10c2cd', 0.3, 3, 0); 44 drawWave('#43c0e4', 0.4, 2, 250); 45 drawWave('#1d82b6', 0.2, 1.6, 100); 46 47 // Update the time and draw again 48 draw.seconds = draw.seconds + .014; 49 draw.t = draw.seconds*Math.PI; 50 setTimeout(draw, 35); 51}; 52draw.seconds = 0; 53draw.t = 0; 54 55/** 56* 波を描画 57* drawWave(色, 不透明度, 波の幅のzoom, 波の開始位置の遅れ) 58*/ 59function drawWave(color, alpha, zoom, delay) { 60 context.fillStyle = color; 61 context.globalAlpha = alpha; 62 63 context.beginPath(); //パスの開始 64 drawSine(draw.t / 0.5, zoom, delay); 65 context.lineTo(width + 10, height); //パスをCanvasの右下へ 66 context.lineTo(0, height); //パスをCanvasの左下へ 67 context.closePath() //パスを閉じる 68 context.fill(); //塗りつぶす 69} 70 71/** 72 * Function to draw sine 73 * 74 * The sine curve is drawn in 10px segments starting at the origin. 75 * drawSine(時間, 波の幅のzoom, 波の開始位置の遅れ) 76 */ 77function drawSine(t, zoom, delay) { 78 79 // Set the initial x and y, starting at 0,0 and translating to the origin on 80 // the canvas. 81 var x = t; //時間を横の位置とする 82 var y = Math.sin(x)/zoom; 83 context.moveTo(yAxis, unit*y+xAxis); //スタート位置にパスを置く 84 85 // Loop to draw segments (横幅の分、波を描画) 86 for (i = yAxis; i <= width + 10; i += 10) { 87 x = t+(-yAxis+i)/unit/zoom; 88 y = Math.sin(x - delay)/3; 89 context.lineTo(i, unit*y+xAxis); 90 } 91} 92 93init(); 94 95})();

###試したこと
値を変更・削除したり、類似のものを流用してみたりしましたが、
どうも関数に弱く、丸一日作業が止まってしまいました。

丸投げに近い形で大変心苦しいのですが、
どうぞご教示のほどよろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masaya_ohashi

2017/04/27 00:48

同ページに複数、というのはcanvasがたくさん並んでいる状態ですか?それとも1つのcanvasの中に沢山の波がある状態ですか?
kkrg24
kei344

2017/04/27 01:43

この「質問への追記・修正の依頼」の部分はデフォルトで表示されませんので、「類似の質問」に関して質問本文に追記することをお勧めします。
guest

回答3

0

ベストアンサー

動作サンプル
https://jsfiddle.net/39we73t1/

まず複数のcanvasがあるので、グローバル変数で全部賄うことはかなり複雑になります。なので、基準となるCanvasを各関数に渡していくことで、「このCanvasに対して処理をする」ことを明確にします。各functionに引数の先頭にcanvasが追加されているのがわかりますね?各関数の中でも、いままでグローバルで1個しかなかったwidth等がcanvasから取られています。これで「このcanvasに対してdrawWave、drawSineの処理をするぞ」というのが分かるようになります。contextも毎回canvasに持たせたcontextCacheを使うことで、このcanvasのcontextであることが分かります。

次に、1回の更新で複数のCanvasを描画するため、「更新処理」と「描画処理」を分離します。updateとdrawという関数に処理を分離しました。時間の計算とかは複数枚ごとにやっちゃうとおかしいですよね?なので1回の処理で1回しかしないでよい処理は更新処理に、各canvasごとにやらなきゃいけない処理はdraw以下に書きます。

canvasごとに色が変えたいのであれば、その色情報を持っていないといけません。colorListにその情報が入っています。描画する際に、canvasごとの色情報を渡してやることで色を変えて処理をすることができるようになっています。

投稿2017/04/27 01:44

編集2017/04/27 01:52
masaya_ohashi

総合スコア9206

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2017/04/27 01:49

jsfiddleってわかりやすいですね!
masaya_ohashi

2017/04/27 01:53

軽い動作テストとかにも重宝してます。これでタダなんですから世の中よくなったものです。
kkrg24

2017/04/27 06:13

動作サンプルまで作成いただき、とてもわかりやすく丁寧にまとめていただきました。これをきっかけに、もっとcanvasへの理解を深めていきたいと思います。この度はご回答いただきありがとうございました。
guest

0

どうも関数に弱く

というよりはforループによる繰り返しや配列の利用のコードの実装イメージを持てないということかと思います。あるいはこのサンプルが何をしているかコードから読み取れていないといったところではないでしょうか。その状態ですと変更コードそのものの回答しか質問者さんにはうれしくないということになるかも知れませんが・・・

例えばdrawなら次のようになるでしょう。多少コメントは付けておきました。
まずはできる限り「コードの中で何をしているか」を読み取ってみてください。
for文や配列、オブジェクトリテラルの書き方も(もし曖昧なら)調べて理解するようにしましょう。

javascript

1//それぞれのキャンバスに関する必要な情報(idや色)を配列に入れておく 2var waveParameters = [ 3 { id: 'sineCanvas1', // キャンバスのid 4 waveColor1: '#10c2cd', // 波の色-1 5 waveColor2: '#43c0e4', // 波の色-2 6 waveColor3: '#1d82b6' // 波の色-3 7 }, 8 { id: 'sineCanvas2', // キャンバスのid 9 ... 10 }]; 11 12function draw() { 13 // 複数のキャンバスに対してパラメータを変えながら描画 14 for (var wp in waveParameters) { 15 // キャンバスと描画コンテキストを求める 16 var canvas = document.getElementById(wp.id); 17 var context = canvas.getContext("2d"); 18 // 波を描画 19 drawWave(wp.waveColor1, 0.3, 3, 0); 20 drawWave(wp.waveColor2, 0.4, 2, 250); 21 drawWave(wp.waveColor3, 0.2, 1.6, 100); 22 } 23 // 次回の描画のために波の位置を変化させる 24 // 35msecごとに0.014/180度だけ角度を変化させる 25 draw.seconds = draw.seconds + .014; 26 draw.t = draw.seconds*Math.PI; 27 // 35msec後に再度この関数を起動 28 setTimeout(draw, 35); 29}

html

1<canvas id="sineCanvas1"> ...</canvas> 2<canvas id="sineCanvas2"> ...</canvas> 3...

なお、実装にはバリエーションがありますので、人それぞれで違ってくると思います。

投稿2017/04/27 01:10

編集2017/04/27 01:48
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kkrg24

2017/04/27 05:59

ご回答くださりありがとうございました。まさにコメントしていただいた通りで、お恥ずかしい限りです。また、ただコピペして記載してしまったのも、回答してくださった方に失礼でした。for文や配列など、まずは意味や役割などをしっかりと理解し、ご回答いただいた方法でも試してみたいと思います。
KSwordOfHaste

2017/04/27 06:01

何を作るせよ、基本的なところがわかってくると世界が広がるのでそれだけコードも書きやすく、おもしろくなってきますよ!頑張ってください。
guest

0

とりあえず変数を配列にして

JavaScript

1var waves = [{ 2 id: 'sineCanvas1', 3 cols: ['#10c2cd', '#43c0e4', '#1d82b6'], 4 canvas: null, 5 context: null, 6 unit: 100, 7 height: 300, 8 width: document.documentElement.clientWidth, 9 xAxis: 0, 10 yAxis: 0, 11 draw: { 12 seconds: 0, 13 t: 0 14 } 15},//...以下同様 16`````for``文で回すって感じですかね… 17```JavaScript 18function init() { 19 for (var i = 0; i < waves.length; i++) { 20 var wave = waves[i]; 21 wave.canvas = document.getElementById(wave.id); 22 wave.context = wave.canvas.getContext("2d"); 23 wave.xAxis = Math.floor(wave.height / 2); 24 wave.yAxis = 0; 25 switch(i){ 26 case 0: draw0();break; 27 case 1: draw1();break; 28 } 29 } 30}

すみません間違って途中で投稿してしまいました。
再帰は使い回しができない?ので、表示するcanvas要素の数だけdraw()を書いてます。
カッコ悪いですが、動かすだけなら動きます。

投稿2017/04/27 01:44

編集2017/04/27 01:51
NS-DOS

総合スコア110

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kkrg24

2017/04/27 06:08

ゴールに辿り着くまでに様々な考え方があるのだとわかりました。「カッコ悪い」とありますが、1番シンプルな考え方なのかなと思います。まだ理解力が乏しいため、お礼のみとなりますが、改めましてご回答いただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問