天天看點

使用HTML5的canvas做一個會動的時鐘

這次我們的目标是畫一個會和時間同步的時鐘,不過沒有美學感覺,樣子醜的厲害。

<a target="_blank" href="http://blog.51cto.com/attachment/201205/162920892.jpg"></a>

HTML5支援canvas了,我們可以直接在頁面上繪圖了,我看了下canvas和GDI+的接口差不多,是以我們先了解些基本的概念和方式,然後來做一個應用吧。

我們做所有的畫之情需要一個畫布,html的canvas标簽就是幫我們聲明了一個畫布。

[javascript] view plaincopy 

&lt;canvas id="mycanvas"&gt;  

&lt;/canvas&gt; 

這個預設的畫布的大小是300*150,接下來的工作大多就是javaScript來做了。

首先要執行個體化這個畫布

$(  

function() {  

var canvas = document.getElementById("mycanvas");  

$.log(canvas.width);  

$.log(canvas.height);  

var context = canvas.getContext("2d");  

$.log(context.canvas);  

$.log(context.fillStyle); //要填充的區域的顔色  

$.log(context.strokeStyle); //要繪制的線條的顔色  

$.log(context.lineCap); //筆帽樣式  

$.log(context.lineJoin); //兩條連續線段的連接配接樣式  

$.log(context.lineWidth); //線段的寬度  

$.log(context.miterLimit); //斜聯接  

$.log(context.shadowColor); //陰影的顔色,預設為#000000,  

$.log(context.shadowOffsetX); //陰影在x方向上的偏移量,預設為0,不受坐标轉換的影響。  

$.log(context.shadowOffsetY); //陰影在y方向上的偏移量,預設為0,不受坐标轉換的影響。  

$.log(context.shadowBlur); //陰影的模糊度,預設為0,負數值将會被忽略  

}  

); 

上面的結果你可以得到一個大緻的想法,就是content可以認為是我們将來作畫用的畫筆(估計有專業人士對強烈抗議,我直接忽略),canvas就是我們的畫布。我們現在的畫筆是2D的畫筆,換句話說就是畫平面幾何的畫筆。

接下來,就是我們利用這個畫筆來學習怎麼畫了

各種線

context.strokeStyle = "rgb(255, 0, 0)";  

context.beginPath();  

context.lineCap = "butt"; //預設  

context.lineWidth = 10;  

context.moveTo(10, 10);  

context.lineTo(100, 10); //簡單的一條線  

context.stroke(); //該方法真正在畫布上繪制該線段  

context.lineCap = "round"; //圓形線頭  

context.moveTo(10, 30);  

context.lineTo(100, 30);  

context.lineCap = "square"; //方形線頭  

context.moveTo(10, 50);  

context.lineTo(100, 50);  

各種陰影 

context.shadowColor = "#0000FF";  

context.lineCap = "round";  

context.lineTo(100, 10);  

context.shadowOffsetX = 10;  

context.shadowBlur = 10;  

context.stroke();  

context.shadowOffsetY = 10;  

各種線∠連接配接 

context.lineJoin = "miter"; //兩條線段的外邊緣一直擴充到它們相交  

context.moveTo(10, 70);  

context.lineTo(50, 10);  

context.lineTo(80, 70);  

context.lineJoin = "bevel"; //以一個斜邊進行連接配接  

context.moveTo(100, 70);  

context.lineTo(140, 10);  

context.lineTo(180, 70);  

context.lineJoin = "round"; //:以一個圓弧邊進行連接配接  

context.moveTo(200, 70);  

context.lineTo(240, 10);  

context.lineTo(280, 70);  

context.closePath(); //關閉path  

mitre的限定 

context.miterLimit = 1; //miterLimit 屬性為斜面的長度設定一個上限。  

//隻對線條使用設定為 "miter" 的 lineJoin 屬性繪制并且兩條線段以銳角相交的時候有效  

各種幾何圖形 

canvas.height = 500; //改變預設高度  

canvas.width = 500;  

context.fillStyle = "#AABBCC";  

context.lineWidth = 2;  

//矩形  

context.fillRect(10, 10, 50, 50); //實體矩形:x,y,width,height  

context.strokeRect(70, 10, 50, 50)//空心矩形:x,y,width,height  

//context.move(10,100);  

//圓弧:x, y, radius, startAngle, endAngle, anticlockwise  

