Posts Javascript HTML5 Canvas 时钟绘制
Post
Cancel

Javascript HTML5 Canvas 时钟绘制

我这里采用 JavascriptHTML5 Canvas API 来进行 Graphic2D 的绘制,主要利用数学的三角函数与圆有关的公式来达到目的,其实最主要是通过实际练习并对这些数学公式进行深入掌握;也希望能够帮助大伙儿明白其中的原理,我尽量用比较详细的方式进行编写这篇博文。

效果图

IMAGE

数学知识

  1. 圆的弧度与角度的关系,以及圆的基础知识。 圆周率(π) = 圆周长 / 圆直径(周长与直径的比值);在计算机领域的数学公式计算坐标都是根据弧度为单位进行计算,那我们在计算时就需要把角度转弧度;角度转弧度的根本原理 —— 圆周率就是180°角的弧度,那么角度转弧度公式可以为:角度 / 180° * π,而弧度转角度:弧度 / π * 180°。

  2. 什么是余弦值与正弦值、正切值。 IMAGE 按以上图为例,已知直角三角形AC、AB、BC的长度,想要获取“a”弧度值,咱们可以利用三种方式进行获取,余弦值 —— 对边/斜边(即AB/AC),正弦值 —— 临边/斜边(即BC/AC),正切值 —— 临边/对边(即BC/AB);在数学中如果知道相应的值后可以利用查表的方式得出弧度;计算机中可以利用反函数获取弧度。

相关注意事项: 在计算机中不管是余弦值、正弦值、正切值都有对应的反余弦值、反正弦值、反正切值函数,而函数返回的内容就是咱们需要的弧度/角度值;

计算机Math函数列表

● Math.sin —— 正弦值获取函数 ● Math.cos —— 余弦值获取函数 ● Math.tan —— 正切值获取函数 ● Math.asin —— 反正弦值函数获取弧度 ● Math.acos —— 反余弦值函数获取弧度 ● Math.atan —— 反正切值函数获取弧度 ● Math.atan2 —— 这个函数是计算机特有的升级版反正切函数,应用数学中不存在这种说法,只需要传入一条射线从A点到B点的对应位置即可获取到咱们想要的弧度;如上图:“a”的弧度 = Math.atan2(C坐标,A坐标)。

核心代码

以下相关的代码使用了 JQuery,如果需要运行起来则需要在HTML里面导入JQuery相关的库,然后再把以下语句拷贝至单独JS文件或HTML中。此份代码可以通过我的 Github 地址进行获取:https://github.com/caryyu/clock

画圆与旋转指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Clock = function(){
	var jCanvas = $('<canvas width="450" height="300">');
	//jCanvas.on('mousemove',onMousemove);
	$(document.body).append(jCanvas);
	this.canvas = jCanvas[0];
	this.ctx = this.canvas.getContext('2d');
	this.ctx.strokeStyle = 'red';
	this.ctx.fillStyle = 'red';
	this.rect = {w:this.canvas.width,h:this.canvas.height,x:0,y:0};
	this.radius = 50;
	this.count = 0;
	this.interval = 100;
};

Clock.prototype = {
	drawing : function(){
		var radius = this.radius;
		var rx = radius;
		var ry = radius;
		//Core Drawing
		this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
		this.ctx.beginPath();
		this.ctx.arc(rx,ry,radius,0,2 * Math.PI);
		var radian = (Math.PI * 2 / 12) * this.count;
		var x = Math.cos(radian) * radius;
		var y = Math.sin(radian) * radius;
		this.ctx.moveTo(rx,ry);
		this.ctx.lineTo(rx + x , ry + y);
		this.ctx.stroke();
		//Counting for drawing
		this.count++;
		if(this.count > 12){this.count = 1}
	},
	start : function(){
		setInterval($.proxy(this.drawing,this),this.interval);
	}
};

function globalToLocal(canvas, x, y) {
  var bbox = canvas.getBoundingClientRect();
  var x = x - bbox.left * (canvas.width / bbox.width);
	var y = y - bbox.top  * (canvas.height / bbox.height);
	return {x: x, y : y};
}


$(function(){
	var c = new Clock();
	c.start();
});

时钟标记绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
Clock = function(){
	var jCanvas = $('<canvas width="450" height="300">');
	//jCanvas.on('mousemove',onMousemove);
	$(document.body).append(jCanvas);
	this.canvas = jCanvas[0];
	this.ctx = this.canvas.getContext('2d');
	this.ctx.strokeStyle = 'red';
	this.ctx.fillStyle = 'red';
	this.rect = {w:this.canvas.width,h:this.canvas.height,x:0,y:0};
	this.radius = 50;
	this.count = 1;
	this.interval = 200;
};

