SOFTELメモ

</> 技術者募集

【JavaScript】canvasでアナログ時計

問題

canvasでアナログ時計って作れる?

html5-canvas-analog-clock

答え

作りましょう。

今回は、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>

メモ

関連するメモ

コメント