用canvas绘制时钟

圆心坐标计算公式

    x1   =   x0   +   r   *   cos( a )
    y1   =   y0   +   r   *   sin( a )

根据公式可知x0,y0为圆心坐标,x1,y1为真实坐标

对时钟进行分析

  • 圆周分为12分每一份为一个小时(时针)
  • 圆周分为60分一个刻度为一分(分针)
  • 秒用getMilliseconds计算,1000ms为1秒,圆周分为60刻度每个刻度为1s

基础准备

     let height = 500  //canvas的宽高
     let width = 500
     let distance = 10 //分秒刻度长度
     let distance1 = 15 // 时针刻度长度
     
     let x0 = 0  // 默认初始圆心位置
     let y0 = 0
     function calcPoint(r, a) {
        x1   =   x0   +   r   *   Math.cos( a )
        y1   =   y0   +   r   *   Math.sin( a )
        return [x1, y1]
      }

复制代码

画布准备


 let Timer = function(props) {
         // 创建dom节点引用
        let ref = React.createRef()
        useEffect(() => {
            let canva = ref.current
            //canvas从css设置宽高会出现一定锯齿问题
            canva.width = width
            canva.height = height
            let ctx = canva.getContext('2d')
          
            drawWatch(ctx, width,height)
            return () => stop = false  
        },[])
        return h('canvas',  {className: 'basic_class', ref})
    }
  // 渲染时钟  
 ReactDOM.render(h(Timer), document.getElementById('app'));    
复制代码

绘制过程

  let reqFrame = requestAnimationFrame || setTimeout
  let stop = false //用于组件销毁时结束reqFrame
  function drawWatch(ctx, width,height) {
        if(!stop) {
          reqFrame(drawWatch.bind(null, ctx, width,height))
        }
        ctx.clearRect(0,0,width, height)
        chart.drawTick(ctx)
        chart.drawText(ctx)
        chart.drawLine(ctx)
  }
  
  
   let chart = {
          drawTick(ctx) {
            let outerline = height*0.8/2
            let centerPoint = [width/2, height/2]
            let maxDeg = 2*Math.PI
            let tick = maxDeg/60
            x0 = centerPoint[0]
            y0 = centerPoint[1]

            ctx.beginPath()
            ctx.lineCap="round"
            for(let item = 0; item<60; item++) {
              let deg = tick*item
              let innerline = outerline - distance
              ctx.strokeStyle = '#aaa'
              if(item%5 == 0) {
                innerline = outerline - distance1
                ctx.strokeStyle = '#fff'
              }
              //此处用了圆心坐标的方法进行计算
              //也可以通过 ctx.save()  ctx.rotate() ctx.restore() 方法实现,参展drawText
              let start = calcPoint(innerline, deg)
              let end = calcPoint(outerline, deg)

              ctx.moveTo(...start)
              ctx.lineTo(...end)
            }

            ctx.stroke()


          },
          drawText(ctx) {
            let maxDeg = 2*Math.PI
            let tick = maxDeg/ 12
            let outerline = height*0.8/2
            let x = -3
            let y = - outerline  +  distance1 + 15
            ctx.beginPath()
            // grd.addColorStop(0,"#FF0000");
            // grd.addColorStop(1,"#00FF00");
            ctx.fillStyle='#fff';
            for(let item = 0; item < 12; item++) {
              ctx.save()
              let num = item
              let x1 = x 
              if(item == 0) { num = 12}
              if(num > 9)  { x1 = -6 }
              ctx.translate(width/2, height/2)
              ctx.rotate(tick*item)
              ctx.strokeStyle = '#fff'
              ctx.fillText(num, x1, y)
              ctx.restore()
            }

            ctx.stroke()
          },
          drawLine(ctx) {
            let outerline = height*0.8/2
            let date = new Date()
            let times = date.getMilliseconds()
            let second = date.getSeconds()
            let hour =date.getHours()
            let mins =date.getMinutes()
            let secondDeg = 2*Math.PI/60
            let hourDeg = 2*Math.PI/12
            //小时添加了分针的进度让时针指向的位置更加合理
            let hDeg = (hour + mins/60) * hourDeg  +   - Math.PI/2 
            //分针的跨度比较小不做精细化处理
            let mDeg = mins * secondDeg - Math.PI/2
            //秒针所要转的角度    
            let sDeg = (second + times/1000) * secondDeg - Math.PI/2
            
            let hp = calcPoint(outerline - distance - 100,  hDeg )
            let mp = calcPoint(outerline - distance -30,  mDeg )
            let sp = calcPoint(outerline - distance,  sDeg ) 
            
            ctx.beginPath()
            ctx.moveTo(width/2, height/2)
            ctx.lineTo(...mp)
            ctx.strokeStyle = '#fff'
            ctx.stroke()

            ctx.beginPath()
            ctx.moveTo(width/2, height/2)
            ctx.lineTo(...hp)
            ctx.strokeStyle = '#19f'
            ctx.stroke()
            
            ctx.beginPath()
            ctx.moveTo(width/2, height/2)
            ctx.lineTo(...sp)
            ctx.strokeStyle = '#f91'
            ctx.stroke()
          }
      }

复制代码

效果

1647930753.jpg

结束

该功能的实现没有复杂的过程,都是比较基础的知识,写这篇文章算是对canvas做一步较深的理解

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享