重复的记忆,会让知识流逝的速度越来越慢
仅作个人学习记录用,大佬勿喷,当然能帮到正好需要的朋友最好
1.新建一个canvas画布,此处很简单,不过多赘述
<canvas id="box" width='300' height='300'> 您的浏览器不支持canvas,请升级! </canvas>
<script>
window.onload = () => {
/** @type {HTMLCanvasElement} */
let canvas = document.querySelector('#box')
if (!canvas.getContext) return
let ctx = canvas.getContext('2d')
}
</script>
2.下边开始写代码
封装一个函数,并使用window.requestAnimationFrame(draw)来调用,每秒调用60次左右,此处不用setInterval是有原因的,具体原因可以MDN自行查询requestAnimationFrame此API
function draw(){
}
函数每次调用,先擦除canvas画布,并且new一个时间实例,后边要用到
function draw() {
ctx.clearRect(0, 0, 300, 300)
ctx.save()
let time = new Date()
let h = time.getHours()
let m = time.getMinutes()
let s = time.getSeconds()
let ss = time.getMilliseconds()
restore()
}
开始绘制时钟的圆盘背景,这一步不难,就是调用canvas的arc方法进行绘制圆
// 绘制圆盘背景
ctx.save()
ctx.translate(150, 150)
ctx.fillStyle = 'white'
ctx.beginPath()
ctx.arc(0, 0, 130, 0, Math.PI * 2)
ctx.fill()
ctx.restore()
然后开始绘制时钟内圈数字(此处需要用到三角函数)
忘了三角函数的同学可以看这张图
看完这张图此处就不难理解,圆盘的半径我们已知,整个圆的弧度是Math.PI*2,所以cos也能求出来,就是整个圆的弧度除以总共12小时,剩下那一个边就是x轴,y轴也是同理,通过sin函数就能求出,求出一个的x,y,那么此时我们就可以通过for循环来进行12小时的整体绘制
// 绘制时针数字
ctx.save()
ctx.translate(150, 150)
ctx.font = '30px MiSans'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
let numbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2]
for (let i = 0; i < numbers.length; i++) {
let x = Math.cos(((Math.PI * 2) / 12) * i) * 100
let y = Math.sin(((Math.PI * 2) / 12) * i) * 100
ctx.fillText(numbers[i], x, y)
}
ctx.restore()
通过上边操作我们已经绘制好了时钟数字,此时开始绘制时针,时针的绘制就用到了我们上边new出来的时间实例,此处旋转的角度不太容易理解,首先Math.PI * 2/ 12* h是当前时间下时针指向的数字,但是他只有整数,所以只能指向整点,此时我们加上Math.PI * 2/ 12 / 60* m,就代表我们此时时针的弧度是小时的弧度+分钟的弧度,此时就能正确指向几点几分,后边的秒同理,也可不加
// 绘制时针
ctx.save()
ctx.translate(150, 150)
ctx.rotate(
((Math.PI * 2) / 12) * h +
((Math.PI * 2) / 12 / 60) * m +
((Math.PI * 2) / 12 / 60 / 60) * s
)
ctx.lineCap = 'round'
ctx.lineWidth = 5
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -50)
ctx.stroke()
ctx.restore()
绘制完时针绘制分针,分针与时针同理
// 绘制分针
ctx.save()
ctx.translate(150, 150)
ctx.rotate(((Math.PI * 2) / 60) * m)
ctx.lineCap = 'round'
ctx.lineWidth = 3
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -70)
ctx.stroke()
ctx.restore()
然后就是绘制秒针 ,此处可以精确到毫秒,会让动画看起来更加流畅
//绘制秒针
ctx.save()
ctx.translate(150, 150)
ctx.rotate(((Math.PI * 2) / 60) * s + ((Math.PI * 2) / 60 / 1000) * ss)
ctx.lineCap = 'round'
ctx.lineWidth = 2
ctx.strokeStyle = 'red'
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -90)
ctx.stroke()
ctx.restore()
绘制指针中心圆,没什么难点
// 绘制中心圆
ctx.save()
ctx.translate(150, 150)
ctx.fillStyle = 'black'
ctx.beginPath()
ctx.arc(0, 0, 10, 0, Math.PI * 2)
ctx.fill()
ctx.fillStyle = 'gray'
ctx.beginPath()
ctx.arc(0, 0, 5, 0, Math.PI * 2)
ctx.fill()
ctx.restore()
绘制时针刻度,此处也较好理解,就是循环绘制线条
// 绘制时针刻度
ctx.save()
ctx.translate(150, 150)
for (let i = 0; i < 12; i++) {
ctx.rotate((Math.PI * 2) / 12)
ctx.lineWidth = 4
ctx.beginPath()
ctx.moveTo(0, -130)
ctx.lineTo(0, -120)
ctx.stroke()
}
ctx.restore()
绘制分针和秒针的刻度,同理
// 绘制分针刻度
ctx.save()
ctx.translate(150, 150)
for (let i = 0; i < 60; i++) {
ctx.rotate((Math.PI * 2) / 60)
ctx.lineWidth = 2
ctx.beginPath()
ctx.moveTo(0, -130)
ctx.lineTo(0, -125)
ctx.stroke()
}
ctx.restore()
好了,到此为止我们就已经绘制了一个简单的时钟表盘
具体效果如下
下边贴出所有代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.clock {
width: 300px;
height: 300px;
background-color: black;
border-radius: 50px;
margin: 10px;
}
</style>
</head>
<body>
<div class="clock">
<canvas id="canvas" width="300" height="300"
>您的浏览器不支持canvas,请升级!</canvas
>
</div>
<script>
/**@type {HTMLCanvasElement}*/
let canvas = document.getElementById('canvas')
let ctx = canvas.getContext('2d')
requestAnimationFrame(draw)
function draw() {
ctx.clearRect(0, 0, 300, 300)
ctx.save()
let time = new Date()
let h = time.getHours()
let m = time.getMinutes()
let s = time.getSeconds()
let ss = time.getMilliseconds()
// 绘制圆盘背景
ctx.save()
ctx.translate(150, 150)
ctx.fillStyle = 'white'
ctx.beginPath()
ctx.arc(0, 0, 130, 0, Math.PI * 2)
ctx.fill()
ctx.restore()
// 绘制时针刻度
ctx.save()
ctx.translate(150, 150)
ctx.font = '30px MiSans'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
let numbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2]
for (let i = 0; i < numbers.length; i++) {
let x = Math.cos(((Math.PI * 2) / 12) * i) * 100
let y = Math.sin(((Math.PI * 2) / 12) * i) * 100
ctx.fillText(numbers[i], x, y)
}
ctx.restore()
// 绘制时针
ctx.save()
ctx.translate(150, 150)
ctx.rotate(
((Math.PI * 2) / 12) * h +
((Math.PI * 2) / 12 / 60) * m +
((Math.PI * 2) / 12 / 60 / 60) * s
)
ctx.lineCap = 'round'
ctx.lineWidth = 5
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -50)
ctx.stroke()
ctx.restore()
// 绘制分针
ctx.save()
ctx.translate(150, 150)
ctx.rotate(((Math.PI * 2) / 60) * m)
ctx.lineCap = 'round'
ctx.lineWidth = 3
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -70)
ctx.stroke()
ctx.restore()
//绘制秒针
ctx.save()
ctx.translate(150, 150)
ctx.rotate(((Math.PI * 2) / 60) * s + ((Math.PI * 2) / 60 / 1000) * ss)
ctx.lineCap = 'round'
ctx.lineWidth = 2
ctx.strokeStyle = 'red'
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -90)
ctx.stroke()
ctx.restore()
// 绘制中心圆
ctx.save()
ctx.translate(150, 150)
ctx.fillStyle = 'black'
ctx.beginPath()
ctx.arc(0, 0, 10, 0, Math.PI * 2)
ctx.fill()
ctx.fillStyle = 'gray'
ctx.beginPath()
ctx.arc(0, 0, 5, 0, Math.PI * 2)
ctx.fill()
ctx.restore()
// 绘制时针刻度
ctx.save()
ctx.translate(150, 150)
for (let i = 0; i < 12; i++) {
ctx.rotate((Math.PI * 2) / 12)
ctx.lineWidth = 4
ctx.beginPath()
ctx.moveTo(0, -130)
ctx.lineTo(0, -120)
ctx.stroke()
}
ctx.restore()
// 绘制分针刻度
ctx.save()
ctx.translate(150, 150)
for (let i = 0; i < 60; i++) {
ctx.rotate((Math.PI * 2) / 60)
ctx.lineWidth = 2
ctx.beginPath()
ctx.moveTo(0, -130)
ctx.lineTo(0, -125)
ctx.stroke()
}
ctx.restore()
ctx.restore()
requestAnimationFrame(draw)
}
</script>
</body>
</html>