canvas标签是HTML5新提出的用于绘制图像的标签,但是canvas本身并没有绘制图像的能力,主要是基于javascript来完成实际的绘制任务,通过getContext()方法来获取一个canvas的上下文对象,这个对象身上提供了绘制图形的属性和方法。接下来是使用canvas绘制时钟的案例。
定义一个canvas标签
<canvas id="canvas1" width="800" height="600"></canvas>
获取canvas对象和context对象
// 获取canvas对象
let canvas1 = document.querySelector("#canvas1");
// 获取canvas上下文context对象
let ctx = canvas1.getContext("2d");
调整画板位置和初始角度
// 保存画板初始状态,一定要保存一个初始状态,否则会有大麻烦
ctx.save();
// 移动坐标轴到画板中央
ctx.translate(400, 300);
// 旋转坐标轴初始方向到-90度方向,即表盘0点方向
ctx.rotate(-2 * Math.PI / 4);
// 再保存一次状态状态
ctx.save();
绘制表盘
// 在每次绘制之前应先清空画布
ctx.clearRect(0, 0, 800, 600);
// 开始路径
ctx.beginPath();
// 绘制圆形,参数依次为圆心的x坐标、y坐标、半径、起始角度和结束角度
ctx.arc(0, 0, 200, 0, 2 * Math.PI);
// 设置线条样式
ctx.strokeStyle = "grey";
// 设置线条宽度
ctx.lineWidth = 10;
// 绘制线条
ctx.stroke();
// 闭合路径
ctx.closePath();
绘制刻度
// 绘制分针刻度
for (let i = 0; i < 60; i++) {
// 每次旋转 2 * Pi / 60
ctx.rotate(2 * Math.PI / 60);
ctx.beginPath();
// 起点位置
ctx.moveTo(180, 0);
// 终点位置
ctx.lineTo(190, 0);
// 设置线条颜色
ctx.strokeStyle = "orange";
// 设置线条宽度
ctx.lineWidth = 3;
// 绘制线条
ctx.stroke();
ctx.closePath();
}
// 由于这里旋转了坐标轴,所以要恢复至上一个状态
ctx.restore();
// 保存状态
ctx.save();
// 绘制时针刻度,与分针刻度同理,旋转度数需要调整
for (let i = 0; i < 12; i++) {
ctx.rotate(2 * Math.PI / 12);
ctx.beginPath();
ctx.moveTo(180, 0);
ctx.lineTo(200, 0);
ctx.strokeStyle = "grey";
ctx.lineWidth = 5;
ctx.stroke();
ctx.closePath();
}
// 这里也旋转了坐标轴,因此要恢复至上一个的状态
ctx.restore();
// 保存状态
ctx.save();
获取当前时间
// 获取当前系统时间
let time = new Date();
// 获取时,分,秒
let hour = time.getHours();
let min = time.getMinutes();
let sec = time.getSeconds();
// 判断小时是否超过12,如果超过则减去12
hour = hour > 12 ? hour - 12 : hour;
绘制时分秒指针
// 绘制秒针
ctx.beginPath();
// 旋转坐标轴, 一分钟有60秒,所以 2 * PI / 60 * sec 则为当前秒针所在的角度
ctx.rotate(2 * Math.PI / 60 * sec);
ctx.moveTo(-30, 0);
ctx.lineTo(170, 0);
ctx.strokeStyle = "red";
ctx.lineWidth = 3;
ctx.stroke();
ctx.closePath();
// 这里同理,要恢复至绘制前的状态
ctx.restore();
// 保存状态
ctx.save();
// 绘制分针
ctx.beginPath();
// 旋转坐标轴,分针角度为当前 分 加上 秒 的影响 一小时有60分和3600秒,
// 所以当前分针角度为 2 * PI / 60 * min + 2 * PI / 3600 * sec
ctx.rotate(2 * Math.PI / 60 * min + 2 * Math.PI / 3600 * sec);
ctx.moveTo(-20, 0);
ctx.lineTo(160, 0);
ctx.strokeStyle = "darkblue";
ctx.lineWidth = 5;
ctx.stroke();
ctx.closePath();
// 这里同理,要恢复至绘制前的状态
ctx.restore();
// 保存状态
ctx.save();
// 绘制时针
ctx.beginPath();
// 旋转坐标轴,分针角度为当前 时 加上 分和秒 的影响, 一天有12小时,12*60分和12*3600秒,
// 所以当前时针角度为 2 * PI / 12 * hour + 2 * PI / 12 / 60 * min + 2 * PI / 12 / 3600 * sec
ctx.rotate(2 * Math.PI / 12 * hour + 2 * Math.PI / 12 / 60 * min + 2 * Math.PI / 12 / 3600 * sec);
ctx.moveTo(-10, 0);
ctx.lineTo(140, 0);
ctx.strokeStyle = "black";
ctx.lineWidth = 6
ctx.stroke();
ctx.closePath();
绘制表盘圆心
// 绘制表盘中心圆点
ctx.beginPath();
ctx.arc(0, 0, 10, 0, 2 * Math.PI)
ctx.fillStyle = 'black';
ctx.fill();
ctx.closePath();
所有都绘制完之后,别忘了要恢复至最初始的状态!!
// 恢复至第二次保存的状态
ctx.restore();
// 恢复至初始状态
ctx.restore();
封装绘制函数,设置计时器来绘制
// 将上面的代码封装进renderClock函数
function renderClock(){
...
}
// 设置定时器,每隔一秒调用一次这个函数
setInterval(function () {
renderClock()
}, 1000);