使用h5 canvas实现时钟的动态效果

互联网 18-7-17
canvas 绘制好时钟界面,使用定时器定时重绘整个canvas,就实现了仿真动态时钟的效果。

难点在于:

  • 秒钟刻度和时钟刻度的绘制

  • 整点文字沿着内边圆形环绕

一切都是因为 ctx.measureText(text).width 存在,但 ctx.measureText(numText).height 不存在。打印测量结果,也只有一个宽度属性。文档中说canvas对于绘制文字的支持比较弱,从这一点上看 何止是弱。

直接设置基线和对齐方式为居中,似乎也存在一定误差,看起来总不是那么赏心悦目。下面的代码中两种方式都写了。

会走的时钟预览:

时间显示可能略有误差。

知识点和求解参考图

主要知识点为圆的坐标公式,和三角函数sin,cos计算。实际上,圆的坐标公式使用的并不多,引入求值反而可能复杂化。

下图是计算刻度线坐标和整点文字绘制坐标的参考图:

canvas画时钟效果的代码编写

下面是全部代码:

<!DOCTYPE html><html lang="en"><head>     <meta charset="UTF-8">     <meta name="viewport" content="width=1024, height=768,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">     <title>时钟</title></head><body><p style="margin: 50px">     <canvas width="300" height="300"></canvas>     <canvas width="200" height="200" style="background-color: #bbbbbb"></canvas>     <canvas width="200" height="200"></canvas>     <canvas width="200" height="200"></canvas></p><script>      var clockHelper = function (canvas, config) {         if (!config) {             config = {}         }        var ctx = canvas.getContext('2d');        var deColor = config.deColor ? config.deColor : '#333333';        var deConfig = {             ringWidth: config.ringWidth ? config.ringWidth : 6,//圆环宽度             ringColor: config.ringColor ? config.ringColor : deColor,//圆环颜色             hSaleL: config.hSaleL ? config.hSaleL : 8,//时刻度线长             hScaleWidth: config.hScaleWidth ? config.hScaleWidth : 4,//时刻度线宽             hScaleColor: config.hScaleColor ? config.hScaleColor : deColor,//时刻度颜色             msSaleL: config.msSaleL ? config.msSaleL : 4,//分秒刻度线长             msScaleWidth: config.msScaleWidth ? config.msScaleWidth : 2,//分秒刻度线宽             msScaleColor: deColor,//分秒刻度颜色             hFontSize: config.hFontSize ? config.hFontSize : 18,//整点文字大小             hHandWidth: config.hHandWidth ? config.hHandWidth : 10,//时针宽度             mHandWidth: config.mHandWidth ? config.mHandWidth : 5,//分针宽度             sHandWidth: config.sHandWidth ? config.sHandWidth : 2,//秒针宽度              hHandColor: config.hHandColor ? config.hHandColor : deColor,//时针颜色             mHandColor: config.mHandColor ? config.mHandColor : deColor,//分针颜色             sHandColor: config.sHandColor ? config.sHandColor : '#bb3333',//秒针颜色             handMode: ['ms', 's'].indexOf("" + config.handMode) !== -1 ? config.handMode : 's',//指针读秒模式,ms:毫秒,s:秒。             clockFaceColor: config.clockFaceColor ? config.clockFaceColor : '',         };        var ox = canvas.width / 2;        var oy = canvas.height / 2;        var width = canvas.width;        var height = canvas.height;          ctx.font = deConfig.hFontSize + "px 黑体";        //中线圆环半径         var ringR = (width < height) ? (width / 2 - deConfig.ringWidth / 2) : (height / 2 - deConfig.ringWidth / 2);        //内圆环半径         var ringInnerR = (width < height) ? (width / 2 - deConfig.ringWidth) : (height / 2 - deConfig.ringWidth);        var timer;        var timeSleep = 100;        var isStart = false;        function start() {             if (isStart) {                return;             }             isStart = true;            if (deConfig.handMode == 'ms') {                 timeSleep = 100;             } else {                 timeSleep = 1000;             }              ctx.clearRect(0, 0, width, height);             draw();              timer = setInterval(function () {                 if (isStart) {                     ctx.clearRect(0, 0, width, height);                     draw();                 }             }, timeSleep);          }        function stop() {             isStart = false;             clearInterval(timer)         }        function draw() {              beforeDraw();              drawCircleFace();             drawHands();              afterDraw();          }        function drawCircleFace() {              ctx.fillStyle = deConfig.ringColor;             ctx.strokeStyle = deConfig.ringColor;              ctx.lineWidth = deConfig.ringWidth;             ctx.beginPath();             ctx.arc(ox, oy, ringR, 0, Math.PI * 2);             ctx.stroke();            if (deConfig.clockFaceColor) {                 ctx.fillStyle = deConfig.clockFaceColor;                 ctx.fill();             }            var x1 = ox;            var y1 = oy;            var x2 = ox;            var y2 = oy;            var radin = 0;             ctx.lineWidth = deConfig.hScaleWidth;            // ctx.beginPath();             for (var i = 1; i <= 60; i++) {                 radin = i * 6 * Math.PI / 180;                 x1 = ox + ringInnerR * Math.sin(radin);                 y1 = oy - ringInnerR * Math.cos(radin);                if (i % 5 === 0) {                     ctx.lineWidth = deConfig.hScaleWidth;                     x2 = ox + (ringInnerR - deConfig.hSaleL) * Math.sin(radin);                     y2 = oy - (ringInnerR - deConfig.hSaleL) * Math.cos(radin);                      ctx.fillStyle = deConfig.hScaleColor;                    var numText = i / 5 + "";                    var textWidth = ctx.measureText(numText).width;                    var x3 = ox + (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.sin(radin);                    var y3 = oy - (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.cos(radin);                     ctx.textAlign = 'center';                     ctx.textBaseline = 'middle';                    //不设置文字居中,基线居中,自己计算。貌似都有误差。因为旋转过程中,角度变化,且文字宽高不尽相同                     // var x3 = ox + (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.sin(radin) - textWidth / 2;                     // var y3 = oy - (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.cos(radin) + deConfig.hFontSize/ 2;                     //x2,y2已经求过,化简为:                     // var x3 = x2 - deConfig.hFontSize * Math.sin(radin) - textWidth / 2;                     // var y3 = y2 + deConfig.hFontSize * Math.cos(radin) + textWidth / 2;                     //文字x轴向左偏移一半文字宽,使之水平居中;向下偏移一半高度,使之垂直居中。                     // 实际中发现,字高没法测(api无),而使用fontSize不准。但y轴加上字宽,位置倒是更对齐一些。                      // var x3 = x2 + textWidth / 2;                     // var y3 = y2 - deConfig.hFontSize / 2;                      ctx.fillText(numText, x3, y3);                  } else {                     ctx.lineWidth = deConfig.msScaleWidth;                     x2 = ox + (ringInnerR - deConfig.msSaleL) * Math.sin(radin);                     y2 = oy - (ringInnerR - deConfig.msSaleL) * Math.cos(radin);                 }                   ctx.beginPath();                 ctx.moveTo(x1, y1);                 ctx.lineTo(x2, y2);                 ctx.stroke();              }          }        //改变坐标中点,并旋转画布也许是更好的选择。         function drawHands() {             var date = new Date();            var h = date.getHours() % 12;            var m = date.getMinutes();            var s = date.getSeconds();            var ms = date.getMilliseconds();            // console.log(h + ":" + m + ":" + s);             //    时针              var hRadin = (h + m / 60 + s / 3600) * Math.PI * 2 / 12;            var mRadin = (m + s / 60) * Math.PI * 2 / 60;            var sRadin;            if (deConfig.handMode == 'ms') {                 sRadin = (s + ms / 1000) * Math.PI * 2 / 60;             } else {                 sRadin = s * Math.PI * 2 / 60;             }            var x = 0;            var y = 0;            var hDotR = deConfig.hHandWidth + 2;            var mDotR = 0.6 * hDotR            var sDotR = 0.5 * hDotR            //秒针半径             var sHandR = ringInnerR - deConfig.hSaleL * 2             //分针半径             var mHandR = 0.8 * sHandR;            //时针半径             var hHandR = 0.7 * mHandR;            //时针             ctx.beginPath();             ctx.lineWidth = deConfig.hHandWidth;             ctx.strokeStyle = deConfig.hHandColor;             ctx.strokeStyle = deConfig.hHandColor;             ctx.moveTo(ox, oy);             x = ox + hHandR * Math.cos(hRadin - Math.PI / 2);             y = oy + hHandR * Math.sin(hRadin - Math.PI / 2);             ctx.lineTo(x, y);             ctx.stroke();            //针尖。直接圆型了(矩形指针来绘制针尖,计算复杂。。。)             ctx.beginPath();             ctx.lineWidth = 0;             ctx.arc(x, y, deConfig.hHandWidth / 2, 0, 2 * Math.PI);             ctx.fill();            //中心             ctx.beginPath();            // ctx.lineWidth = hDotR;             ctx.arc(ox, oy, hDotR / 2, 0, Math.PI * 2);             ctx.fill();             ctx.stroke();            //分针             ctx.beginPath();             ctx.lineWidth = deConfig.mHandWidth;             ctx.strokeStyle = deConfig.mHandColor;             ctx.fillStyle = deConfig.mHandColor;             ctx.moveTo(ox, oy);             x = ox + mHandR * Math.cos(mRadin - Math.PI / 2);             y = oy + mHandR * Math.sin(mRadin - Math.PI / 2);             ctx.lineTo(x, y);             ctx.stroke();            //针尖。直接圆型了(矩形指针来绘制针尖,计算复杂。。。)             ctx.beginPath();             ctx.lineWidth = 0;             ctx.arc(x, y, deConfig.mHandWidth / 2, 0, 2 * Math.PI);             ctx.fill();            //中心             ctx.beginPath();             ctx.arc(ox, oy, mDotR / 2, 0, Math.PI * 2);             ctx.stroke();            //秒针             ctx.beginPath();             ctx.strokeStyle = deConfig.sHandColor;             ctx.fillStyle = deConfig.sHandColor;             ctx.lineWidth = deConfig.sHandWidth;            //秒针有长短两线             x = ox - sHandR / 4 * Math.cos(sRadin - Math.PI / 2);             y = oy - sHandR / 4 * Math.sin(sRadin - Math.PI / 2);             ctx.moveTo(x, y);             x = ox + sHandR * Math.cos(sRadin - Math.PI / 2);             y = oy + sHandR * Math.sin(sRadin - Math.PI / 2);             ctx.lineTo(x, y);             ctx.stroke();            //针尖。直接圆型了(矩形指针来绘制针尖,计算复杂。。。)             ctx.beginPath();             ctx.lineWidth = 0;             ctx.arc(x, y, deConfig.sHandWidth / 2, 0, 2 * Math.PI);             ctx.fill();            //中心             ctx.beginPath();             ctx.fillStyle = deColor;             ctx.arc(ox, oy, sDotR, 0, Math.PI * 2);             ctx.fill();             ctx.stroke();          }        function beforeDraw() {             if (typeof exp.beforeDraw === 'function') {                 exp.beforeDraw(ctx, deConfig);             }         }        function afterDraw() {             if (typeof exp.afterDraw === 'function') {                 exp.afterDraw(ctx, deConfig);             }         }        var exp = {             start: start,             stop: stop,             beforeDraw: null,             afterDraw: null,         }        return exp;       }    var clockCanvas1 = document.getElementsByTagName('canvas')[0];    var clockCanvas2 = document.getElementsByTagName('canvas')[1];    var clockCanvas3 = document.getElementsByTagName('canvas')[2];    var clockCanvas4 = document.getElementsByTagName('canvas')[3];    var clock = clockHelper(clockCanvas1, {mHandColor: '#3333bb', sHandColor: '#bb3333'});     clock.start();     setTimeout(function () {         clock.stop()     }, 5000)     setTimeout(function () {         clock.start();     }, 8000)      clockHelper(clockCanvas2, {         mHandColor: 'green',         hHandWidth: 6,         mHandWidth: 4,         hFontSize: 14,         hScaleWidth: 2,         handMode: 'ms'     }).start();       clockHelper(clockCanvas2, {         mHandColor: 'green',         hHandWidth: 6,         mHandWidth: 4,         hFontSize: 14,         hScaleWidth: 2,         handMode: 'ms'     }).start();       clockHelper(clockCanvas3, {         deColor: '#bbbbbb',         sHandColor: '#bbbbbb',         clockFaceColor: '#112233',//钟面         hHandWidth: 6,         mHandWidth: 4,         hFontSize: 14,         hScaleWidth: 2,         handMode: 's'     }).start();    var clock4 = clockHelper(clockCanvas4, {         deColor: '#bbbbbb',         sHandColor: '#bbbbbb',        // clockFaceColor: '#112233',         hHandWidth: 6,         mHandWidth: 4,         hFontSize: 14,         hScaleWidth: 2,         handMode: 's'     });      clock4.afterDraw = function (ctx, deConfig) {         var grd = ctx.createLinearGradient(0, 0, clockCanvas4.width, clockCanvas4.height);         grd.addColorStop(0, "rgba(255,0,0,0.3)");         grd.addColorStop(1, "rgba(0,0,255,0.5)");         ctx.fillStyle = grd;         ctx.arc(clockCanvas4.width/2,clockCanvas4.height/2,clockCanvas4.width/2,0,Math.PI*2);        // ctx.fillRect(0, 0, clockCanvas4.width, clockCanvas4.height);         ctx.fill();          ctx.fillText('时钟绘制完成后,自定义其他绘制',clockCanvas4.width/2,clockCanvas4.height - deConfig.hFontSize);     };      clock4.start();</script></body></html>

说明:

1、clockHelper第一个参数传入画布。第二个参数传入时钟界面的配置对象,包括指针、刻度的颜色、大小等,配置项和clockHelper中的deConfig默认对象是相对的,参考deConfig的属性传入参数即可。

2、clockHelper的封装性略差,仅是基本能用型。但属性不多,改造应该并不困难。

3、提供了时钟界面绘制之前和之后的方法,可以在beforeDraw和afterDraw这两个方法中执行自己的逻辑。但是由于事先设计没有留出足够的空白像素,用处不大。只能进行一些简单的再绘制。比如给钟面添加色彩、渐变。

相关推荐:

H5+C3实现时钟效果

使用Canvas制作时钟动画的方法

以上就是使用h5 canvas实现时钟的动态效果的详细内容,更多内容请关注技术你好其它相关文章!

来源链接:
免责声明:
1.资讯内容不构成投资建议,投资者应独立决策并自行承担风险
2.本文版权归属原作所有,仅代表作者本人观点,不代表本站的观点或立场
标签: Canvas
上一篇:php获取远程图片并下载保存到本地的方法分析 下一篇:HTML5嵌入音频和视频的方法

相关资讯