看到有不少人用canvas写钟表,今天也来加入他们,自己实现个。
效果图:
实现代码如下:
<html> <head> <title>Html5 canvas 钟表</title> <style type="text/css"> canvas{ border:2px solid Gray; background-color:Gray;} </style> </head> <body> <canvas width="250" height="250" id="canvas"></canvas> <script type="text/javascript"> //时钟对象 function clock(canvasID) { var TT = new Date(); var HH = TT.getHours(); //时,分,秒 this.HH = HH > 12 ? HH - 12 : HH; this.MM = TT.getMinutes(); this.SS = TT.getSeconds(); var canvas = document.getElementById(canvasID); this.context = canvas.getContext("2d"); //宽,高,半径,表盘外边框宽度,品牌文字 this.W = canvas.offsetWidth; this.H = canvas.offsetHeight; this.R = this.W / 2; this.B = 12; this.Brand = "SIMILAR"; } //初始化设置 clock.prototype.cxtInit = function () { var cxt = this.context; cxt.save(); //保存画布原始状态 cxt.lineWidth = 3; //笔刷宽度为3 cxt.strokeStyle = "White"; //笔刷颜色为白色 cxt.translate(this.R, this.R); //定位中心点 cxt.rotate(-Math.PI / 2); //旋转负90度 cxt.save(); //保存初始化设置后的状态 } //画表盘 clock.prototype.drawCCFace = function () { var cxt = this.context; //外框大圆 cxt.lineWidth = this.B; //笔刷宽度 cxt.beginPath(); cxt.arc(0, 0, this.R - this.B, 0, 2 * Math.PI); cxt.stroke(); cxt.closePath(); //填充黑色 cxt.fillStyle = "Black"; cxt.fill(); cxt.restore(); cxt.save(); //中心小圆 cxt.lineWidth = 3; cxt.beginPath(); cxt.arc(0, 0, 3, 0, 2 * Math.PI); cxt.stroke(); cxt.closePath(); //填充白色 cxt.fillStyle = "White"; cxt.fill(); cxt.restore(); cxt.save(); } //画时针刻度 clock.prototype.drawHHScale = function () { var cxt = this.context; cxt.lineWidth = 3; cxt.beginPath(); for (var i = 1; i < 13; i++) { cxt.rotate(Math.PI / 6); cxt.moveTo(this.R - this.B - 15, 0); cxt.lineTo(this.R - this.B, 0); } cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); } //画分针刻度 clock.prototype.drawMMScale = function () { var cxt = this.context; cxt.lineWidth = 1; cxt.beginPath(); for (var i = 0; i < 60; i++) { if (i % 5 != 0) { cxt.moveTo(this.R-this.B-8, 0); cxt.lineTo(this.R-this.B, 0); } cxt.rotate(Math.PI / 30); } cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); } //画数字 clock.prototype.drawCCNumber = function () { var cxt = this.context; cxt.rotate(Math.PI / 2); for (i = 0; i < 12; i++) { var num = (i + 3 > 12) ? i + 3 - 12 : i + 3; var numX = Math.round(Math.cos(i * Math.PI / 6) * (this.R - this.B - 30)); var numY = Math.round(Math.sin(i * Math.PI / 6) * (this.R - this.B - 30)); cxt.font = ‘bold 12px 微软雅黑‘; cxt.fillStyle = "White"; cxt.fillText(num, numX - 5, numY + 5); } cxt.restore(); cxt.save(); } //画时针 clock.prototype.drawHHHand = function () { var cxt = this.context; cxt.rotate((Math.PI / 6) * this.HH + (Math.PI / 360) * this.MM + (Math.PI / 21600) * this.SS); cxt.lineCap = "round"; cxt.beginPath(); cxt.moveTo(0, 0); cxt.lineTo(this.R / 2, 0); cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); } //画分针 clock.prototype.drawMMHand = function () { var cxt = this.context; cxt.rotate((Math.PI / 30) * this.MM + (Math.PI / 1800) * this.SS); cxt.lineCap = "round"; cxt.beginPath(); cxt.moveTo(0, 0); cxt.lineTo(this.R - this.B - 20, 0); cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); } //画秒针 clock.prototype.drawSSHand = function () { var cxt = this.context; cxt.rotate(this.SS * Math.PI / 30); cxt.lineWidth = 2; cxt.beginPath(); cxt.moveTo(-20, 0); cxt.lineTo(this.R - this.B - 5, 0); cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); } //画品牌 clock.prototype.drawCCBrand = function () { var cxt = this.context; cxt.rotate(Math.PI / 2); cxt.font = "15px Arial" cxt.fillStyle = "White"; cxt.fillText(this.Brand, - 25, -(this.R - 80), 50); cxt.restore(); cxt.save(); } //还原画布到原始状态 clock.prototype.cxtBackOriginal = function () { var cxt = this.context; cxt.restore(); cxt.restore(); } //主函数 function Main() { var c = new clock("canvas"); //初始化 c.cxtInit(); //表盘 c.drawCCFace(); //刻度,数字 c.drawHHScale(); c.drawMMScale(); c.drawCCNumber(); //指针 c.drawHHHand(); c.drawMMHand(); c.drawSSHand(); //品牌 c.drawCCBrand(); //还原画布 c.cxtBackOriginal(); } setInterval(Main, 1000); </script> </body> </html>
上面是初始版本,上面这个版本性能是极差的,因为每隔1秒就会创建1个新对象,即:new clock()
刚开始想到的解决方案是用 单例模式 ,但结果行不通,因为时间必须是实时的,如果用 单例模式 则时间就一直是第一次new clock()时的那个时间,因此也就不会走针。
之后修改如下:
<html> <head> <title>Html5 canvas 钟表</title> <style type="text/css"> canvas{ border:2px solid Gray; background-color:Gray;} </style> </head> <body> <canvas width="250" height="250" id="canvas"></canvas> <script type="text/javascript"> //时钟对象 function clock(canvasID) { //取得画布对象 var canvas = document.getElementById(canvasID); this.context = canvas.getContext("2d"); //宽,高,半径,表盘外边框宽度,品牌文字 this.W = canvas.offsetWidth; this.H = canvas.offsetHeight; this.R = this.W / 2; this.B = 12; this.Brand = "SIMILAR"; } //初始化设置 clock.prototype.cxtInit = function () { var cxt = this.context; cxt.save(); //保存画布原始状态 cxt.clearRect(0, 0, this.W, this.H); //清空画布 cxt.lineWidth = 3; //笔刷宽度为3 cxt.strokeStyle = "White"; //笔刷颜色为白色 cxt.translate(this.R, this.R); //定位中心点 cxt.rotate(-Math.PI / 2); //旋转负90度 cxt.save(); //保存初始化设置后的状态 } //画表盘 clock.prototype.drawCCFace = function () { var cxt = this.context; //外框大圆 cxt.lineWidth = this.B; //笔刷宽度 cxt.beginPath(); cxt.arc(0, 0, this.R - this.B, 0, 2 * Math.PI); cxt.stroke(); cxt.closePath(); //填充黑色 cxt.fillStyle = "Black"; cxt.fill(); cxt.restore(); cxt.save(); //中心小圆 cxt.lineWidth = 3; cxt.beginPath(); cxt.arc(0, 0, 3, 0, 2 * Math.PI); cxt.stroke(); cxt.closePath(); //填充白色 cxt.fillStyle = "White"; cxt.fill(); cxt.restore(); cxt.save(); } //画时针刻度 clock.prototype.drawHHScale = function () { var cxt = this.context; cxt.lineWidth = 3; cxt.beginPath(); for (var i = 1; i < 13; i++) { cxt.rotate(Math.PI / 6); cxt.moveTo(this.R - this.B - 15, 0); cxt.lineTo(this.R - this.B, 0); } cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); } //画分针刻度 clock.prototype.drawMMScale = function () { var cxt = this.context; cxt.lineWidth = 1; cxt.beginPath(); for (var i = 0; i < 60; i++) { if (i % 5 != 0) { cxt.moveTo(this.R-this.B-8, 0); cxt.lineTo(this.R-this.B, 0); } cxt.rotate(Math.PI / 30); } cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); } //画数字 clock.prototype.drawCCNumber = function () { var cxt = this.context; cxt.rotate(Math.PI / 2); for (i = 0; i < 12; i++) { var num = (i + 3 > 12) ? i + 3 - 12 : i + 3; var numX = Math.round(Math.cos(i * Math.PI / 6) * (this.R - this.B - 30)); var numY = Math.round(Math.sin(i * Math.PI / 6) * (this.R - this.B - 30)); cxt.font = ‘bold 12px 微软雅黑‘; cxt.fillStyle = "White"; cxt.fillText(num, numX - 5, numY + 5); } cxt.restore(); cxt.save(); } //画指针 clock.prototype.drawCCHand = function () { var tt = new Date(); //时,分,秒 var hh = tt.getHours() > 12 ? tt.getHours() - 12 : tt.getHours();var mm = tt.getMinutes(); var ss = tt.getSeconds(); var cxt = this.context; //画时针 cxt.rotate((Math.PI / 6) * hh + (Math.PI / 360) * mm + (Math.PI / 21600) * ss); cxt.lineCap = "round"; cxt.beginPath(); cxt.moveTo(0, 0); cxt.lineTo(this.R / 2, 0); cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); //画分针 cxt.rotate((Math.PI / 30) * mm + (Math.PI / 1800) * ss); cxt.lineCap = "round"; cxt.beginPath(); cxt.moveTo(0, 0); cxt.lineTo(this.R - this.B - 20, 0); cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); //画秒针 cxt.rotate(ss * Math.PI / 30); cxt.lineWidth = 2; cxt.beginPath(); cxt.moveTo(-20, 0); cxt.lineTo(this.R - this.B - 5, 0); cxt.stroke(); cxt.closePath(); cxt.restore(); cxt.save(); } //画品牌 clock.prototype.drawCCBrand = function () { var cxt = this.context; cxt.rotate(Math.PI / 2); cxt.font = "15px Arial" cxt.fillStyle = "White"; cxt.fillText(this.Brand, - 25, -(this.R - 80), 50); cxt.restore(); cxt.save(); } //还原画布到原始状态 clock.prototype.cxtBackOriginal = function () { var cxt = this.context; cxt.restore(); cxt.restore(); } //主函数 function Main() { var c = new clock("canvas"); setInterval(function () { //初始化 c.cxtInit(); //表盘 c.drawCCFace(); //刻度,数字 c.drawHHScale(); c.drawMMScale(); c.drawCCNumber(); //指针 c.drawCCHand(); //品牌 c.drawCCBrand(); //还原画布到原始状态 c.cxtBackOriginal(); }, 1000); } Main(); </script> </body> </html>
修改的地方:
1.>将画指针的3个方法(即,画时针,分针,秒针)合并成了一个方法( 即,画指针 drawCCHand() )
2.>将时间的获取放到了drawCCHand()方法里面,而不是在构造函数里面。
3.>在初始化方法cxtInit()里面加了一句代码:cxt.clearRect(0, 0, this.W, this.H); //清空画布。因为不会重新创建clock对象,所以每次画前要清空前一秒的画布内容
如果大家还有好的优化方案或建议,就分享下吧。
推广个新建的WEB前端QQ群:142512178
时间: 2024-10-25 18:53:21