写在之前
canvas 元素中提供了看似简单的绘图方法,但仔细挖掘,可以以此做出非常复杂而漂亮的图形。随着 API 的逐渐完善,我相信自己能进行更多有意思的尝试。
时钟的 canvas + js 实现主要是应用上下文的简单变换、文本添加及周期性调用方法 setInterval(func, delay)。在绘制表盘及时针过程注意使用save()及restore()方法添加用以保存或返回上一个画布设置属性。
思路:编写两个构造函数,分别代表表盘和时针,最后利用函数加以实现。
具体效果可转接到我的Codepen-->效果演示
代码实现
1, html 部分
<body>
<canvas id="plate">你看不见我!</canvas>
</body>
2, javascript 部分
<script>
var plate = document.getElementById("plate");
var ctp = plate.getContext("2d");
document.body.style.backgroundColor = "#FFFACD";
plate.setAttribute(‘style‘, ‘margin:50px 0 0 300px‘);
plate.width = 600;
plate.height = 600;
//创建时间对象
var date = new Date();
var baseTime; //表示各指针旋转基数
var counter = 0;
//构造表盘
// ct-->上下文, radius-->表盘外延半径, textLen-->文本高度, lineEnd-->刻度线末端y坐标/
function DrawPlate(ct, radius, textHight, lineLen) {
this.ct = ct;
this.radius = radius;
this.textHight = textHight;
this.lineLen = lineLen;
}
//添加方法,绘制表盘外延
DrawPlate.prototype.drawPlateCir = function(color) {
this.ct.beginPath();
this.ct.save();
this.ct.translate(300, 300);
this.ct.arc(0, 0, this.radius, 0, 2*Math.PI, false);
this.ct.strokeStyle = color;
this.ct.stroke();
this.ct.closePath();
this.ct.restore();
}
//添加方法,绘制表盘刻度
DrawPlate.prototype.drawCalibration = function(color) {
//大刻度
for(var i = 1; i <= 12 ; i++) {
this.ct.beginPath();
this.ct.save();
this.ct.translate(300, 300);
this.ct.rotate(i*Math.PI/6);
this.ct.moveTo(0, -this.radius);
this.ct.lineTo(0, this.lineLen - this.radius);
this.ct.lineWidth = 5;
this.ct.strokeStyle = color;
this.ct.stroke();
this.ct.closePath();
this.ct.restore();
}
//小刻度
for(var j = 0; j <= 60; j++) {
this.ct.beginPath();
this.ct.save();
this.ct.translate(300, 300);
this.ct.rotate(j*Math.PI/30);
this.ct.moveTo(0, -this.radius);
this.ct.lineTo(0, this.lineLen - this.radius);
this.ct.lineWidth = 2;
this.ct.strokeStyle = color;
this.ct.stroke();
this.ct.closePath();
this.ct.restore();
}
};
//添加指示文本
DrawPlate.prototype.drawPlateText = function() {
for(var i = 1; i <= 12; i++) {
this.ct.beginPath();
this.ct.save();
this.ct.translate(300, 300);
this.ct.font = "bold " + this.textHight + "px Times New Roman";
this.ct.textAlign = "center";
this.ct.textBaseline = "middle";
this.ct.fillText(i, -(this.radius - this.lineLen - 0.6*this.textHight)*Math.sin(-i*2*Math.PI/12), -(this.radius - this.lineLen - 0.6*this.textHight)*Math.cos(-i*2*Math.PI/12));
this.ct.closePath();
this.ct.restore();
}
};
//构造指针函数
function DrawNeedles(ct, needleEnd, centerCirR) {
this.ct = ct;
this.needleEnd = needleEnd;
this.centerCirR = centerCirR;
}
//绘制中心园
DrawNeedles.prototype.addCenterCir = function (color) {
this.ct.beginPath();
this.ct.save();
this.ct.translate(300, 300);
this.ct.arc(0, 0, this.centerCirR, 0, 2*Math.PI, false);
this.ct.fillStyle = color;
this.ct.fill();
this.ct.closePath();
this.ct.restore();
};
//绘制指针方法
DrawNeedles.prototype.addNeedles = function (needleName, needleLen, lineW, color) {
var h = date.getHours(), m = date.getMinutes(), s = date.getSeconds();
this.ct.beginPath();
this.ct.save();
this.ct.translate(300, 300);
switch(needleName){
case "hr":
if(h > 12) {
h = h -12;
}
baseTime = 12;
this.ct.rotate((h + m/60 + s/3600 + counter/1000/3600)*2*Math.PI/baseTime);
this.ct.moveTo(0, this.needleEnd);
this.ct.lineTo(0, this.needleEnd - needleLen);
break;
case "min":
baseTime = 60;
this.ct.rotate((m + s/60 + counter/1000/60)*2*Math.PI/baseTime);
this.ct.moveTo(0, this.needleEnd);
this.ct.lineTo(0, this.needleEnd - needleLen);
break;
case "sec":
baseTime = 60;
this.ct.rotate((s + counter/1000)*2*Math.PI/baseTime);
this.ct.moveTo(0, this.needleEnd);
this.ct.lineTo(0, this.needleEnd - needleLen);
break;
default:
break;
}
this.ct.lineWidth = lineW;
this.ct.lineCap = "round"; //指针末端为圆头
this.ct.strokeStyle = color;
this.ct.stroke();
this.ct.closePath();
this.ct.restore();
};
//实现
function drawClock() {
ctp.clearRect(0, 0, plate.width, plate.height);
var p = new DrawPlate(ctp, 200, 30, 10);
var n = new DrawNeedles(ctp, 20, 5);
p.drawPlateCir("green");
p.drawPlateText();
p.drawCalibration("green");
n.addCenterCir("green");
//时针
n.addNeedles("hr", 100, 3, "black");
//分针
n.addNeedles("min", 145, 2, "black");
//秒针
n.addNeedles("sec", 170, 1, "red");
}
function index(delay) {
drawClock();
setInterval(function() {
counter = counter + delay;
drawClock();
}, delay);
}
index(10);
</script>