Canvas实现简单时钟表盘

重复的记忆,会让知识流逝的速度越来越慢

仅作个人学习记录用,大佬勿喷,当然能帮到正好需要的朋友最好

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>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值