Clock.prototype = {
	drawingMarks : function(){
		var radius = this.radius;
		var rx = radius;
		var ry = radius;
		//Hour Wheel Marks
		for(var i=1;i<=12;i++){
			var radian = (Math.PI * 2 / 12) * i;
			var p1 = this.getPoint(radian,radius - 8);
			var p2 = this.getPoint(radian,radius);
			this.ctx.moveTo(rx + p1.x , ry + p1.y);
			this.ctx.lineTo(rx + p2.x , ry + p2.y);
		}
		//Minute Wheel Marks
		for(var j=1;j<=60;j++){
			var radian = (Math.PI * 2 / 60) * j;
			var p1 = this.getPoint(radian,radius - 3);
			var p2 = this.getPoint(radian,radius);
			this.ctx.moveTo(rx + p1.x , ry + p1.y);
			this.ctx.lineTo(rx + p2.x , ry + p2.y);
		}
	},
	drawing : function(){
		var radius = this.radius;
		var rx = radius;
		var ry = radius;
		//Core Drawing
		this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
		this.ctx.beginPath();
		this.ctx.arc(rx,ry,radius,0,2 * Math.PI);
		var radian = (Math.PI * 2 / 12) * this.count;
		var p = this.getPoint(radian,radius);
		this.drawingMarks();
		this.ctx.moveTo(rx, ry);
	  this.ctx.lineTo(rx + p.x , ry + p.y);
		this.ctx.stroke();
		//Counting for drawing
		this.count++;
		if(this.count > 12){this.count = 1}
	},
	getPoint : function(radian,radius){
		var x = Math.cos(radian) * radius;
		var y = Math.sin(radian) * radius;
		return {x : x , y : y};
	},
	start : function(){
		//this.drawing();
		setInterval($.proxy(this.drawing,this),this.interval);
	}
};

function globalToLocal(canvas, x, y) {
  var bbox = canvas.getBoundingClientRect();
  var x = x - bbox.left * (canvas.width / bbox.width);
	var y = y - bbox.top  * (canvas.height / bbox.height);
	return {x: x, y : y};
}


$(function(){
	var c = new Clock();
	c.start();
});

时钟时分秒针绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
Clock = function(){
	var jCanvas = $('<canvas width="450" height="300">');
	//jCanvas.on('mousemove',onMousemove);
	$(document.body).append(jCanvas);
	this.canvas = jCanvas[0];
	this.ctx = this.canvas.getContext('2d');
	this.ctx.strokeStyle = 'red';
	this.ctx.fillStyle = 'red';
	this.rect = {w:this.canvas.width,h:this.canvas.height,x:0,y:0};
	this.radius = 50;
	this.count = 1;
	this.interval = 1000;
};

Clock.prototype = {
	drawingMarks : function(){
		var radius = this.radius;
		var rx = radius;
		var ry = radius;
		//Hour Wheel Marks
		for(var i=1;i<=12;i++){
			var radian = (Math.PI * 2 / 12) * i;
			var p1 = this.getPoint(radian,radius - 8);
			var p2 = this.getPoint(radian,radius);
			this.ctx.moveTo(rx + p1.x , ry + p1.y);
			this.ctx.lineTo(rx + p2.x , ry + p2.y);
		}
		//Minute Wheel Marks
		for(var j=1;j<=60;j++){
			var radian = (Math.PI * 2 / 60) * j;
			var p1 = this.getPoint(radian,radius - 3);
			var p2 = this.getPoint(radian,radius);
			this.ctx.moveTo(rx + p1.x , ry + p1.y);
			this.ctx.lineTo(rx + p2.x , ry + p2.y);
		}
	},
	drawing : function(){
		var radius = this.radius;
		var rx = radius;
		var ry = radius;
		//Core Drawing
		this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
		this.ctx.beginPath();
		this.ctx.arc(rx,ry,radius,0,2 * Math.PI);
		var radian = (Math.PI * 2 / 12) * this.count;
		var p = this.getPoint(radian,radius);
		this.drawingMarks();
		//
		this.ctx.moveTo(rx, ry);
		this.ctx.arc(rx,ry,2,0,Math.PI*2);
		//
		var date = new Date();
		//Hour Wheel
		var hours = date.getHours();
		radian = (Math.PI * 2 / 12) * (hours - 12);
		var p1 = this.getPoint(radian - Math.PI/2,radius-25);
		this.ctx.moveTo(rx, ry);
		this.ctx.lineTo(rx + p1.x , ry + p1.y);
		//Minute Wheel
		var minutes = date.getMinutes();
		radian = (Math.PI * 2 / 60) * minutes;
		var p2 = this.getPoint(radian - Math.PI/2,radius-15);
		this.ctx.moveTo(rx, ry);
		this.ctx.lineTo(rx + p2.x , ry + p2.y);
		//Second Wheel
		var seconds = date.getSeconds();
		radian = (Math.PI * 2 / 60) * seconds;
		var p3 = this.getPoint(radian - Math.PI/2,radius);
		this.ctx.moveTo(rx, ry);
		this.ctx.lineTo(rx + p3.x , ry + p3.y);
		this.ctx.stroke();
	},
	getPoint : function(radian,radius){
		var x = Math.cos(radian) * radius;
		var y = Math.sin(radian) * radius;
		return {x : x , y : y};
	},
	start : function(){
		//this.drawing();
		setInterval($.proxy(this.drawing,this),this.interval);
	}
};