context.arc(35, 110, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);  

//context.closePath();  

context.arc(85, 110, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 180, false);  

context.arc(135, 110, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 180, true);  

context.arc(185, 110, 25, (Math.PI / 180) * 180, (Math.PI / 180) * 360, true);  

context.arc(235, 110, 25, (Math.PI / 180) * 90, (Math.PI / 180) * 0, false);  

context.fillStyle = "blue";  

context.fill();  

//context.stroke();  

context.arc(285, 110, 25, (Math.PI / 180) * 180, (Math.PI / 180) * 45, false);  

context.closePath();  

context.arc(335, 110, 25, (Math.PI / 180) * 180, (Math.PI / 180) * 45, false);  

//曲線  

context.moveTo(10, 160); //二次貝塞爾曲線的起始點  

//controlX, controlY, endX, endY  

context.quadraticCurveTo(70, 280, 235, 140);  

context.moveTo(10, 300); //三次貝塞爾曲線的起始點  

//controlX1, controlY1, controlX2, controlY2, endX, endY  

context.bezierCurveTo(70, 280, 50, 400, 235, 190);  

各種變換 

記得CSS3中的transform不?canvas肯定也有啊 

平移 

//context.beginPath();  

$(canvas).on(  

"click",  

{ "context": context },  

function(e) {  

$.log(e.data.context);  

var ctx = e.data.context;  

ctx.translate(10, 10); //再最後的路徑點上偏移10*10的位置  

context.fillRect(10, 10, 50, 50);  

);  

縮放 

ctx.scale(1.1, 1.1); //在最後的大小基礎上縮放倍數 必須是正數  

旋轉 

ctx.rotate((Math.PI / 180) * 10); //旋轉的角度,旋轉的中心是canvas坐标原點 

transform,transform的參數比較多,也比較難了解,簡單的說transform是最自由的變形方式,下面給出些參考

//以下兩段代碼結果一緻  

context.transform(1, 0, 0, 1, 10, 10)  

context.translate(10, 10);  

context.transform(10, 0, 0, 10, 0, 0);  

context.scale(10, 10);  

//以下三段代碼結果一緻  

context.transform(Math.cos((Math.PI / 180) * 10), Math.sin((Math.PI / 180) * 10), -Math.sin((Math.PI / 180) * 10), Math.cos((Math.PI / 180)) * 10, 0, 0);  

context.transform(-Math.sin((Math.PI/180)*10),Math.cos((Math.PI/180)*10),Math.cos((Math.PI/180)*10),Math.sin((Math.PI/180)*10), 0,0);  

context.rotate(10); 

組合

canvas.height = 100;  

canvas.width = 100;  

//預設 新圖形會覆寫在原有内容之上  

context.globalCompositeOperation = "source-over";  

context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);  

$("span").html(context.globalCompositeOperation);  

$(canvas).toggle(  

// 原有内容之下繪制新圖形  

context.clearRect(0, 0, 500, 500);  

context = canvas.getContext("2d");  

context.globalCompositeOperation = "destination-over";  

},  

//新圖形會僅僅出現與原有内容重疊的部分。其它區域都變成透明的  

context.globalCompositeOperation = "source-in";  

//原有内容中與新圖形重疊的部分會被保留,其它區域都變成透明的destination-in 

context.globalCompositeOperation = "destination-in";  

//隻有新圖形中與原有内容不重疊的部分會被繪制出來source-out  

context.globalCompositeOperation = "source-out";  

//原有内容中與新圖形不重疊的部分會被保留  

context.globalCompositeOperation = "destination-out";  

//新圖形中與原有内容重疊的部分會被繪制,并覆寫于原有内容之上  

context.globalCompositeOperation = "source-atop";  

//原有内容中與新内容重疊的部分會被保留,并會在原有内容之下繪制新圖形  

context.globalCompositeOperation = "destination-atop";  

//兩圖形中重疊部分作加色處理  

context.globalCompositeOperation = "lighter";  

//兩圖形中重疊的部分作減色處理darker  

context.globalCompositeOperation = "darker";  

//重疊的部分會變成透明  

context.globalCompositeOperation = "xor";  

//隻有新圖形會被保留,其它都被清除掉  

context.globalCompositeOperation = "copy";  

alert("示範結束");  

字型(看文檔說canvas的字型支援CSS樣式的描寫,但是,我不知道怎麼樣讓canvas的font支援CSS3的線上字型) 

