最近看到一篇资讯:
点击链接去看了一眼,果然又是canvas,想到了开始接触canvas的时候也写过一个时钟,不过当时实现的代码比较坑……
//弧度=角度*Math.PI/180 ogc.save(); //保存绘图 ogc.arc(100, 100, 50, 0, 90 * Math.PI / 180, false); //圆心坐标,半径,起始弧度,结束弧度,旋转方向(默认false顺时针) ogc.stroke(); ogc.restore(); //恢复绘图
canvas绘图与我们一般对绘图的理解不同,它不是所见即所得并且运用了很多数学知识(毕竟是用代码写出来的……)
上面代码就是用canvas的arc()方法绘制了一个90度角的弧线,由于canvas的坐标系比较特殊,所以效果是这样的:
可能不太明显,那么用canvas绘制一个扇形:
//弧度=角度*Math.PI/180 ogc.save(); //保存绘图 ogc.beginPath();//开始一段路径 ogc.moveTo(100,100); ogc.arc(100, 100, 50, 0, 90 * Math.PI / 180, false); //圆心坐标,半径,起始弧度,结束弧度,旋转方向(默认false顺时针) ogc.closePath();//闭合路径 ogc.stroke(); ogc.restore(); //恢复绘图
其中,beginPath()方法和closePath()方法完全是两个不同的概念,当初被这个绕了好久……关于canvas的基础知识就不说了,这里主要说说当时的思路吧,用arc()方法绘制基于角度的直线,也是一个有趣的用法。
function toDraw() { var oDate = new Date(); var oHours = oDate.getHours(); var oMin = oDate.getMinutes(); var oSen = oDate.getSeconds(); ogc.save(); var x = 100; var y = 100; var r = 100; var oHoursValue = (-90 + oHours * 30 + oMin / 2) * Math.PI / 180; //时针弧度 var oMinValue = (-90 + oMin * 6 + oSen / 10) * Math.PI / 180; //分针弧度 var oSenValue = (-90 + oSen * 6) * Math.PI / 180; //秒针弧度 ogc.beginPath(); for (var i = 0; i < 60; i++) { ogc.moveTo(x, y); ogc.arc(x, y, r, 6 * i * Math.PI / 180, 6 * (i + 1) * Math.PI / 180); }; ogc.closePath(); ogc.stroke(); ogc.beginPath(); ogc.fillStyle = '#fff'; ogc.moveTo(x, y); ogc.arc(x, y, r * 19 / 20, 0, 360 * Math.PI / 180); ogc.closePath(); ogc.fill(); //填充 ogc.beginPath(); ogc.lineWidth = 3; for (var i = 0; i < 12; i++) { ogc.moveTo(x, y); ogc.arc(x, y, r, 30 * i * Math.PI / 180, 30 * (i + 1) * Math.PI / 180); }; ogc.closePath(); ogc.stroke(); ogc.beginPath(); ogc.fillStyle = '#fff'; ogc.moveTo(x, y); ogc.arc(x, y, r * 18 / 20, 0, 360 * Math.PI / 180); ogc.closePath(); ogc.fill(); //填充 //时针 ogc.beginPath(); ogc.moveTo(x, y); ogc.arc(x, y, r * 12 / 20, oHoursValue, oHoursValue); ogc.closePath(); ogc.stroke(); //分针 ogc.beginPath(); ogc.moveTo(x, y); ogc.arc(x, y, r * 16 / 20, oMinValue, oMinValue); ogc.closePath(); ogc.stroke(); //秒针 ogc.beginPath(); ogc.lineWidth = 1.5; ogc.moveTo(x, y); ogc.arc(x, y, r * 18 / 20, oSenValue, oSenValue); ogc.closePath(); ogc.stroke(); ogc.restore(); for (var i = 0; i <= 330; i += 30) { ogc.save(); ogc.translate(x, y); //移动画布的原点 ogc.rotate((i) * Math.PI / 180); //旋转图形(旋转的中心基于画布原点) ogc.translate(0, -r * 15 / 20); ogc.rotate((-i) * Math.PI / 180); //旋转图形(旋转的中心基于画布原点) ogc.translate(0, r * 16.5 / 20); ogc.font = r * 0.2+"px Arial"; ogc.textAlign = "center"; i == 0 ? ogc.fillText(12, 0, -r * 15 / 20) : ogc.fillText(i / 30, 0, -r * 15 / 20); ogc.restore(); }; } setInterval(toDraw, 1000);
先循环60次扇形画分针刻度,然后画个圆盖住,再然后循环12次时针刻度,然后画个圆盖住,三针,数字表盘,封装函数,每秒重绘执行一次。(代码执行状态如下图)
有点ps图层的意思,不过现在来看这段代码实在是看不下去,尤其是最后绘制数字表盘的循环,也是佩服自己当时的脑洞怎么开的这么大……
如果换个思路,已知圆心坐标和半径,能否利用lineTo()方法去绘制刻度和表针呢?
ogc.save(); ogc.translate(x, y); for (var angle = 0; angle < 360; angle += 6) { var tickWidth = angle % 5 === 0 ? 15 : 15 / 2; var radian = angle * Math.PI / 180; ogc.beginPath(); ogc.moveTo((r - tickWidth) * Math.cos(radian), (r - tickWidth) * Math.sin(radian)); ogc.lineTo(r * Math.cos(radian), r * Math.sin(radian)); ogc.strokeStyle = 'rgba(100, 140, 230, 0.7)'; ogc.stroke(); ogc.beginPath(); ogc.textAlign = "center"; ogc.textBaseline = "middle"; ogc.font = '12px Helvetica'; if (angle % 30 === 0) { var num = angle / 30 - 9 > 0 ? angle / 30 - 9 : angle / 30 + 3; //刻度 ogc.fillText(num, (r - 30) * Math.cos(radian), (r - 30) * Math.sin(radian)); }; } ogc.restore();
基于之前的代码删改了下,只改了刻度与表盘的绘制,效果还是可以的。
lineTo()方法需要传递一个坐标,至于坐标点的位置怎么得到,就要用到三角函数了,直接上图,方便理解。