技术点:
- 状态保存
context.save()
- 状态恢复
context.restore()
- 旋转
context.rotate(弧度)
- 平移
context.translate(x,y)
x,y 是需要移动到的目标位置坐标 - 缩放
context.scale(1.5,1.5)
1.5,1.5 是缩放比例, 将原来的画布放大1.5倍 - 画圆弧
context.arc(x,y,r,初始弧度, 最终弧度)
- 清空矩形内容
context.clearRect(x,y,width,height)
- 时间(时,分,秒)的角度换算
效果图如下
上代码
<canvas id="clock" width="400" height="400"></canvas>
canvas {
border: 1px solid #000;
display: block;
margin: 100px auto;
}
function Clock(options) {
this._init(options);
}
Clock.prototype = {
constructor: Clock,
_init: function(options) {
options = options || {};
this.width = options.width || 400;
this.height = options.height || 400;
this.r = options.r || 180;
this.clockR = options.r - 20 || 160;
this.ctx = options.ctx || document.getElementById('clock').getContext('2d');
},
// 渲染表盘
renderClock: function() {
// 保存状态
this.ctx.save();
// 绘制外面的圈
this.ctx.arc(0, 0, this.r, 0, 2 * Math.PI);
this.ctx.strokeStyle = '#408000';
this.ctx.lineWidth = 10;
this.ctx.stroke();
// 恢复状态
this.ctx.restore();
},
renderPoint: function() {
this.ctx.save();
this.ctx.beginPath();
this.ctx.fillStyle = '#FF6666';
this.ctx.arc(0, 0, 8, 0, 2 * Math.PI);
this.ctx.fill();
this.ctx.restore();
},
// 渲染刻度
renderScale: function() {
// 保存状态
this.ctx.save();
// 绘制刻度
this.ctx.beginPath();
for (var i = 0; i < 60; i++) {
var x = Math.cos(i * 6 * Math.PI / 180) * this.clockR;
var y = Math.sin(i * 6 * Math.PI / 180) * this.clockR;
this.ctx.beginPath();
var r = 3;
var text = 1;
if (i % 5 == 0) {
r = 5;
this.ctx.save();
var v = parseInt(i / 5);
text = v == 0 ? 12 : v;
this.ctx.textAlign = 'center';
this.ctx.textBaseline = 'middle';
this.ctx.font = '18px Monaco';
this.ctx.fillStyle = '#000';
var xx = Math.cos(i * 6 * Math.PI / 180) * (this.clockR + 15);
var yy = Math.sin(i * 6 * Math.PI / 180) * (this.clockR + 15);
this.ctx.translate(xx, yy);
this.ctx.rotate(90 * Math.PI / 180);
this.ctx.fillText(text, 0, 0);
this.ctx.restore();
}
this.ctx.beginPath();
this.ctx.arc(x, y, r, 0, 2 * Math.PI);
this.ctx.fillStyle = '#FF8000';
this.ctx.fill();
}
// 恢复状态
this.ctx.restore();
},
// 渲染时针
renderHour: function(dateTime) {
this.ctx.save();
var hour = dateTime.getHours();
var minute = dateTime.getMinutes();
var second = dateTime.getSeconds();
// 每秒6度
var deg = ((hour % 12) * 30 * Math.PI / 180);
// 计算分针和秒针旋转过的角度对应的时针旋转过的角度
var otherDeg = ((minute * 6 + 6 / 60 * second) / 60 * 5) * Math.PI / 180;
deg += otherDeg;
this.ctx.rotate(deg);
this.ctx.beginPath();
this.ctx.moveTo(-15, 0);
this.ctx.lineTo(90, 0);
this.ctx.strokeStyle = '#0094ff';
this.ctx.lineWidth = 8;
this.ctx.stroke();
this.ctx.restore();
},
// 渲染分针
renderMiute: function(dateTime) {
this.ctx.save();
var minute = dateTime.getMinutes();
var second = dateTime.getSeconds();
// 每秒6度
var deg = (minute * 6 * Math.PI / 180) + (6 / 60 * second * Math.PI / 180);
this.ctx.rotate(deg);
this.ctx.beginPath();
this.ctx.moveTo(-20, 0);
this.ctx.lineTo(120, 0);
this.ctx.strokeStyle = '#333333';
this.ctx.lineWidth = 5;
this.ctx.stroke();
this.ctx.restore();
},
// 渲染秒针
renderSecond: function(dateTime) {
this.ctx.save();
var second = dateTime.getSeconds();
// 每秒6度
var deg = second * 6 * Math.PI / 180;
this.ctx.rotate(deg);
this.ctx.beginPath();
this.ctx.moveTo(-30, 0);
this.ctx.lineTo(150, 0);
this.ctx.lineWidth = 2;
this.ctx.strokeStyle = '#FF6666'
this.ctx.stroke();
this.ctx.restore();
},
render: function(dateTime) {
this.ctx.save();
this.ctx.lineCap = 'round';
this.ctx.clearRect(0, 0, this.width, this.height);
this.ctx.beginPath();
this.ctx.translate(this.width / 2, this.width / 2);
this.ctx.rotate(-Math.PI / 2);
this.renderClock();
this.renderScale();
this.renderHour(dateTime);
this.renderMiute(dateTime);
this.renderSecond(dateTime);
this.renderPoint();
this.ctx.restore();
}
}
var clock = new Clock();
clock.render(new Date());
setInterval(function() {
clock.render(new Date());
}, 1000)