用canvas制作一个时钟

我想熟悉一下canvas的使用,参考一个例子做了一个能动态展示当前时刻的canvas时钟。

先看效果:

用canvas制作一个时钟_第1张图片

实现思路:

使用canvas绘图第一步肯定是先获取canvas元素对象,并定义上下文。

var clock = document.getElementById("clock");
clock.style.backgroundColor = "black";
var graph = null;
graph = clock.getContext("2d");

然后开始绘制内外圆:

beginPath()方法是路径的开始,stroke()是绘制前面beginPath()之间定义的路径,假如你想画两条两条颜色等设置不一样的路径,那你就需要各自用一个beginPath()去开始路径,否则在同一个beginPayh()后面的两个不同的strokeStyle样式只能表现出后定义的那一个设置。比如说我在下面代码中对画内圆部分前加一行graph.strokeStyle = "white"的话,得不到两个不同颜色的圆,两个圆都会是白色的。

 

graph.beginPath();
//画外圆
graph.strokeStyle = "yellow";
graph.moveTo(600,300);
graph.arc(300,300,outside_circle_r,0,2*Math.PI,false);
//画内圆
graph.moveTo(590,300);
graph.arc(300,300,inside_circle_r,0,2*Math.PI,false);
graph.stroke();

刻度:

每一条线段的绘制都需要知道两个端点的坐标,刻度端点的坐标就需要使用三角函数了,可以以默认的左上角为原点,也可以使用translate方法把坐标原点移动到时钟的圆心,后者计算坐标更简单。但是我用的是笨方法,以左上角为坐标原点来想办法计算各个刻度的坐标值,小时刻度和分钟刻度长度不一样,但坐标计算方法是一样的,我写了一个函数drawHourAndMinuteLine去封装了计算过程,然后针对小时刻度和分钟刻度用对应传参调用了两次。刻度部分我是在看参考例子前做的,以画布左上角作为坐标原点,实现过程比较复杂,其实没有必要,所以就不解释这部分我写的代码了。这一部分可以参考文章开头的参考例子链接,以时钟中心点作为圆点更简单。

//画小时刻度
var hour_len = 30;//刻度长度
var hourAngleArray = [];
for(let i = 0;i < 4;i++){
hourAngleArray.push(i*Math.PI/6);
}
drawHourAndMinuteLine(hourAngleArray,hour_len);

//画分钟刻度
var minuteAngleArray = [];
var minute_len = 10;//刻度长度
for(let i = 0;i < 15;i++){
minuteAngleArray.push(i*Math.PI/30);
}
drawHourAndMinuteLine(minuteAngleArray,minute_len);

文本:

绘制文本的基本过程都是相同的,不同的只是样式,坐标参数,所以我也写了函数封装。

function drawText(fillStyle,font,textAlign,textBaseline,size,x,y){
graph.fillStyle = fillStyle;
graph.font = font;
graph.textAlign = textAlign;
graph.textBaseline = textBaseline;
graph.fillText(size,x,y);
}

比如说我绘制上下左右的12、6、9、3数字文本的时候就直接调用这个函数:

//画刻度文本值
drawText("yellow","bold 18px Arial","center","middle","12",300,48);
drawText("yellow","bold 18px Arial","center","middle","3",552,300);
drawText("yellow","bold 18px Arial","center","middle","6",300,552);
drawText("yellow","bold 18px Arial","center","middle","9",48,300);

时针、分针和秒针:

为了实现在当前时刻时针指向正确数字的功能实现,必须把时间和时针转过的角度之间建立一个关系,还要确定每根针的长度。这一部分参考了例子,以时钟圆心作为原点实现。

首先获得时间,并在角度和时间之间建立数学关系:

var hourLength = 180;
var minuteLength = 204;
var secondLength = 240;

var date = new Date();
var hour = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();

if (hour > 12) {
hour -= 12;
}

var hourAngle = (hour * 30 - 90) * Math.PI / 180;
var minutesAngle = (minutes * 6 - 90) * Math.PI / 180;
var secondsAngle = (seconds * 6 - 90) * Math.PI / 180;

绘制三根针:

//分针
graph.save();
graph.beginPath();
graph.translate(300, 300);
graph.strokeStyle = "yellow";
graph.moveTo(0, 0);
graph.lineTo(minuteLength * Math.cos(minutesAngle), minuteLength * Math.sin(minutesAngle));
graph.stroke();

//秒针
graph.save();//保存新的圆点
graph.beginPath();
graph.strokeStyle = "red";
graph.moveTo(0, 0);
graph.lineTo(secondLength * Math.cos(secondsAngle), secondLength * Math.sin(secondsAngle));
graph.stroke();
graph.stroke();

//时针
graph.beginPath();
graph.strokeStyle = "blue";
graph.moveTo(0, 0);
graph.lineTo(hourLength * Math.cos(hourAngle), hourLength * Math.sin(hourAngle));
graph.stroke();
graph.restore();
graph.restore();

上面代码我用到了两次save()和两次restore()方法,save()方法用于保存前面的各种设置,restore()方法用于退回到上一次save()所保存的设置。因为在我的代码中,只有绘制三根针的时候原点设置才是时钟的中心,所以我的使用主要是为了保证只有在这一部分代码中,原点的设置是时钟中心。

时钟上方的报时文本:

文本绘制还是使用前面提到的一个自定义函数,但需要随着时间更新文本,如果只是简单地每秒绘制一次文本,那不同文本会在同一个区域重叠,所以必须在绘制新的文本时把前一秒绘制的文本去掉,我的办法是每次画一个和背景色相同颜色的矩形框把文本盖住。

/*画出时间文本并定时清除*/
function drawTimeText(){
var date = new Date();
var timeText1 = date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
var timeText2 = date.getFullYear()+"年"+(date.getMonth()+1)+"月"+date.getDate()+"日";
drawText("yellow","bold 30px Arial","center","top",timeText1,295,162);
drawText("yellow","bold 16px Arial","center","top",timeText2,295,200);
setTimeout("drawClearRect()",980);//清除矩形区域的内容
}

function dateText(time){
graph.beginPath();
//表内文本
drawTimeText();
setInterval("drawTimeText()",time);
graph.stroke();

graph.restore();
}

时针变化:

最后我把前面所有绘制部分的代码放到一个函数里,并添加两行清除整个时钟的代码,使用的是clearRect()方法清除区域,否则你会得到一圈60根秒针,然后用setInterval()每秒调用一次这个函数。

if (clock.getContext) {
drawClock();
dateText(1001);
setInterval(drawClock, 1000);
}

上面dateText给的时间1001ms是为了把显示报时文本的时间和drawClock这个绘制整个时钟的函数中清除整个时钟的时刻错开,但这也是一个bug,随着时间它所引起的时间差会越来越大,暂时没有想到怎么解决这个问题。

 

完整代码:

Clock

Canvas

 

 

你可能感兴趣的:(前端开发)