這次我們的目标是畫一個會和時間同步的時鐘,不過沒有美學感覺,樣子醜的厲害。
<a target="_blank" href="http://blog.51cto.com/attachment/201205/162920892.jpg"></a>
HTML5支援canvas了,我們可以直接在頁面上繪圖了,我看了下canvas和GDI+的接口差不多,是以我們先了解些基本的概念和方式,然後來做一個應用吧。
我們做所有的畫之情需要一個畫布,html的canvas标簽就是幫我們聲明了一個畫布。
[javascript] view plaincopy
<canvas id="mycanvas">
</canvas>
這個預設的畫布的大小是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的線上字型)
<script src="js/jquery-1.7.1.min.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Tangerine">
<script type="text/javascript">
$.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);
</script>
我們嘗試寫一圈旋轉的文字,吧上面的知識點合起來看看效果
canvas.height = 500;
context.translate(150, 150);
context.scale(0.7, 0.7);
context.font = "12px Tahoma";
for (var i = 0; i < 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 < 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 < 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 < 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 < 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() >= 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