1. 程式人生 > >Canvas 實現一個時鐘

Canvas 實現一個時鐘

使用canvas實現另一個小時鐘,效果圖如下:

前端html程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        body {
            background: #dddddd;
        }

        #canvas {
            margin: 0 auto;
            padding: 10px;
            background:#ffffff;
            border: thin inset #aaaaaa;  
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="400" height="400">
        Canvas not supported
    </canvas>
    <script src="./js/example.js"></script>
</body>
</html>

下面是example.js的具體實現:

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
 
var FONT_HEIGHT = 15;// 字型大小
var MARGIN = 35; // 邊距
var HAND_TRUNCATION = canvas.width/12; // 分鐘需要減去的半徑
var HOUR_HAND_TRUNCATION = canvas.width/10;// 小時針需要減去的半徑
var NUMBER_SPACING = 20; // 數字間距
var RADIUS = canvas.width/2 - MARGIN; // 半徑
var HAND_RADIUS = RADIUS + NUMBER_SPACING; // 指標半徑(數字間距)

// 繪製圓
function drawCircle(){
    context.beginPath();
    context.arc(canvas.width/2, canvas.height/2, RADIUS, 0, Math.PI*2, true);
    context.stroke();
}

// 繪製中心點
function drawCenter(){
    context.beginPath();
    context.arc(canvas.width/2, canvas.height/2, 5, 0, Math.PI*2, true);
    context.fill();
}


// 繪製數字
function drawNumbers(){
    var numberals = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
    var angle = 0;
    var numeralWidth = 0;
    numberals.forEach(function(numeral){
        angle = Math.PI/6 * (numeral - 3);
        // 填充文字
        numeralWidth = context.measureText(numeral).width;
        context.fillText(numeral,
            canvas.width/2 + Math.cos(angle)*(HAND_RADIUS)
                - numeralWidth/2,
            canvas.height/2 + Math.sin(angle)*(HAND_RADIUS)
                + FONT_HEIGHT/3
        );
        // 繪製刻度 
        context.moveTo(canvas.width/2 + Math.cos(angle)*(RADIUS -5),
                    canvas.height/2 + Math.sin(angle)*(RADIUS -5));
        context.lineTo(canvas.width/2 + Math.cos(angle)*(RADIUS),
                canvas.height/2 + Math.sin(angle)*(RADIUS));
        context.stroke();   
    });
}

// 繪製指標
function drawHand(loc, isHour , isMin){
    var angle = (Math.PI * 2) * (loc/60) - Math.PI/2;
    var handRadius = isHour? RADIUS - HAND_TRUNCATION - HOUR_HAND_TRUNCATION
                            : (isMin ? (RADIUS - HAND_TRUNCATION) : (RADIUS * 0.95));
    context.moveTo(canvas.width/2, canvas.height/2);
    context.lineTo(canvas.width/2 + Math.cos(angle) * handRadius,
                    canvas.height/2 + Math.sin(angle) * handRadius);
    context.stroke();
}

// 繪製所有指標
function drawHands(){
    var date = new Date;
    var hour = date.getHours();
    hour = hour >12 ? hour - 12 : hour;
    // 繪製小時指標
    drawHand((hour + date.getMinutes()/60)*5, true,false);
    // 繪製分鐘指標
    drawHand(date.getMinutes(),false,true);
    // 繪製秒指標
    drawHand(date.getSeconds(),false,false);
}

// 畫鍾
function drawClock(){
    context.clearRect(0, 0, canvas.width, canvas.height);
    drawCircle();
    drawCenter();
    drawNumbers();
    drawHands();
}
 
context.font = FONT_HEIGHT + 'px Arial';
loop = setInterval(drawClock, 1000);

另外,實現時鐘的主要的難點如下:

在刻畫指標的時候採用了這樣的處理方法:

小時取1-12 但是我們會乘以5,因為我們把一個圓分成了60個小刻度,這樣在渲染的時候對於時、分、秒的處理就變得很容易:

時指標的偏移度數(我們取canvas下的偏轉度數)={ [ (小時數 + 當前時間的分鐘/60) * 5]   /   60 } * (2 * π) - π/2。

具體理解如下:

首先我們以canvas旋轉座標定義,順時針為+,逆時針為-,這樣我們迴歸到0度數。假設現在需要渲染1:00,小時指標情況,顯然1個小時佔據圓盤的30度的夾角,我們從0開始旋轉30度角成:

但是實際上1:00的錶盤時指標的顯示應該為: