使用canvas繪制時鐘

jopen 9年前發布 | 22K 次閱讀 前端技術 canvas

準備工作

在HTML中指定一個區域放置時鐘:

<div id="clock" style="position: relative;"></div>

時鐘的一些外觀設定:

var width = 260; // 桌布寬度
var height= 260; // 桌布高度
var dot = {
    x : width / 2,
    y : height / 2,
    radius : 6
}; // 圓點位置、半徑
var radius = 120; // 圓半徑
var borderWidth = 6; // 圓邊框寬度

創建<canvas>元素:

var clock = document.getElementById('clock');
var clockBg = document.createElement('canvas');
var clockPointers = document.createElement('canvas');

clockPointers.width = clockBg.width = width; clockPointers.height = clockBg.height = height; clockPointers.style.position = 'absolute'; clockPointers.style.left = 0; clockPointers.style.right = 0;

clock.appendChild(clockBg); clock.appendChild(clockPointers);</pre>

這里要創建兩個<canvas>元素,目的在于把時鐘的圓盤跟指針分離開。這是因為指針要根據當前時間擦除重繪,如果放置在一個<canvas>中,擦除的時候就會把圓盤也給擦掉了。

繪制圓盤

但凡要在<canvas>中繪圖,都要先獲得其上下文,對應的接口是 canvas.getContext

var bgCtx = clockBg.getContext('2d');

目前canvas.getContext接口的唯一一個合法參數是' 2d ',將來應該會支持3D繪圖。

先來繪制最外面的圓框:

bgCtx.beginPath();
bgCtx.lineWidth = borderWidth;
bgCtx.strokeStyle = '#000';
bgCtx.arc(dot.x, dot.y, radius, 0, 2 * Math.PI, true);
bgCtx.stroke();
bgCtx.closePath();

繪圖的流程其實都是類似的:

  1. 調用 context.beginPath() 新建路徑;
  2. 設置顏色等樣式;
  3. 調用路徑函數生成路徑;
  4. 畫線( stroke )或者填充( fill );
  5. 調用 context.closePath() 關閉路徑;
  6. </ol>

    上面用到的 context.arc 接口可以生成圓弧路徑,其詳細說明參見 此處

    用類似的方法,畫出圓點:

    bgCtx.beginPath();
    bgCtx.fillStyle = '#000';
    bgCtx.arc(dot.x, dot.y, dot.radius, 0, 2 * Math.PI, true);
    bgCtx.fill();
    bgCtx.closePath();

    此時,結果如下圖所示:

    使用canvas繪制時鐘

    繪制刻度

    最復雜的地方就是畫刻度了,這里要先復習一下數學中的 三角函數

    使用canvas繪制時鐘

    刻度的起始位置就是圓框上的一個點,第一步就是要知道這個點的坐標。上圖中:

    sinθ = AC / AO
    cosθ = OC / AO

    其中 AO即為圓半徑 ,而θ的值則根據刻度而定。0是π/2,3是0,6是3π/2,9是π:

    使用canvas繪制時鐘

    由此可得到刻度起始點的位置為:

    x = 圓點橫坐標 + AO * cosθ
    y = 圓點縱坐標 + AO * sinθ

    同理可算出刻度結束點的位置為(結束點相當于在一個半徑為 圓框半徑-刻度長度 的圓上):

    x = 圓點橫坐標 + (AO - 刻度長度) * cosθ
    y = 圓點縱坐標 + (AO - 刻度長度) * sinθ

    于是,這程序可以寫了:

    for (var i = 0, angle = 0, tmp, len; i < 60; i++) {
        bgCtx.beginPath();

    // 突出顯示能被5除盡的刻度
    if (0 === i % 5) {
        bgCtx.lineWidth = 5;
        len = 12;
        bgCtx.strokeStyle = '#000';
    } else {
        bgCtx.lineWidth = 2;
        len = 6;
        bgCtx.strokeStyle = '#999';
    }
    
    tmp = radius - borderWidth / 2; // 因為圓有邊框,所以要減去邊框寬度
    bgCtx.moveTo(
        dot.x + tmp * Math.cos(angle),
        dot.y + tmp * Math.sin(angle)
    );
    tmp -= len;
    bgCtx.lineTo(dot.x + tmp * Math.cos(angle), dot.y + tmp * Math.sin(angle));
    bgCtx.stroke();
    bgCtx.closePath();
    
    angle += Math.PI / 30; // 每次遞增1/30π
    

    }</pre>

    畫好刻度后,結果應該是這樣:

    使用canvas繪制時鐘

    畫指針

    先得獲取指針<canvas>的上下文:

    var ptxContext = clockPointers.getContext('2d');

    由于畫指針的操作每隔一秒都要執行一次,所以這里就寫成一個函數,方便傳給setInterval調用:

    function updatePointers() {
        ptCtx.clearRect(0, 0, width, height);        // 清掉原來的指針

    // 獲取當前時間
    var now = new Date();
    var h = now.getHours();
    var m = now.getMinutes();
    var s = now.getSeconds();
    
    // 算出時分秒指針現在應指向圓的幾分之幾處
    h = h > 12 ? h - 12 : h;
    h = h + m / 60;
    h = h / 12;
    m = m / 60;
    s = s / 60;
    
    drawPointers(s, 2, 92); // 畫秒針
    drawPointers(m, 4, 82); // 畫分針
    drawPointers(h, 6, 65); // 畫時針
    

    }</pre>

    drawPointers函數的實現是:

    // angle是角度,lineWidth是指針寬度,length是指針長度
    function drawPointers(angle, lineWidth, length) {
        angle = angle  Math.PI  2 - Math.PI / 2;

    ptCtx.beginPath();
    ptCtx.lineWidth = lineWidth;
    ptCtx.strokeStyle = "#000";
    ptCtx.moveTo(dot.x, dot.y);
    ptCtx.lineTo(dot.x + length * Math.cos(angle), dot.y + length * Math.sin(angle));
    ptCtx.stroke();
    ptCtx.closePath();
    

    }</pre>

    這里主要也是用到三角函數,就不啰嗦了,但是要注意angel的計算。由于傳入的angel是一個百分數,所以要乘以一個圓周,也就是2π,才知道對應的弧度,算出來以后還要減去π/2,因為從上面的坐標圖就可以看到,0是位于x軸而不是y軸除,剛好比正常的時鐘多了π/2。

    最后別忘了調用updatePointers實時更新指針:

    setInterval(updatePointers, 1000);
    updatePointers();

    這下時鐘完全出來了,除了初步熟悉<canvas>繪圖API外,還順便復習了一次三角函數。

    使用canvas繪制時鐘

    </div> 原文 http://www.heeroluo.net/article/detail/95/draw-clock-in-canvas

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!