やっぱり。JavaScript!- Canvasで時計(1)
上記サイトを参考に時計を作っていきます。まずは外観からですが、基本のHTMLは
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>canvasで時計を作ろう!</title>
</head>
<body>
<canvas id="canvas" width="400" height="400" style="border: solid;"></canvas>
<script src="script.js"></script>
</body>
</html>
とします。ここではCSSとデジタル時計は外しています。
描画に必要な場所の確保
とスクリプトを読み込ませるファイルを指定しています。
これで場所と命令について書けたので一旦HTMLについては終わりにして、別ファイルscript.jsにJavaScriptを書いていきます。
まず、時計の骨格をつく定期ます。円形の枠組みを描画する関数を書きます。
function draw() {
// HTMLに紐付ける命令
const board = document.querySelector("#canvas");
const canvasWidth = canvasHeight = 400;
const context = board.getContext("2d");
// これから使う色の指定
const colorRed = "#FF0000";
const colorBlack = "#000000";
// 長さの定義
const flameR = canvasWidth / 2.5;
const flameLineWidth = 3;
// 円形の枠を描画
context.beginPath();
context.strokeStyle = colorBlack;
context.lineWidth = flameLineWidth;
context.arc(canvasWidth / 2, canvasHeight / 2, flameR, 0, Math.PI * 2, true);
context.stroke();
}
これで
HTMLで指定している四角とJavaScriptで命令している円形が表示されました。
次に時計の時間を示す目盛りを書いていきます。
円形を等分していくために角度をとって分割していきます。その角度はラジアンを使って計算していきます。
角度は普段は0度から360度までの度数法を使っていますがプログラムを組む場合は弧度法(ラジアン)を使います。
ラジアンとは
ということで360度は2πラジアンとなります。
角度ラジアンを求める関数を作ります。
function calcRadian(theta) {
return (Math.PI * 2) * theta;
}
目盛りの長さを定義します
const scaleShortWidth = 1;
const scaleLongWidth = 3;
const scaleShortLength = 0.9;
const scaleLongLength = 0.85;
目盛りを描画します。
目盛りを書く座標の求め方ですが、三角関数を使います。x座標についてはsin()、y座標についてはcos()を使います。単位円あたりの計算式からこの三角関数でx,y座標を簡単に求めることができます。
線は、ペンをmoveTo()で始点へ移動させ、lineTo()で終点まで線を引くという感じです。
ここで描画方法について
中心座標から三角関数で目的座標を求めて移動して、目盛の座標まで線を引きます。長い目盛と短い目盛を条件(5分刻み)でかき分けます。
for (let i = 0; i < 10; i++) {
context.beginPath();
context.strokeStyle = colorBlack;
if (i % 5 === 0) {
// 5分刻み:長い目盛り
context.lineWidth = scaleLongWidth;
context.moveTo(canvasWidth / 2 + (Math.cos(calcRadian(i / 60)) * flameR) * scaleLongLength, canvasHeight / 2 + (Math.sin(calcRadian(i / 60)) * flameR) * scaleLongLength);
} else {
// それ以外:短い目盛り
context.lineWidth = scaleShortWidth;
context.moveTo(canvasWidth / 2 + (Math.cos(calcRadian(i / 60)) * flameR) * scaleShortLength, canvasHeight / 2 + (Math.sin(calcRadian(i / 60)) * flameR) * scaleShortLength);
}
context.lineTo(canvasWidth / 2 + (Math.cos(calcRadian(i / 60)) * flameR), canvasHeight / 2 + (Math.sin(calcRadian(i / 60)) * flameR));
context.stroke();
目盛りがひとまず書けましたが頂点が思ったとことは違うので少し回転させたいです。
canvasのxy座標系は左上が0で、xは右、yは下へ向かう座標となりので45度回転させると頂点からスタートとなるので2πが360度なので90度は1/2πとなるので、"Math.PI / 2"を引いてやります。
function calcRadian(theta) {
return (Math.PI * 2) * theta - Math.PI / 2;
}
として再度表示してみると
うまくいきました。あとは繰り返しの部分を
としてやれば円の周囲全てに目盛りが付きます。