使用canvas复刻vivo时钟

432 阅读1分钟

前言

今天在设闹钟的时候发现手机上的那个世界时钟挺好看的,正好最近在学canvas,就心血来潮想将它复刻出来

原版

Screenrecording_20220502_222758.gif 首先将时针、分针和刻度都画出来

时针,可以根据当前时间算出时针转过的角度,如果不考虑分针对时针的影响,那时针当前转过的角度就是(2π/12) h(h是当前小时数),再叫上分钟数(一开始我忘了,后来越看越不对劲,经过对比发现,我忘记了时针转动的角度还和分钟有关)。那时钟转过的角度就是(2π/12) h+(2π/6012) m(m是当前分钟数)

分针就类似时针

刻度可以通过一个60次的循环,每循环一次画一个刻度,并判断当前刻度是否是当前秒数。

这样子就已经将大体弄出来了,其他的数字之类的就通过fillText()画上去,中间的圆环是一个有颜色的大圆中间一个白色小圆

注意:如果分钟是小于10的数时,要补个0,可以通过padStart(2,0)完成,小时也一样

效果:

QQ录屏20220502223140.gif

代码如下:

<canvas id="clock" width="300" height="300"></canvas>
    <script>
        const clock = document.getElementById("clock")
        const ctx = clock.getContext("2d")
​
        fn()
        function fn() {
            const time = Date.now()
            const h1 = new Date(time).getHours()
            const h = h1 % 12
            const m = new Date(time).getMinutes()
            const s = new Date(time).getSeconds()
​
            ctx.save()
            ctx.clearRect(0, 0, 300, 300)
            ctx.translate(120, 120)
            ctx.save()
​
            //分
            ctx.rotate(2 * Math.PI * m / 60 + s * 2 * Math.PI / 3600)
            ctx.beginPath()
            ctx.moveTo(0, -50)
            ctx.lineTo(0, -85)
            ctx.lineWidth = 5
            ctx.lineCap = "round"
            ctx.stroke()
            ctx.closePath()
            ctx.restore()
            ctx.save()
​
            //时
            ctx.rotate(2 * Math.PI * h / 12 + m * 2 * Math.PI / 720)
            ctx.beginPath()
            ctx.moveTo(0, -50)
            ctx.lineTo(0, -75)
            ctx.lineWidth = 10
            ctx.strokeStyle = "red"
            ctx.lineCap = "round"
            ctx.stroke()
            ctx.closePath()
            ctx.restore()
            ctx.save()
​
​
            ctx.font = "bold 14px Arial"
            ctx.textAlign = "center"
            ctx.textBaseLine = "middle"
            ctx.fillText("12", 0, -95)
            ctx.fillText("3", 100, 4)
            ctx.fillText("6", 0, 103)
            ctx.fillText("9", -100, 4)
            for (let i = 0; i < 60; i++) {
                if (i === s) {
                    ctx.lineWidth = 5
                    ctx.strokeStyle = "red"
                    ctx.beginPath()
                    ctx.moveTo(0, -104)
                    ctx.lineTo(0, -90)
                    ctx.lineCap = "round"
                    ctx.stroke()
                    ctx.closePath()
                } else {
                    ctx.strokeStyle = "rgba(0,0,0,.3)"
                    if (i % 5 === 0 && i !== 0 && i !== 15 && i !== 30 && i !== 45) {
                        ctx.lineWidth = 3
                        ctx.lineCap = "round"
                        ctx.beginPath()
                        ctx.moveTo(0, -100)
                        ctx.lineTo(0, -94)
                        ctx.stroke()
                        ctx.closePath()
                    } else if (i % 5 !== 0) {
                        ctx.lineWidth = 1
                        ctx.beginPath()
                        ctx.moveTo(0, -100)
                        ctx.lineTo(0, -98)
                        ctx.stroke()
                        ctx.closePath()
                    }
                }
                ctx.rotate(2 * Math.PI / 60)
            }
            ctx.beginPath()
            ctx.arc(0, 0, 40, 0, 2 * Math.PI)
            ctx.fillStyle = "rgba(0,0,0,0.1)"
            ctx.fill()
            ctx.closePath()
​
            ctx.beginPath()
            ctx.arc(0, 0, 20, 0, 2 * Math.PI)
            ctx.fillStyle = "white"
            ctx.fill()
            ctx.closePath()
​
            ctx.fillStyle = "black"
            ctx.font = "bold 30px Arial"
            ctx.fillText(`${(h1 + "").padStart(2, 0)}:${(m + "").padStart(2, 0)}`, 0, 10)
​
            ctx.restore()
            ctx.restore()
        }
        setInterval(fn, 1000)
​
    </script>