function globalToLocal(canvas, x, y) {
  var bbox = canvas.getBoundingClientRect();
  var x = x - bbox.left * (canvas.width / bbox.width);
	var y = y - bbox.top  * (canvas.height / bbox.height);
	return {x: x, y : y};
}


$(function(){
	var c = new Clock();
	c.start();
});

完整版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
Clock = function(){
	var jCanvas = $('<canvas width="450" height="300">');
	//jCanvas.on('mousemove',onMousemove);
	$(document.body).append(jCanvas);
	this.canvas = jCanvas[0];
	this.ctx = this.canvas.getContext('2d');
	this.ctx.strokeStyle = 'red';
	this.ctx.fillStyle = 'red';
	this.rect = {w:this.canvas.width,h:this.canvas.height,x:0,y:0};
	this.radius = 50;
	this.count = 1;
	this.interval = 1000;
};

Clock.prototype = {
	drawingMarks : function(){
		var radius = this.radius;
		var rx = radius;
		var ry = radius;
		//Hour Wheel Marks
		for(var i=1;i<=12;i++){
			var radian = (Math.PI * 2 / 12) * i;
			var p1 = this.getPoint(radian,radius - 8);
			var p2 = this.getPoint(radian,radius);
			this.ctx.moveTo(rx + p1.x , ry + p1.y);
			this.ctx.lineTo(rx + p2.x , ry + p2.y);
		}
		//Minute Wheel Marks
		for(var j=1;j<=60;j++){
			var radian = (Math.PI * 2 / 60) * j;
			var p1 = this.getPoint(radian,radius - 3);
			var p2 = this.getPoint(radian,radius);
			this.ctx.moveTo(rx + p1.x , ry + p1.y);
			this.ctx.lineTo(rx + p2.x , ry + p2.y);
		}
	},
	drawing : function(){
		var radius = this.radius;
		var rx = radius;
		var ry = radius;
		//Core Drawing
		this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
		this.ctx.beginPath();
		this.ctx.arc(rx,ry,radius,0,2 * Math.PI);
		var radian = (Math.PI * 2 / 12) * this.count;
		var p = this.getPoint(radian,radius);
		this.drawingMarks();
		//
		this.ctx.moveTo(rx, ry);
		this.ctx.arc(rx,ry,2,0,Math.PI*2);
		//
		var date = new Date();
		var hours = date.getHours();
		var minutes = date.getMinutes();
		var seconds = date.getSeconds();
		//Hour Wheel
		radian = (Math.PI * 2 / 12) * (hours - 12) + (Math.PI * 2 / 12) * (minutes / 60);
		var p1 = this.getPoint(radian - Math.PI/2,radius-25);
		this.ctx.moveTo(rx, ry);
		this.ctx.lineTo(rx + p1.x , ry + p1.y);
		//Minute Wheel
		radian = (Math.PI * 2 / 60) * minutes + (Math.PI * 2 / 12 / 60 / 60) * seconds;;
		var p2 = this.getPoint(radian - Math.PI/2,radius-15);
		this.ctx.moveTo(rx, ry);
		this.ctx.lineTo(rx + p2.x , ry + p2.y);
		//Second Wheel
		radian = (Math.PI * 2 / 60) * seconds;
		var p3 = this.getPoint(radian - Math.PI/2,radius);
		this.ctx.moveTo(rx, ry);
		this.ctx.lineTo(rx + p3.x , ry + p3.y);
		this.ctx.stroke();
	},
	getPoint : function(radian,radius){
		var x = Math.cos(radian) * radius;
		var y = Math.sin(radian) * radius;
		return {x : x , y : y};
	},
	start : function(){
		//this.drawing();
		setInterval($.proxy(this.drawing,this),this.interval);
	}
};

function globalToLocal(canvas, x, y) {
  var bbox = canvas.getBoundingClientRect();
  var x = x - bbox.left * (canvas.width / bbox.width);
	var y = y - bbox.top  * (canvas.height / bbox.height);
	return {x: x, y : y};
}


$(function(){
	var c = new Clock();
	c.start();
});

SEO

如何/怎么 截图 画箭头实现,类似 QQ 那种截图后画箭头的功能。 如何/怎么 画一个闹钟展现在页面/界面上。

最后

以上这些是我个人总结的一些肤浅的知识,如果有不对的地方还望多多赐教,谢谢。

This post is licensed under CC BY 4.0

Golang 依赖包下载时候代理设置

GIT 免密登录解决多账户问题,涉及 SSH 私钥/公钥

Comments powered by Disqus.