今年も残りあと1ヶ月。
新しいことをはじめようと意気込んだこの一年、結局、例年とあまり変わらない一年で終わりそうなので、来年につなげられるよう、しばらく中断していた記事を日々書いていこうと思います。
『息子に教えるJavaScript』と銘打って書き始めたものの、教えたいことがたくさんありすぎて、思いばかりが先に行ってしまっています。
コンピュータ、算数、科学・・・。少なくとも、自分が学んできたことの多くを息子に教えたい。本当に学ぶべきことは、もっと先にあるのだから、基礎となる部分だけでも教えられればと思います。
本Blogは、プログラミングを通して息子にコンピュータを教えたいという思いで書きはじめました。コンピュータの使い方は様々ですが、仕組みを理解するという点でプログラミングを学んでほしいと考え、身近なブラウザ上で動かせるJavaScriptを教えることにしました。
今回は、Canvasを使ったサンプルはないかと部屋を見渡したところ、たまたま時計が目に入ったので、アナログ時計を表示してみたいと思います。
あまり綺麗なソースではありませんが、細かいことは気にせずに、習うより慣れろ式に、短めのサンプルを例に挙げて、教えるきっかけになればと考えています。
リスト16: lesson16.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Lesson16 Clock</title>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
canvas {
position: absolute;
}
</style>
</head>
<body>
<canvas id="myCanvas"></canvas>
<script>
function drawClock() {
let canvas = document.getElementById("myCanvas");
let context = canvas.getContext("2d");
let width = canvas.width;
let height = canvas.height;
let radius = Math.min(width, height) / 2.0 * 0.8;
let cx = width / 2;
let cy = height / 2;
// Time
let date = new Date();
let hour = date.getHours() % 12;
let minute = date.getMinutes();
let second = date.getSeconds();
// Clear canvas
context.beginPath();
context.fillStyle = "white";
context.fillRect(0, 0, width, height);
// Circle
context.beginPath();
context.arc(cx, cy, radius, 0, Math.PI * 2, true);
context.strokeStyle = "black";
context.lineWidth = 5;
context.stroke();
// Numbers
let hours = ["Ⅻ","Ⅰ","Ⅱ","Ⅲ","Ⅳ","Ⅴ","Ⅵ","Ⅶ","Ⅷ","Ⅸ","Ⅹ","Ⅺ"];
context.beginPath();
context.textAlign = "center";
context.textBaseline = "middle";
context.font = Math.floor(radius * 0.15) + "px 'MS 明朝'";
context.fillStyle = "black";
for (let index in hours) {
let radiusNumber = radius * 0.85;
let thetaNumber = (2 * Math.PI / 12 ) * index;
let posNumber = calcPosition(cx, cy, radiusNumber, thetaNumber);
context.fillText(hours[index], posNumber.x, posNumber.y);
}
// Hour hand
let radiusHour = radius * 0.7;
let thetaHour = (2 * Math.PI / 12 ) * (hour + minute / 60 + second / 3600);
let posHour = calcPosition(cx, cy, radiusHour, thetaHour);
context.beginPath();
context.moveTo(cx, cy);
context.lineTo(posHour.x, posHour.y);
context.lineWidth = 4;
context.stroke();
// Minute hand
let radiusMinute = radius * 0.9;
let thetaMinute = (2 * Math.PI / 60) * (minute + second / 60);
let posMinute = calcPosition(cx, cy, radiusMinute, thetaMinute);
context.beginPath();
context.moveTo(cx, cy);
context.lineTo(posMinute.x, posMinute.y);
context.lineWidth = 3;
context.stroke();
// Second hand
let radiusSecond = radius * 0.9;
let thetaSecond = (2 * Math.PI / 60) * second;
let posSecond = calcPosition(cx, cy, radiusSecond, thetaSecond);
context.beginPath();
context.moveTo(cx, cy);
context.lineTo(posSecond.x, posSecond.y);
context.strokeStyle = "red";
context.lineWidth = 1;
context.stroke();
// Invoke when second changed
setTimeout(drawClock, 1000 - date.getMilliseconds());
}
function calcPosition(cx, cy, radius, theta) {
return {
x: cx + (radius * Math.sin(theta)),
y: cy - (radius * Math.cos(theta))
};
}
function resize() {
let canvas = document.getElementById("myCanvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
drawClock();
}
window.addEventListener("resize", resize, false);
window.addEventListener("load", resize, false);
</script>
</body>
</html>