&lt;script src="js/jquery-1.7.1.min.js" type="text/javascript"&gt;&lt;/script&gt;  

&lt;link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Tangerine"&gt;  

&lt;script type="text/javascript"&gt;  

$.log = function(msg) {  

console.log(msg);  

canvas.height = 200;  

canvas.width = 200;  

context.font = "20px 新宋體";  

context.fillText("這是實心新宋體", 10, 30);  

context.strokeText("這是空心新宋體", 10, 60);  

context.font = "20px Tangerine serif";  

context.fillText("Hello HTML5", 10, 100);  

context.strokeText("Hello HTML5", 10, 150);  

&lt;/script&gt; 

我們嘗試寫一圈旋轉的文字,吧上面的知識點合起來看看效果

canvas.height = 500;  

context.translate(150, 150);  

context.scale(0.7, 0.7);  

context.font = "12px Tahoma";  

for (var i = 0; i &lt; 12; i++) {  

context.fillText((i + 3) % 12 == 0 ? 12 : (i + 3) % 12, 150, 10);  

context.rotate((Math.PI / 6));  

在具體繪制的時候,定位總是讓我這樣沒有空間感的人感覺痛苦,是以我現在canvas上畫上很多格子,幫助我進行布局

context.lineWidth = 1;  

context.strokeStyle = "rgb(211,211,211)";  

for (var i = 0; i &lt; 50; i++) {  

$.log(i);  

context.moveTo(i * 10, 0);  

context.lineTo(i * 10, 500);  

context.moveTo(0, i * 10);  

context.lineTo(500, i * 10);  

前面的準備工作都完成了,現在我們來綜合下,完成一個具有時分秒的會動的鐘 

$( 

function() { 

    clock(); 

    setInterval(clock, 1000); 

function clock() { 

    var canvas = document.getElementById("mycanvas"); 

    canvas.height = 500; 

    canvas.width = 500; 

    var context = canvas.getContext("2d"); 

    context.beginPath(); 

    context.lineWidth = 1; 

    context.strokeStyle = "rgb(211,211,211)"; 

    for (var i = 0; i &lt; 50; i++) { 

        $.log(i); 

        context.moveTo(i * 10, 0); 

        context.lineTo(i * 10, 500); 

        context.stroke(); 

    } 

        context.moveTo(0, i * 10); 

        context.lineTo(500, i * 10); 

    context.strokeStyle = "rgb(255,0,0)"; 

    context.arc(250, 250, 200, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false); 

    context.stroke(); 

    context.save(); //存儲目前畫布坐标系狀态 

    context.font = "14px Tahoma" 

    context.translate(255, 255); //将坐标系坐标原點移至圖中間 

    context.strokeStyle = "#FFFFFF"; 

    for (var i = 0; i &lt; 12; i++) { 

        context.fillText((i + 3) % 12 == 0 ? 12 : (i + 3) % 12, 180, 0); 

        context.rotate((Math.PI / 6)); 

    context.restore(); 

    context.save(); 

    context.lineWidth = 5; 

    for (i = 0; i &lt; 60; i++) { 

        if (i % 5 != 0) { 

            context.beginPath(); 

            context.moveTo(180, 0); 

            context.lineTo(190, 0); 

            context.stroke(); 

        } 

        context.rotate(Math.PI / 30); 

    var now = new Date(); 

    var sec = now.getSeconds(); 

    var min = now.getMinutes(); 

    var hr = now.getHours() &gt;= 12 ? now.getHours() - 12 : now.getHours(); 

    // - (Math.PI / 6) * 3 是因為0度在3點這裡 

    context.rotate(hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) * sec - (Math.PI / 6) * 3); 

    context.lineWidth = 14; 

    context.moveTo(-20, 0); 

    context.lineTo(150, 0); 

    context.rotate(min * (Math.PI / 30) + (Math.PI / 1800) * sec - (Math.PI / 6) * 3) 

    context.lineWidth = 10; 

    context.moveTo(-28, 0); 

    context.lineTo(160, 0); 

    context.rotate(sec * (Math.PI / 30) + (Math.PI / 1800) * sec - (Math.PI / 6) * 3) 

本文轉自shyleoking 51CTO部落格,原文連結:http://blog.51cto.com/shyleoking/864007

繼續閱讀