canvas繪圖之鐘表

舊巷老友發表於2019-02-23

前言 

最近公司做專案用到了統計圖一些東西,我當然用的是第三方類庫,週末在家沒事想起了canvas繪圖,就熟悉了一下並做了一個鐘錶的小例子,如圖:

鐘錶

雖然樣子醜點,但是該有的功能一點都不少,接下來就說下怎樣實現的。

介紹canvas

現在大部分瀏覽器都支援canvas,使用canvas前要新建個畫布,就是這樣

<canvas id="myCanvas" width="200" height="100"></canvas>
複製程式碼

然後再說一些常用的屬性和方法:

顏色和樣式

  • fillStyle 設定或返回用於填充繪畫的顏色、漸變或模式
  • strokeStyle 設定或返回用於筆觸的顏色、漸變或模式
  • shadowColor 設定或返回用於陰影的顏色

矩形

  • rect() 建立矩形
  • fillRect() 繪製“被填充”的矩形
  • strokeRect() 繪製矩形(無填充)
  • clearRect() 在給定的矩形內清除指定的畫素

路徑

  • fill() 填充當前繪圖(路徑)
  • stroke() 繪製已定義的路徑
  • beginPath() 起始一條路徑,或重置當前路徑
  • moveTo() 把路徑移動到畫布中的指定點,不建立線條
  • closePath() 建立從當前點回到起始點的路徑
  • lineTo() 新增一個新點,然後在畫布中建立從該點到最後指定點的線條
  • clip() 從原始畫布剪下任意形狀和尺寸的區域
  • quadraticCurveTo() 建立二次貝塞爾曲線
  • bezierCurveTo() 建立三次方貝塞爾曲線
  • arc() 建立弧/曲線(用於建立圓形或部分圓)
  • arcTo() 建立兩切線之間的弧/曲線
  • isPointInPath() 如果指定的點位於當前路徑中,則返回 true,否則返回 false

文字

  • font 設定或返回文字內容的當前字型屬性
  • textAlign 設定或返回文字內容的當前對齊方式
  • textBaseline 設定或返回在繪製文字時使用的當前文字基線
  • fillText() 在畫布上繪製“被填充的”文字
  • strokeText() 在畫布上繪製文字(無填充)
  • measureText() 返回包含指定文字寬度的物件

影像繪製

  • drawImage() 向畫布上繪製影像、畫布或視訊

今天用到的暫時就這麼多。

繪製鐘錶

首先新建一個html檔案,新建畫板並且給畫板增加些樣式,就像這樣

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>鐘錶</title>
        <style>
	#canvas {
	    border: 1px solid #000;
	    margin: 0 auto;
	    display: block;
	}
        </style>
    </head>
    <body>
	<!-- 新建畫板 -->
	<canvas id="canvas" width="400" height="400"></canvas>
    </body>
</html>
複製程式碼

然後開始操作canvas,

//獲取canvas標籤,並且建立 context 物件
var canvas = document.getElementById(`canvas`),
	context = canvas.getContext(`2d`),
	deg = Math.PI/180;
context.translate(200,200);	複製程式碼

說明:getContext(“2d”) 物件是內建的 HTML5 物件,擁有多種繪製路徑、矩形、圓形、字元以及新增影像的方法,deg計算圓周率,translate() 畫布的位置

建立錶盤、數字、刻度、中心點

建立錶盤

context.beginPath();
context.arc(0, 0, 150, 0, 360 * deg);
context.lineWidth = 3;
context.stroke();
context.closePath();
複製程式碼

建立數字

//建立數字
for (var i = 1; i <= 12; i++) {
  context.beginPath();
  context.save();
  context.rotate(30 * i * deg);
  context.textAlign = `center`;
  if (i % 3 == 0) {
      context.fillStyle = `red`;
      context.font = "normal 28px arial";
      context.fillText(i, 0, -110);
  } else {
      context.font = "normal 20px arial";
      context.fillText(i, 0, -120);
  }
  context.restore();
  context.closePath();
}
複製程式碼

建立刻度

for (var i = 1; i <= 60; i++) {
    context.beginPath();
    context.save();
    context.rotate(6 * i * deg);
    context.moveTo(0, -150);
    //判斷刻度顯示顏色
    if (i % 15 == 0) {
        context.strokeStyle = `red`;
        context.lineWidth = 3;
        context.lineTo(0, -135);
        context.stroke();
    } else if (i % 5 == 0) {
        context.strokeStyle = `orange`;
        context.lineWidth = 2;
        context.lineTo(0, -140);
        context.stroke();
    } else {
        context.strokeStyle = `#000`;
        context.lineWidth = 1;
        context.lineTo(0, -145);
        context.stroke();
    }
    context.restore();
    context.closePath();
}
複製程式碼

建立中心點

 context.beginPath();
 context.arc(0, 0, 5, 0, 360 * deg);
 context.fill();
 context.closePath();
複製程式碼

如圖:
錶盤

建立指標

