绘制背景
<!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>模拟IOS时钟</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #ddd;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.clock {
width: 300px;
height: 300px;
background-color: black;
border-radius: 50px;
}
</style>
</head>
<body>
<div class="clock">
<canvas class="canvas" width="300" height="300"></canvas>
</div>
<script>
const canvasEl = document.querySelector('canvas')
const ctx = canvasEl.getContext('2d')
// 绘制 时钟白色背景
function drawBg() {
ctx.save()
ctx.translate(150, 150)
ctx.fillStyle="#fff"
ctx.beginPath()
ctx.arc(0, 0, 130, 0, Math.PI * 2)
ctx.fill()
ctx.closePath()
ctx.restore()
}
function draw() {
ctx.clearRect(0, 0, 300, 300)
drawBg()
requestAnimationFrame(draw)
}
draw()
</script>
</body>
</html>
绘制刻度
先绘制一个刻度3
function drawNumber() {
ctx.save()
ctx.translate(150, 150)
ctx.font="30px fangsong";
ctx.fillText(3, 100, 0)
ctx.restore()
}
在canvas中绘制文本需要使用fillText,而fillText需要传递三个参数
ctx.fillText(<font>, <X>, <Y>)
所以我们需要计算出每一个刻度所对应的X和Y轴坐标
我们知道三角形 三条边的关系如下
此时A是圆点,AC是圆的半径
x= AB = cos(a) * AC => x = Math.cos(a对应的弧度) * R
y= BC = sin(a) * AC => y = Math.sin(a对应的弧度) * R
function drawNumber() {
ctx.save()
const numbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2]
ctx.translate(150, 150)
ctx.font="30px fangsong";
// 绘制文本的时候,确保绘制点 位于 绘制文字的中心点
// 避免因为绘制文字的中心不对 而导致时钟刻度盘不居中
ctx.textBaseline="middle"
ctx.textAlign="center"
// 一圈是 Math.PI * 2
// 需要绘制12个刻度,所以每一份刻度所占的弧度为 Math.PI * 2 / 12
// 所以对于每一个刻度 对于的弧度极为 Math.PI * 2 / 12 * i
for(let i =0; i < numbers.length; i++) {
ctx.fillText(numbers[i],
Math.cos(Math.PI / 6 * i) * 100,
Math.sin(Math.PI / 6 * i) * 100
)
}
ctx.restore()
}
绘制时分针
function drawHands() {
ctx.save()
const date = new Date()
const hours = date.getHours()
const minutes = date.getMinutes()
const seconds = date.getSeconds()
ctx.translate(150, 150)
// 绘制时钟,对于小时而言
// 1小时 -> Math.PI * 2 / 12 === 12个刻度
// 1分钟 -> Math.PI * 2 / 12 / 60
// 1秒 -> Math.PI * 2 / 12 / 60 / 60
ctx.save()
ctx.beginPath()
ctx.lineWidth = 5
ctx.lineCap = 'round'
ctx.rotate(Math.PI * 2 / 12 * hours + Math.PI * 2 / 12 / 60 * minutes + Math.PI * 2 / 12 / 60 / 60 * seconds)
ctx.moveTo(0, 0)
ctx.lineTo(0, -50)
ctx.stroke()
ctx.closePath()
ctx.restore()
// 绘制分钟
// 一圈是60分钟
// 1分钟 Math.PI * 2 / 60
// 1秒 Math.PI * 2 / 60 / 60
ctx.save()
ctx.beginPath()
ctx.lineWidth = 3
ctx.lineCap = 'round'
ctx.rotate(Math.PI * 2 / 60 * minutes + Math.PI * 2 / 60 / 60 * seconds)
ctx.moveTo(0, 0)
ctx.lineTo(0, -65)
ctx.stroke()
ctx.closePath()
ctx.restore()
// 绘制秒针
// 一圈是60秒
// 1s Math.PI * 2 / 60
ctx.save()
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.rotate(Math.PI * 2 / 60 * seconds)
ctx.strokeStyle="#f00"
ctx.lineCap = 'round'
ctx.lineTo(0, -85)
ctx.stroke()
ctx.closePath()
ctx.restore()
ctx.restore()
}
绘制圆盘
function drawCricle() {
ctx.save()
ctx.translate(150, 150)
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.arc(0, 0, 8, 0, Math.PI * 2)
ctx.fill()
ctx.closePath()
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.arc(0, 0, 5, 0, Math.PI * 2)
ctx.fillStyle = "gray"
ctx.fill()
ctx.closePath()
ctx.restore()
}
绘制刻度
绘制小时刻度
function drawHourScale() {
ctx.save()
ctx.translate(150, 150)
for(let i = 0; i < 12; i++) {
ctx.rotate(Math.PI * 2 / 12)
ctx.beginPath()
ctx.lineWidth = 3
ctx.moveTo(0, -130)
ctx.lineTo(0, -122)
ctx.stroke()
ctx.closePath()
}
ctx.restore()
}
绘制分钟刻度
function drawMinuteScale() {
ctx.save()
ctx.translate(150, 150)
for(let i = 0; i < 60; i++) {
ctx.rotate(Math.PI * 2 / 60)
ctx.beginPath()
ctx.moveTo(0, -130)
ctx.lineTo(0, -125)
ctx.stroke()
ctx.closePath()
}
ctx.restore()
}