Thứ bảy, ngày 25 tháng 11 năm 2017

HTML5 – Canvas: Vẽ đồng hồ kim (analog clock)

Ngày đăng: 20/4/2012, 8:21:5PM | Lượt xem: 6,355
Hot!

Hướng dẫn cách vẽ đồng hồ kim với requestAnimationFrame trong Canvas. Xem Demo.

Canvas - Simple Analog ClockHướng dẫn cách vẽ đồng hồ kim với requestAnimationFrame trong Canvas.
Xem Demo.

Công việc cần làm của ứng dụng này là lấy thời gian và vẽ ra các kim đồng hồ. Thông thường, lập trình viên sẽ dùng các công thức lượng giác để tính ra được góc và vị trí của kim. Cách làm này tuy hiệu quả và nhanh nhưng các kim đồng hồ sẽ khó thay đổi và thường chỉ là các đường thẳng đơn giản. Vậy, nếu muốn làm một đồng hồ đẹp mắt, hãy sử dụng các phương thức biến đổi của context (rotate, translate,…).
Trong ví dụ này, tôi sẽ hướng dẫn theo cách thông thường: sử dụng các công thức lượng giác.

Hai hàm vẽ cơ bản

// draw a line from {x1, y1} to {x2,y2}
function drawLine(x1,y1,x2,y2,lineWidth,color){
	context.save();
	context.lineWidth = lineWidth;
	if(color)
		context.strokeStyle = color;
	context.beginPath();
	context.moveTo(x1,y1);
	context.lineTo(x2, y2);
	context.closePath();
	context.stroke();
	context.restore();
}
// draw a circle with the center at {cx, cy}
function drawCircle(cx,cy,radius){
	context.beginPath();
	context.arc(cx,cy, radius, 0, Math.PI*2, true);
	context.closePath();
	context.fill();
}

Vẽ mặt đồng hồ

Tôi sẽ vẽ các điểm tròn quanh vành đồng hồ, mỗi điểm tương ứng với bước di chuyển của kim giây và phút, như vậy ta có tất cả 60 điểm. Chia 360° của vòng tròn thành 60 phần, mỗi phần sẽ có 6°. Từ mỗi độ này, ta có thể tính được tọa độ của điểm cần vẽ với độ lớn là 1 thông qua hai hàm sin và cos.

for(var i=0;i<60;i++){
	var angle = 6*i*ONE_RADIAN;
	var x = cx + Math.cos(angle)*CLOCK_RADIUS;
	var y = cy + Math.sin(angle)*CLOCK_RADIUS;
	drawCircle(x,y,2);
}

Để làm nổi bật các vị trí chỉ giờ, tôi sẽ thay đổi radius của các điểm tròn. Do một giờ có 12 tiếng nên tôi lấy 60/12 = 5 để xác định các điểm chỉ giờ:

for(var i=0;i<60;i++){
	var radius = i%5==0?3:1;
	var angle = 6*i*ONE_RADIAN;
	var x = cx + Math.cos(angle)*CLOCK_RADIUS;
	var y = cy + Math.sin(angle)*CLOCK_RADIUS;
	drawCircle(x,y,radius);
}

Canvas -Drawing Clock Dial

Cuối cùng là các số chỉ giờ lên mặt đồng hồ. Từ vòng lặp i, ta có thể tính được giờ bằng cách chia nguyên cho 5. Tuy nhiên, vì góc 0° nằm ở vị trí 3 giờ và độ lớn tăng theo ngược chiều kim đồng hồ nên công thức được tính sẽ là: hour = (i/5+3)%12. Phép tính này cho kết quả là 0 tại vị trí 12 giờ, nên ta cần thêm một câu điều kiện nữa để chuyển nó về 12.

for(var i=0;i<60;i++){
	var angle = 6*i*ONE_RADIAN;
	var x = cx + Math.cos(angle)*CLOCK_RADIUS;
	var y = cy + Math.sin(angle)*CLOCK_RADIUS;
	var radius = 1;
	if(i%5==0)
	{
		radius = 3;
		var hour = (i/5+3)%12;
		if(hour == 0)
			hour = 12;

		// text width
		var tw = context.measureText(hour).width;
		// text location
		var tx = cx + Math.cos(angle)*SECOND_HAND_SIZE-tw/2;
		var ty = cy + Math.sin(angle)*SECOND_HAND_SIZE+6;

		context.fillText(hour,tx,ty);
	}

	drawCircle(x,y,radius);
}

Canvas Clock Dial

Vẽ các kim đồng hồ

Đối với kim giây/phút, ta sẽ một đường thẳng từ điểm bắt đầu là tâm đồng hồ đến một điểm đích tính được dựa thời gian hiện tại. Cách tính tọa độ điểm đích tương tự như phần trên, mỗi kim được xác định độ dài dựa vào hai hằng: SECOND_HAND_SIZE và MINUTE_HAND_SIZE.
Với kim giờ, để nó có thể di chuyển vào khoảng giữa hai giờ (ví dụ 2h30′) ta cần cộng với độ lớn của phút. Tức là 2h30′ = 2 + 30/60 = 2.5h. Mỗi giờ chiếm một góc 30°, vậy ta có:

var now = new Date();
var hours = now.getHours();
var minutes = now.getMinutes();
var seconds = now.getSeconds();

// second hand
var angle = ONE_RADIAN*seconds*6;
var x = cx + Math.sin(angle)*SECOND_HAND_SIZE;
var y = cx - Math.cos(angle)*SECOND_HAND_SIZE;
drawLine(cx,cy,x,y,1);