var nowdate = new Date(),
     hour = nowdate.getHours() % 12,
     minu = nowdate.getMinutes(),
     second = nowdate.getSeconds();
 var ms = nowdate.getMilliseconds(); //毫秒
 //秒針
 context.beginPath();
 context.save();
 context.lineWidth = 1;
 context.strokeStyle = `red`;
 //context.rotate(6*second*deg);
 context.rotate((ms / 1000 + second) * 6 * deg);
 context.moveTo(0, 20);
 context.lineTo(0, -130);
 context.stroke();
 context.restore();
 context.closePath();
 //分針
 context.beginPath();
 context.save();
 context.lineWidth = 2;
 context.strokeStyle = `orange`;
 //context.rotate((second/60+minu)*6*deg);
 context.rotate((ms / 1000 / 60 + second / 60 + minu) * 6 * deg);
 context.moveTo(0, 10);
 context.lineTo(0, -120);
 context.stroke();
 context.restore();
 context.closePath();
 //時針
 context.beginPath();
 context.save();
 context.lineWidth = 3;
 context.strokeStyle = `#000`;
 //context.rotate((second/3600+minu/60+hour)*30*deg);
 context.rotate((ms / 1000 / 60 / 60 + second / 60 / 60 + minu / 60 + hour) * 30 * deg);
 context.moveTo(0, 0);
 context.lineTo(0, -110);
 context.stroke();
 context.restore();
 context.closePath();
複製程式碼

如圖:
完成之後
是不是以為到現在就結束了,我大聲的告訴大家沒有,現在才是剛剛開始,接下來就是見證奇蹟的時刻。。。

最後完成

我們需要把上邊的繪製封裝成方法,然後不停的繪製不停的清除這樣鐘錶就動起來了

function dialPlate() { //建立錶盤
    //context.clearRect(-150,-150,400,400);//清除畫布
    context.beginPath();
    context.arc(0, 0, 150, 0, 360 * deg);
    context.lineWidth = 3;
    context.stroke();
    context.closePath();
    //建立刻度
    for (var i = 1; i <= 60; i++) {
        context.beginPath();
        context.save();
        context.rotate(6 * i * deg);
        context.moveTo(0, -150);
        if (i % 15 == 0) {
            context.strokeStyle = `red`;
            context.lineWidth = 3;
            context.lineTo(0, -135);
            context.stroke();
        } else if (i % 5 == 0) {
            context.strokeStyle = `orange`;
            context.lineWidth = 2;
            context.lineTo(0, -140);
            context.stroke();
        } else {
            context.strokeStyle = `#000`;
            context.lineWidth = 1;
            context.lineTo(0, -145);
            context.stroke();
        }
        context.restore();
        context.closePath();
    }
    //建立數字
    for (var i = 1; i <= 12; i++) {
        context.beginPath();
        context.save();
        context.rotate(30 * i * deg);
        context.textAlign = `center`;
        if (i % 3 == 0) {
            context.fillStyle = `red`;
            context.font = "normal 28px arial";
            context.fillText(i, 0, -110);
        } else {
            context.font = "normal 20px arial";
            context.fillText(i, 0, -120);
        }
        context.restore();
        context.closePath();
    }
    //中心點
    context.beginPath();
    context.arc(0, 0, 5, 0, 360 * deg);
    context.fill();
    context.closePath();
}

function Pointer() { //建立指標
    var nowdate = new Date(),
        hour = nowdate.getHours() % 12,
        minu = nowdate.getMinutes(),
        second = nowdate.getSeconds();
    var ms = nowdate.getMilliseconds(); //毫秒
    //秒針
    context.beginPath();
    context.save();
    context.lineWidth = 1;
    context.strokeStyle = `red`;
    //context.rotate(6*second*deg);
    context.rotate((ms / 1000 + second) * 6 * deg);
    context.moveTo(0, 20);
    context.lineTo(0, -130);
    context.stroke();
    context.restore();
    context.closePath();
    //分針
    context.beginPath();
    context.save();
    context.lineWidth = 2;
    context.strokeStyle = `orange`;
    //context.rotate((second/60+minu)*6*deg);
    context.rotate((ms / 1000 / 60 + second / 60 + minu) * 6 * deg);
    context.moveTo(0, 10);
    context.lineTo(0, -120);
    context.stroke();
    context.restore();
    context.closePath();
    //時針
    context.beginPath();
    context.save();
    context.lineWidth = 3;
    context.strokeStyle = `#000`;
    //context.rotate((second/3600+minu/60+hour)*30*deg);
    context.rotate((ms / 1000 / 60 / 60 + second / 60 / 60 + minu / 60 + hour) * 30 * deg);
    context.moveTo(0, 0);
    context.lineTo(0, -110);
    context.stroke();
    context.restore();
    context.closePath();
}

dialPlate();
Pointer();
setInterval(function(){
	dialPlate();
	Pointer();
},1000/60)
複製程式碼

說明:動畫每秒執行60次是最好的,所以定時器才讓他沒秒執行60次。
到現在是真結束了,一個簡單的canvas繪製鐘錶就完成了。希望可以到 專案上點一個 star 作為你對這個專案的認可與支援,謝謝。 聽說長的帥的小哥哥和長的漂亮的小姐姐都會點讚的。

專案地址:github.com/Mr-MengBo/C…

相關文章