您好,登錄后才能下訂單哦!
使用h5 canvas實現時鐘動態效果的案例?這個問題可能是我們日常學習或工作經常見到的。希望通過這個問題能讓你收獲頗深。下面是小編給大家帶來的參考內容,讓我們一起來看看吧!
canvas 繪制好時鐘界面,使用定時器定時重繪整個canvas,就實現了仿真動態時鐘的效果。
難點在于:
秒鐘刻度和時鐘刻度的繪制
整點文字沿著內邊圓形環繞
其中刻度的環繞并不難計算,文字的環繞就比較坑爹了,canvas繪制的文字是在繪制坐標之上的(文字基線和對齊方式影響),需要進行偏移的計算,使之文字中點正好落在圓上。
這一步相當淡疼,由于api中并沒有測量字高的辦法,而使用fontSize,其實也并不是字的準確高度,因此,y坐標+二分之一行高向下偏移,使之垂直居中,卻總是不夠準確的。而x坐標+二分之一行寬向左偏移,使之水平居中,則沒有這個問題,因為api提供了測量行寬的方法。
一切都是因為 ctx.measureText(text).width
存在,但 ctx.measureText(numText).height
不存在。打印測量結果,也只有一個寬度屬性。文檔中說canvas對于繪制文字的支持比較弱,從這一點上看 何止是弱。
直接設置基線和對齊方式為居中,似乎也存在一定誤差,看起來總不是那么賞心悅目。下面的代碼中兩種方式都寫了。
主要知識點為圓的坐標公式,和三角函數sin,cos計算。實際上,圓的坐標公式使用的并不多,引入求值反而可能復雜化。
下面是全部代碼:
<!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 canvas實現時鐘動態效果的案例大概了解了嗎?希望文章內容對大家有所幫助。如果想了解更多相關文章內容,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。