【JavaScript】canvasでアナログ時計
問題
canvasでアナログ時計って作れる?

答え
作りましょう。
今回は、1つのcanvas要素を用いて、1秒ごとに時計全体を書き直す形で実装する。
canvasは、ほぼWindows付属のペイントの表示領域のようなものと考えてよく、一度描画した図形を再取得して描画しなおしたり、位置をずらしたり、回転したりといったことはできない。フォトショップで言うレイヤーのようなものはなく、canvasが1つしかないなら、毎秒書き直すのがよくある実装だと思う。
時計の表示には以下の要素が考えられる、
- 文字盤
- 背景
- 時間の目盛り
- 分の目盛り
- 時針
- 分針
- 秒針
シンプルな時計を作るので、文字盤や背景は省略する。
時間の目盛り、分の目盛りはいつも固定位置に、時針、分針、秒針は時刻に応じた位置に表示する。
それぞれの描画メソッドをつくり、タイマーで1秒おきに更新できる仕組みを作ったら出来上がり。
Demo
Source
<canvas id="sample20130319" width="200" height="200"></canvas>
<script>
function clock(id){
this.id = id;
this.init = function(){
this.timerId = null;
this.canvas = document.getElementById(this.id);
this.ctx = this.canvas.getContext('2d');
this.width = this.canvas.width;
this.height = this.canvas.height;
var x = this.ctx;
x.translate(this.width / 2, this.height / 2);
x.scale(this.width / 200, this.height / 200);
x.rotate(-Math.PI/2);
x.strokeStyle = "black";
x.fillStyle = "white";
x.lineCap = "butt";
}
this.memoriM = function(){
var x = this.ctx;
x.save();
x.lineWidth = 2;
for (var i = 0; i < 60; i++) {
x.beginPath();
x.rotate(Math.PI/30);
x.moveTo(90,0);
x.lineTo(100,0);
x.stroke();
}
x.restore();
}
this.memoriH = function(){
var x = this.ctx;
x.save();
x.lineWidth = 8;
for (var i = 0; i < 12; i++) {
x.beginPath();
x.rotate(Math.PI/6);
x.moveTo(80,0);
x.lineTo(100,0);
x.stroke();
}
x.restore();
}
this.h = function(){
var x = this.ctx;
x.save();
x.rotate(Math.PI/6 * (this.datetime.getHours() + this.datetime.getMinutes() / 60));
x.lineWidth = 8;
x.beginPath();
x.moveTo(-5, 0);
x.lineTo(60, 0);
x.stroke();
x.restore();
}
this.m = function(){
var x = this.ctx;
x.save();
x.rotate(Math.PI/30 * (this.datetime.getMinutes() + this.datetime.getSeconds() / 60));
x.lineWidth = 4;
x.beginPath();
x.moveTo(-5, 0);
x.lineTo(80, 0);
x.stroke();
x.restore();
}
this.s = function(){
var x = this.ctx;
x.save();
x.rotate(Math.PI/30 * this.datetime.getSeconds());
x.strokeStyle = "#cc0000";
x.lineWidth = 2;
x.beginPath();
x.moveTo(-10, 0);
x.lineTo(80, 0);
x.stroke();
x.restore();
}
this.ticktack = function(){
if (!this.canvas) {
this.init();
}
this.datetime = new Date();
var x = this.ctx;
x.clearRect(-100, -100, 200, 200);
this.memoriM();
this.memoriH();
this.h();
this.m();
this.s();
}
this.start = function(){
if (!this.timerId) {
var _clock = this;
_clock.ticktack();
this.timerId = setInterval(function(){_clock.ticktack();}, 1000);
}
}
this.stop = function() {
if (this.timerId) {
clearInterval(this.timerId);
this.timerId = null;
}
}
}
//開始処理(jQueryがないときはwindow.onloadなどで)
$(function(){
var x = new clock('sample20130319');
x.start();
});
</script>
メモ
- canvasの操作に関してはjQueryはあまり役に立たないので、開始の処理のところでしか使っていない。canvas操作のライブラリも使っていないので、ほぼ素のJavaScript。
- アナログ時計の場合、canvasのrotateを利用すると、円形に目盛りを並べたり、指定の角度で針を描画するのが簡単に書ける。
- 機能は現在時刻の表示のみとして作っているので、ボタンを押したら開始したいとか、指定の時刻を表示させたいといった場合は、もう一工夫必要。
- 拡大、縮小(scale)も利用すると、canvasの大きさに応じた表示が簡単にできる。
- 背景に画像を使うと、だいぶイメージの違うアナログ時計ができるでしょう。目盛りも背景に含めてしまうと、いちいちか描かなくてよくなって、プログラムもすっきりするでしょう。