怎么绘制漂亮的时钟,Canvas来帮忙?

绘制漂亮的时钟需要使用到Canvas的动画技术。秒针每秒钟都会移动,所以我们需要使用setInterval()setTimeout()requestAnimationFrame()其中的一个来不断更新时钟画面。这些函数都可以让浏览器在指定的时间间隔内重复执行某段代码,从而实现动画效果。

具体来说,我们可以使用setInterval()函数来每隔一定时间(比如10毫秒)就重新绘制一次时钟。在每次重新绘制时钟时,我们需要更新秒针的位置,然后清空画布,再重新绘制时钟的各个部分。

绘制时钟的基本步骤包括:

  1. 清除画布:在每次重新绘制时钟之前,我们需要使用clearRect()函数来清除画布上的内容。
  2. 绘制时钟的圆盘:使用arc()函数来绘制一个圆形,作为时钟的圆盘。设置填充颜色和描边颜色,以呈现出圆盘的外观。
  3. 绘制时针、分针和秒针:根据当前的时间,计算出时针、分针和秒针的位置,并使用moveTo()lineTo()函数来绘制它们。需要注意的是,由于时钟的圆盘是立体的,所以时针、分针和秒针的颜色可能会有所不同,以呈现出更好的立体效果。
  4. 循环执行:使用setInterval()函数来不断重复执行上述步骤,以实现动画效果。

通过这些步骤,我们就可以使用Canvas来绘制一个漂亮的时钟了。

示例效果与源代码:

运行效果

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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<!DOCTYPE html>
<html>

<head>
<title>动画(时钟)</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="图形系统开发实战:基础篇 示例">
<meta name="author" content="hjq">
<meta name="keywords" content="canvas,ladder,javascript">
<script src="./js/helper.js"></script>
</head>

<body style="overflow: hidden; margin:10px;">
<div style="display: inline-block;">
<canvas id="canvas" width="500" height="450" style="border:solid 1px #CCCCCC;"></canvas>
</div>
</body>
<script>
// 从页面中获取画板对象
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');

// 时钟大小
let x = 250, y = 225, radius = 200;
// 最后一次绘制时钟的秒数
let lastSecond = 0;

// 时钟动起来
requestAnimationFrame(drawClock);

/**
* 绘制时钟函数
*/
function drawClock() {
let second = Math.round(Date.now() / 1000);
// 当前秒数大于上一次绘制时钟的秒数时,重绘时钟
if (second > lastSecond) {
lastSecond = second;

// 清除已有内容
ctx.clearRect(0, 0, canvas.width, canvas.height);

// 绘制背景网格
drawGrid('lightgray', 10, 10, ctx);

// 绘制时钟外观
drawFacade();

// 绘制时钟刻度
let min = 60;
for (let i = 0; i < min; i++) {
drawScale(x, y, radius, i);
}

// 绘制时针、分针、秒针
drawPointer("h");
drawPointer("m");
drawPointer("s");
}

// 重绘
requestAnimationFrame(drawClock);
}

/**
* 绘制时钟外观
*/
function drawFacade() {
// 外圈渐变样式
const gradient = ctx.createRadialGradient(x, y, 0, x, y, radius + 25);
gradient.addColorStop(0, "rgb(255,255,255)");
gradient.addColorStop(0.817, "rgb(255,255,255)");
gradient.addColorStop(0.837, "rgb(237,237,237)");
gradient.addColorStop(0.874, "rgb(77,77,77)");
gradient.addColorStop(0.904, "rgb(236,236,236)");
gradient.addColorStop(0.969, "rgba(77,77,77,168)");
gradient.addColorStop(1, "rgba(77,77,77,0)");

// 绘制外圈
ctx.save();
ctx.beginPath();
ctx.arc(x, y, radius + 10, 0, 2 * Math.PI);
ctx.fillStyle = gradient;
ctx.fill();

// 绘制中心
ctx.beginPath();
ctx.fillStyle = "gray";
ctx.arc(x, y, 10, 0, 2 * Math.PI)
ctx.fill();
ctx.restore();
}

/**
* 绘制时针、分针、秒针函数
*/
function drawPointer(type, value) {
let deg, beginX, endX;
let now = new Date();
ctx.save();

// 计算时针角度和长度,并设置样式
if (type == "s") { // 秒
deg = now.getSeconds() * 6 - 90;
beginX = -30;
endX = radius - 50; // 长
ctx.lineWidth = 4; // 细
ctx.strokeStyle = "gold";
} else if (type == "m") { // 分
deg = now.getMinutes() * 6 + (now.getSeconds() / 60 * 6) - 90;
beginX = -20;
endX = radius - 70;
ctx.lineWidth = 6;
ctx.strokeStyle = "#2400CC";
} else { // 时
deg = now.getHours() * 30 + (now.getMinutes() / 60 * 30) - 90;
beginX = -15;
endX = radius - 90;
ctx.lineWidth = 8;
ctx.strokeStyle = "#0018CC";
}

// 绘制
ctx.translate(x, y);
ctx.rotate(toRadians(deg));
ctx.beginPath();
ctx.moveTo(beginX, 0);
ctx.lineTo(endX, 0);
ctx.stroke();
ctx.restore();
}

/**
* 绘制时钟刻度函数
*/
function drawScale(x, y, radius, min) {
let deg = min * 6; // 每分钟为6°
let len = 20;
ctx.save();
// 按时钟中心旋转
ctx.translate(x, y);
ctx.rotate(toRadians(deg));

ctx.beginPath();
// 5的整数分钟的刻度要长一些粗一些
if (min % 5 == 0) {
ctx.lineWidth = 4;
ctx.moveTo(radius - 30, 0);
} else {
ctx.lineWidth = 2;
ctx.moveTo(radius - 20, 0);
}
ctx.lineTo(radius - 8, 0);
ctx.stroke();
ctx.restore();

// 每5分钟显示数字值
if (min % 5 == 0) {
ctx.save();
// 按按时钟中心旋转
ctx.translate(x, y);
ctx.rotate(toRadians(deg));
// 平移至文字所在位置,并反向旋转
ctx.translate(radius - 45, 0);
ctx.rotate(toRadians(-deg));
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "bold 25px 黑体";
//
ctx.fillText((min > 45 ? (min - 45) : (min + 15)) / 5, 0, 0);
ctx.restore()
}
}

</script>

</html>

尝试一下 »