前面介紹過canvas粒子時鐘的繪製,本文將詳細介紹canvas自適應圓形時鐘繪製html
最終自適應圓形時鐘的效果以下所示canvas
下面來分析一下該圓形時鐘的功能瀏覽器
【1】靜態背景函數
對於時鐘來講,背景是不變的,包括外層鍾框、內層圓點及數字、以及中心點的固定按扣字體
【2】動態時鐘spa
時態的動態,表如今秒針、分針、時針隨着當前時間的變化的變化。開啓一個每秒變化1次定時器,秒針與當前的時間的秒數保持一致,分針的變化與當前的秒數和分鐘數都有關,時針的變化與當前的分鐘數和小時數都有關rest
【3】自適應code
要作到時鐘自適應,須要將時鐘內部的尺寸繪製與時鐘總體的寬高相關聯,而不能設置爲固定值htm
下面是一張時鐘的簡易分析圖blog
下面來實現靜態的時鐘背景,包括外層鍾框、內層圓點及數字、以及中心點的固定按扣,以時鐘尺寸爲200*200爲基準,則半徑爲100,經過translate()將圓心點調整爲(0,0)點
【初始設置】
因爲外面常常要用到R和cxt.lineWidth,因此將其保存爲變量
var cxt = drawing.getContext('2d'); var W = drawing.width = 400; var H = drawing.height = 400; var R = W / 2; var cw = cxt.lineWidth = 0.1*R;
【外層鍾框】
爲了將外層鍾框不超出canvas區域,則其半徑設置爲R-cw/2,線條寬度與半徑成比例
cxt.translate(R,R); cxt.beginPath(); cxt.arc(0,0,R-cw/2,0,2*Math.PI,false); cxt.stroke();
【內層數字】
在距離圓心點0.8R-cw/2處,繪製12個數字,表示當前的分鐘數,數字的字體大小與半徑成比例
cxt.beginPath(); cxt.font = 0.2 * R + 'px 宋體'; cxt.textAlign = 'center'; cxt.textBaseline = 'middle'; var r1 = 0.8*R - cw/2; for(var i = 12; i > 0; i--){ var radius = 2*Math.PI/12 * i + 1.5*Math.PI; var x = Math.cos(radius) * r1; var y = Math.sin(radius) * r1; cxt.fillText(i,x,y); }
【內層原點】
在距離圓心點0.9R-cw/2處,繪製60個圓點,表示當前的秒數,當前秒數與分鐘數處於同一角度時,表示爲大圓點(半徑爲cx/5),不然爲小圓點(半徑爲cx/8)
cxt.beginPath(); var r2 = 0.9*R - cw/2; for(var i = 0; i < 60; i++){ var radius = 2*Math.PI/60*i + 1.5*Math.PI; var x = Math.cos(radius) * r2; var y = Math.sin(radius) * r2; cxt.beginPath(); if(i%5 === 0){ cxt.arc(x,y,cw/5,0,2*Math.PI,false); }else{ cxt.arc(x,y,cw/8,0,2*Math.PI,false); } cxt.fill(); }
【繪製中心點的固定按扣】
cxt.beginPath();
cxt.arc(0,0,cw/3,0,2*Math.PI,false);
cxt.fill();
最終,靜態背景封裝爲函數drawStatics(),代碼以下
<canvas id="drawing" style="border:1px solid black"></canvas> <script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var cxt = drawing.getContext('2d'); var W = drawing.width = 200; var H = drawing.height = 200; var R = W / 2; var cw = cxt.lineWidth = 0.1*R; function drawStatics(){ cxt.translate(R,R); cxt.beginPath(); cxt.lineWidth = 0.1*R; cxt.arc(0,0,R-cw/2,0,2*Math.PI,false); cxt.stroke(); cxt.beginPath(); cxt.font = 0.2 * R + 'px 宋體'; cxt.textAlign = 'center'; cxt.textBaseline = 'middle'; var r1 = 0.8*R - cw/2; for(var i = 12; i > 0; i--){ var radius = 2*Math.PI/12 * i + 1.5*Math.PI; var x = Math.cos(radius) * r1; var y = Math.sin(radius) * r1; cxt.fillText(i,x,y); } cxt.beginPath(); var r2 = 0.9*R - cw/2; for(var i = 0; i < 60; i++){ var radius = 2*Math.PI/60*i + 1.5*Math.PI; var x = Math.cos(radius) * r2; var y = Math.sin(radius) * r2; cxt.beginPath(); if(i%5 === 0){ cxt.arc(x,y,cw/5,0,2*Math.PI,false); }else{ cxt.arc(x,y,cw/8,0,2*Math.PI,false); } cxt.fill(); } cxt.beginPath(); cxt.arc(0,0,cw/3,0,2*Math.PI,false); cxt.fill(); } function draw(){ cxt.clearRect(0,0,W,H); drawStatics(); } draw(); } </script>
靜態效果以下
下面來分爲時針、分針、秒針來進行動態效果
【秒針】
開啓一個每秒變化1次定時器,秒針與當前的時間的秒數保持一致
function drawSecond(second){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/60 * second; cxt.rotate(radius); cxt.lineWidth = 2; cxt.moveTo(0,cw*2); cxt.lineTo(0,-0.8*R); cxt.strokeStyle = 'red'; cxt.stroke(); cxt.restore(); }
【分針】
分針的變化與當前的秒數和分鐘數都有關
function drawMinute(minute,second){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/60 * minute; var sRaiuds = 2*Math.PI/60/60 * second; cxt.rotate(radius + sRaiuds); cxt.lineWidth = 4; cxt.lineCap = 'round'; cxt.moveTo(0,cw); cxt.lineTo(0,-(0.8*R - cw/2)); cxt.stroke(); cxt.restore(); }
【時針】
時針的變化與當前的分鐘數和小時數都有關
function drawHour(hour,minute){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/12 * hour; var mRaiuds = 2*Math.PI/12/60 * minute; cxt.rotate(radius + mRaiuds); cxt.lineWidth = 6; cxt.lineCap = 'round'; cxt.moveTo(0,cw/2); cxt.lineTo(0,-(0.8*R - cw*2)); cxt.stroke(); cxt.restore(); }
如今,須要對代碼進行調整,由於canvas是按照代碼順序進行繪製的,因此代碼順序應該是,靜態背景(時鐘外框、圓點及數字) -> 動態效果(秒針、分針、時針) -> 中心按扣
所以,須要將中心按扣的代碼從靜態背景函數drawStatics()中分離出來,並從新安排代碼順序
因爲瀏覽器的定時器存在偏差,所以設置爲1000ms並不合適,因爲系統卡頓等緣由,可能會跳過某次效果,所以,設置爲500ms
最終完整代碼以下所示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <canvas id="drawing"></canvas> <script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var cxt = drawing.getContext('2d'); var W = drawing.width = 200; var H = drawing.height = 200; var R = W / 2; var cw = cxt.lineWidth = 0.1*R; function drawStatics(){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); cxt.lineWidth = 0.1*R; cxt.arc(0,0,R-cw/2,0,2*Math.PI,false); cxt.stroke(); cxt.beginPath(); cxt.font = 0.2 * R + 'px 宋體'; cxt.textAlign = 'center'; cxt.textBaseline = 'middle'; var r1 = 0.8*R - cw/2; for(var i = 12; i > 0; i--){ var radius = 2*Math.PI/12 * i + 1.5*Math.PI; var x = Math.cos(radius) * r1; var y = Math.sin(radius) * r1; cxt.fillText(i,x,y); } cxt.beginPath(); var r2 = 0.9*R - cw/2; for(var i = 0; i < 60; i++){ var radius = 2*Math.PI/60*i + 1.5*Math.PI; var x = Math.cos(radius) * r2; var y = Math.sin(radius) * r2; cxt.beginPath(); if(i%5 === 0){ cxt.arc(x,y,cw/5,0,2*Math.PI,false); }else{ cxt.arc(x,y,cw/8,0,2*Math.PI,false); } cxt.fill(); } cxt.restore(); } function drawDot(){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); cxt.arc(0,0,cw/3,0,2*Math.PI,false);
cxt.fillStyle = '#fff';
cxt.fill(); cxt.restore(); } function drawSecond(second){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/60 * second; cxt.rotate(radius); cxt.lineWidth = 2; cxt.moveTo(0,cw*2); cxt.lineTo(0,-0.8*R); cxt.strokeStyle = 'red'; cxt.stroke(); cxt.restore(); } function drawMinute(minute,second){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/60 * minute; var sRaiuds = 2*Math.PI/60/60 * second; cxt.rotate(radius + sRaiuds); cxt.lineWidth = 4; cxt.lineCap = 'round'; cxt.moveTo(0,cw); cxt.lineTo(0,-(0.8*R - cw/2)); cxt.stroke(); cxt.restore(); } function drawHour(hour,minute){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/12 * hour; var mRaiuds = 2*Math.PI/12/60 * minute; cxt.rotate(radius + mRaiuds); cxt.lineWidth = 6; cxt.lineCap = 'round'; cxt.moveTo(0,cw/2); cxt.lineTo(0,-(0.8*R - cw*2)); cxt.stroke(); cxt.restore(); } function draw(){ cxt.clearRect(0,0,W,H); drawStatics(); var now = new Date(); drawHour(now.getHours(),now.getMinutes()); drawMinute(now.getMinutes(),now.getSeconds()); drawSecond(now.getSeconds()); drawDot(); } draw(); setInterval(draw,500); } </script> </body> </html>