// minute hand
angle = ONE_RADIAN*minutes*6;
x = cx + Math.sin(angle)*MINUTE_HAND_SIZE;
y = cx - Math.cos(angle)*MINUTE_HAND_SIZE;
drawLine(cx,cy,x,y,2,"blue");

// hour hand
angle = ONE_RADIAN * (hours+minutes/60)*30;
x = cx + Math.sin(angle)*HOUR_HAND_SIZE;
y = cx - Math.cos(angle)*HOUR_HAND_SIZE;
drawLine(cx,cy,x,y,4,"#900000");

Canvas - Simple Analog Clock

Mã nguồn hoàn chỉnh

<html>
<head>
  <script>
	const ONE_RADIAN = Math.PI/180;
	const CLOCK_RADIUS = 100;
	const SECOND_HAND_SIZE = CLOCK_RADIUS * 0.9;
	const MINUTE_HAND_SIZE = CLOCK_RADIUS * 0.7;
	const HOUR_HAND_SIZE = CLOCK_RADIUS * 0.5;
	var cx;
	var cy;
	var canvas;
	var context;
	var _animationFrame;
	var _startTime;

	function loop(time) {
		var diffTime = Math.abs(time - _startTime);
		if(diffTime >= 1000)
		{
			update();
			_startTime = time;
		}

		_animationFrame(loop);
	}
	// draw a line from {x1, y1} to {x2,y2}
	function drawLine(x1,y1,x2,y2,lineWidth,color){

		context.save();
		context.lineWidth = lineWidth;
		if(color)
			context.strokeStyle = color;
		context.beginPath();
		context.moveTo(x1,y1);
		context.lineTo(x2, y2);
		context.closePath();
		context.stroke();
		context.restore();
	}
	// draw a circle with the center at {cx, cy}
	function drawCircle(cx,cy,radius){
		context.beginPath();
		context.arc(cx,cy, radius, 0, Math.PI*2, true);
		context.closePath();
		context.fill();
	}

	function update(){

		context.clearRect(0, 0, canvas.width, canvas.height);

		// draw clock dial
		drawCircle(cx,cy,4);

		for(var i=0;i<60;i++){
			var angle = 6*i*ONE_RADIAN;
			var x = cx + Math.cos(angle)*CLOCK_RADIUS;
			var y = cy + Math.sin(angle)*CLOCK_RADIUS;
			var radius = 1;
			if(i%5==0)
			{
				radius = 3;
				var hour = (i/5+3)%12;
				if(hour == 0)
					hour = 12;

				// text width
				var tw = context.measureText(hour).width;
				// text location
				var tx = cx + Math.cos(angle)*SECOND_HAND_SIZE-tw/2;
				var ty = cy + Math.sin(angle)*SECOND_HAND_SIZE+6;

				context.fillText(hour,tx,ty);
			}

			drawCircle(x,y,radius);
		}

		// draw clock hands ////////////////////////////////////

		var now = new Date();
		var hours = now.getHours();
		var minutes = now.getMinutes();
		var seconds = now.getSeconds();

		// second hand
		var angle = ONE_RADIAN*seconds*6;
		var x = cx + Math.sin(angle)*SECOND_HAND_SIZE;
		var y = cx - Math.cos(angle)*SECOND_HAND_SIZE;
		drawLine(cx,cy,x,y,1);

		// minute hand
		angle = ONE_RADIAN*minutes*6;
		x = cx + Math.sin(angle)*MINUTE_HAND_SIZE;
		y = cx - Math.cos(angle)*MINUTE_HAND_SIZE;
		drawLine(cx,cy,x,y,2,"blue");

		// hour hand
		angle = ONE_RADIAN * (hours+minutes/60)*30;
		x = cx + Math.sin(angle)*HOUR_HAND_SIZE;
		y = cx - Math.cos(angle)*HOUR_HAND_SIZE;
		drawLine(cx,cy,x,y,4,"#900000");
	}

	window.onload = function(){
		canvas  = document.getElementById("canvas");
		context = canvas.getContext("2d");
		context.font = "14px Arial";
		cx = canvas.width/2;
		cy = canvas.height/2;
		_animationFrame = window.requestAnimationFrame 	||
					window.mozRequestAnimationFrame		||
					window.webkitRequestAnimationFrame	||
					window.msRequestAnimationFrame		||
					window.oRequestAnimationFrame		;

		if(_animationFrame)
		{
			_startTime = Date.now();
			_animationFrame(loop);
		}
		else
			alert("Your browser don't support requestAnimationFrame.");
	};
  </script>
</head>
<body>
<canvas id="canvas" width="400px" height="400px" style="border: 1px solid"></canvas>

</body>
</html>

YinYang’s Programming Blog

 Chia sẻ qua: 
Hot!
Ý kiến bạn đọc

These items will be permanently deleted and cannot be recovered. Are you sure?

Gallery

image

Maecenas viverra rutrum pulvinar

Maecenas viverra rutrum pulvinar! Aenean vehicula nulla sit amet metus aliquam et malesuada risus aliquet. Vestibulum rhoncus, dolor sit amet venenatis porta, metus purus sagittis nisl, sodales volutpat elit lorem…

Read more

Text Links

Thiết kế logo chuyên nghiệp Insky
DAFABET
W88 w88b.com/dang-ky-tai-khoan-w88
W88
ca do bong da online
Copyright © 2011 - 2012 vietshare.vn by phamkhuong102@gmail.com doanhkisi2315@gmail.com. All rights reserved.