Html5のCanvasAPIのチュートリアルを参考にやってみた・・の2回目です。
目次
前回からの続きの説明
前回はこちらです。
MDNのCanvasAPIのチュートリアル。。
これを参考に、自分なりにCSSにBulmaを使って以下のようなサンプル画面を作ってみました・・というのが前回の話でした。
今回は上記の「チュートリアル03」と「チュートリアル04」についてやります。
前回で書いた内容は再掲しませんので、前回の記事から見てもらう方がわかりやすいとは思います。
JavaScript:ニコニコマークを描く
ニコニコマークを描いてみました・・てやつです。
サンプルとしてチュートリアルに掲載されていた、そのままに近いです。
これを描くソースは以下です。
var c03 = document.getElementById('c03'); if (c03.getContext){ var ctx = c03.getContext("2d") ctx.beginPath(); ctx.arc(75, 75, 50, 0, Math.PI * 2, true); // Outer circle ctx.moveTo(110, 75); ctx.arc(75, 75, 35, 0, Math.PI, false); // Mouth (clockwise) ctx.moveTo(65, 65); ctx.arc(60, 65, 5, 0, Math.PI * 2, true); // Left eye ctx.moveTo(95, 65); ctx.arc(90, 65, 5, 0, Math.PI * 2, true); // Right eye ctx.stroke(); }else{ console.log('canvasオブジェクトがNullです。'); }
pathとかstrokeとかの意味と使い方は、前回の繰り返しになるので特に説明しませんが、移動して(moveTo)そこに円弧を描く(arc) を繰り返しているだけです。
補足は特にありません。
JavaScript:実際に動く丸時計を描く
丸時計を描きます。
秒針も動くちゃんとした時計です。
ちょっと、ソースコード的には長めですが、素のCanvasを使って、ちゃんと動く時計をブラウザに表示できるチュートリアルって、なんか、贅沢感があります(笑)
先に時計を描く、ソースコードです。
function clock(){ var c04 = document.getElementById('c04'); if (c04.getContext){ var now = new Date(); var ctx = c04.getContext("2d") ctx.save(); ctx.clearRect(0, 0, 150, 150); ctx.translate(75, 75); ctx.scale(0.4, 0.4); ctx.rotate(-Math.PI / 2); ctx.strokeStyle = 'black'; ctx.fillStyle = 'white'; ctx.lineWidth = 8; ctx.lineCap = 'round'; // Hour marks ctx.save(); for (var i = 0; i < 12; i++) { ctx.beginPath(); ctx.rotate(Math.PI / 6); ctx.moveTo(100, 0); ctx.lineTo(120, 0); ctx.stroke(); } ctx.restore(); // Minute marks ctx.save(); ctx.lineWidth = 5; for (i = 0; i < 60; i++) { if (i % 5!= 0) { ctx.beginPath(); ctx.moveTo(117, 0); ctx.lineTo(120, 0); ctx.stroke(); } ctx.rotate(Math.PI / 30); } ctx.restore(); var sec = now.getSeconds(); var min = now.getMinutes(); var hr = now.getHours(); hr = hr >= 12 ? hr - 12 : hr; ctx.fillStyle = 'black'; // write Hours ctx.save(); ctx.rotate(hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) *sec); ctx.lineWidth = 14; ctx.beginPath(); ctx.moveTo(-20, 0); ctx.lineTo(80, 0); ctx.stroke(); ctx.restore(); // write Minutes ctx.save(); ctx.rotate((Math.PI / 30) * min + (Math.PI / 1800) * sec); ctx.lineWidth = 10; ctx.beginPath(); ctx.moveTo(-28, 0); ctx.lineTo(112, 0); ctx.stroke(); ctx.restore(); // Write seconds ctx.save(); ctx.rotate(sec * Math.PI / 30); ctx.strokeStyle = '#D40000'; ctx.fillStyle = '#D40000'; ctx.lineWidth = 6; ctx.beginPath(); ctx.moveTo(-30, 0); ctx.lineTo(83, 0); ctx.stroke(); ctx.beginPath(); ctx.arc(0, 0, 10, 0, Math.PI * 2, true); ctx.fill(); ctx.beginPath(); ctx.arc(95, 0, 10, 0, Math.PI * 2, true); ctx.stroke(); ctx.fillStyle = 'rgba(0, 0, 0, 0)'; ctx.arc(0, 0, 3, 0, Math.PI * 2, true); ctx.fill(); ctx.restore(); ctx.beginPath(); ctx.lineWidth = 14; ctx.strokeStyle = '#325FA2'; ctx.arc(0, 0, 142, 0, Math.PI * 2, true); ctx.stroke(); ctx.restore(); window.requestAnimationFrame(clock); }else{ console.log('canvasオブジェクトがNullです。'); } } window.requestAnimationFrame(clock);
時計を描くclock()メソッドをコールバックとして、window.requestAnimationFrame()で動かしています。
よく見るとclock()メソッドの中でも「window.requestAnimationFrame()」を再帰的に実行しています。
このテクニックは自分は知らなかったです。
やや長いですが、clock()メソッドの中で文字盤を描いて、針を描いて・・というのを、コツコツやってるだけなので、じっくり見ると、なんとなくわかります。
内部で、save()とrestore()を使ってます。
この説明だけ見るとピンときませんが、高度なスタックだと考えればいいみたいです。
つまり。
save()を呼び出すたびに、その時点のすべての設定がスタックにプッシュされます。
restore()を呼び出すたびに、最後に保存されたすべての設定が復元されるわけです。
このへん・・頭の中だけでは、なかなかイメージしきれません。
自分も上から少しずつ実行して、その時の画面を見て・・というのを地道にやって初めて「ああ、そういうことか!」とわかりました。
やっぱ、ソースはただ眺めるより、動かしてみたほうが速い・・ですね。
JavaScript:全体の再掲
JavaScript部分だけ、前回と今回をくっつけた全体を再掲しておきます。
demo_p01.js
var c01 = document.getElementById('c01'); if (c01.getContext){ var ctx = c01.getContext("2d") for (var i = 0; i < 6; i++) { for (var j = 0; j < 6; j++) { ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ', ' + Math.floor(255 - 42.5 * j) + ', 0)'; ctx.fillRect(j * 25, i * 25, 25, 25); } } ctx.globalAlpha = 0.2; ctx.fillStyle = '#FFF'; for (var i = 0; i < 7; i++) { ctx.beginPath(); ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true); ctx.fill(); } }else{ console.log('canvasオブジェクトがNullです。'); } var c02 = document.getElementById('c02'); if (c02.getContext){ var ctx = c02.getContext("2d") ctx.font = '48px serif'; ctx.fillText('Hello world', 10, 50); ctx.strokeText('Hello world', 30, 70); ctx.strokeStyle = '#F22' for (var i = 0; i < 5; i++) { ctx.lineWidth = 1 + i; ctx.beginPath(); ctx.moveTo(30,10 * i + 70); ctx.lineTo(300,10 * i + 70); ctx.stroke(); } }else{ console.log('canvasオブジェクトがNullです。'); } var c03 = document.getElementById('c03'); if (c03.getContext){ var ctx = c03.getContext("2d") ctx.beginPath(); ctx.arc(75, 75, 50, 0, Math.PI * 2, true); // Outer circle ctx.moveTo(110, 75); ctx.arc(75, 75, 35, 0, Math.PI, false); // Mouth (clockwise) ctx.moveTo(65, 65); ctx.arc(60, 65, 5, 0, Math.PI * 2, true); // Left eye ctx.moveTo(95, 65); ctx.arc(90, 65, 5, 0, Math.PI * 2, true); // Right eye ctx.stroke(); }else{ console.log('canvasオブジェクトがNullです。'); } function clock(){ var c04 = document.getElementById('c04'); if (c04.getContext){ var now = new Date(); var ctx = c04.getContext("2d") ctx.save(); ctx.clearRect(0, 0, 150, 150); ctx.translate(75, 75); ctx.scale(0.4, 0.4); ctx.rotate(-Math.PI / 2); ctx.strokeStyle = 'black'; ctx.fillStyle = 'white'; ctx.lineWidth = 8; ctx.lineCap = 'round'; // Hour marks ctx.save(); for (var i = 0; i < 12; i++) { ctx.beginPath(); ctx.rotate(Math.PI / 6); ctx.moveTo(100, 0); ctx.lineTo(120, 0); ctx.stroke(); } ctx.restore(); // Minute marks ctx.save(); ctx.lineWidth = 5; for (i = 0; i < 60; i++) { if (i % 5!= 0) { ctx.beginPath(); ctx.moveTo(117, 0); ctx.lineTo(120, 0); ctx.stroke(); } ctx.rotate(Math.PI / 30); } ctx.restore(); var sec = now.getSeconds(); var min = now.getMinutes(); var hr = now.getHours(); hr = hr >= 12 ? hr - 12 : hr; ctx.fillStyle = 'black'; // write Hours ctx.save(); ctx.rotate(hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) *sec); ctx.lineWidth = 14; ctx.beginPath(); ctx.moveTo(-20, 0); ctx.lineTo(80, 0); ctx.stroke(); ctx.restore(); // write Minutes ctx.save(); ctx.rotate((Math.PI / 30) * min + (Math.PI / 1800) * sec); ctx.lineWidth = 10; ctx.beginPath(); ctx.moveTo(-28, 0); ctx.lineTo(112, 0); ctx.stroke(); ctx.restore(); // Write seconds ctx.save(); ctx.rotate(sec * Math.PI / 30); ctx.strokeStyle = '#D40000'; ctx.fillStyle = '#D40000'; ctx.lineWidth = 6; ctx.beginPath(); ctx.moveTo(-30, 0); ctx.lineTo(83, 0); ctx.stroke(); ctx.beginPath(); ctx.arc(0, 0, 10, 0, Math.PI * 2, true); ctx.fill(); ctx.beginPath(); ctx.arc(95, 0, 10, 0, Math.PI * 2, true); ctx.stroke(); ctx.fillStyle = 'rgba(0, 0, 0, 0)'; ctx.arc(0, 0, 3, 0, Math.PI * 2, true); ctx.fill(); ctx.restore(); ctx.beginPath(); ctx.lineWidth = 14; ctx.strokeStyle = '#325FA2'; ctx.arc(0, 0, 142, 0, Math.PI * 2, true); ctx.stroke(); ctx.restore(); window.requestAnimationFrame(clock); }else{ console.log('canvasオブジェクトがNullです。'); } } window.requestAnimationFrame(clock);
HTML 部分は前回の記事を参照ください。
今回はこんなところで。
ではでは。
#JS