canvas自適應圓形時鐘繪製

前面的話

  前面介紹過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>
相關文章
相關標籤/搜索