圆心坐标计算公式
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()
}
}
复制代码
效果
结束
该功能的实现没有复杂的过程,都是比较基础的知识,写这篇文章算是对canvas做一步较深的理解
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END