1. 程式人生 > >HTML5之Canvas 2D入門2

HTML5之Canvas 2D入門2

canvas只支援一種基本形狀——矩形,所有其它形狀都是通過一個或多個路徑組合而成,甚至是基本的矩形也可以通過路徑組合成。
一、設定畫筆屬性
  設想我們生活中畫圖的樣子,我們首先是選取合適的顏料和筆,一樣的道理,在canvas中畫圖同樣也是根據需要,不斷的去設定當前使用的顏色和線條型別。
設定當前使用的顏色
  任何封閉的圖形都是有輪廓部分和填充部分組成。設定當前的顏色也是分兩部分設定:
•設定填充色:context.fillStyle = color
•設定輪廓色:context.strokeStyle = color

  引數color可以是表示CSS顏色值的字串,漸變物件或者圖案物件。預設情況下,線條和填充顏色都是黑色(CSS顏色值#000000)。
顏色的字串表示


  下面都是正確的值:

// 這些 fillStyle 的值均為 '橙色'  
ctx.fillStyle = "orange";  
ctx.fillStyle = "#FFA500";  
ctx.fillStyle = "rgb(255,165,0)";  
ctx.fillStyle = "rgba(255,165,0,1)";  

如果你要給每個圖形上不同的顏色,你需要重新設定 fillStyle或strokeStyle 的值,就像我們畫畫時需要不斷換不同顏色的顏料一樣。
設定透明度
1.設定全域性透明度:context.globalAlpha = transparency value。
  這個屬性影響到 canvas 裡所有圖形的透明度,有效的值範圍是 0.0 (完全透明)到 1.0(完全不透明),預設是 1.0。例子如下所示:

function draw2() {  
  var ctx = document.getElementById('lesson01').getContext('2d');  
  // draw background  
  ctx.fillStyle = '#FD0';  
  ctx.fillRect(0,0,75,75);  
  ctx.fillStyle = '#6C0';  
  ctx.fillRect(75,0,75,75);  
  ctx.fillStyle = '#09F';  
  ctx.fillRect(0,75,75,75);  
  ctx.fillStyle = '#F30'
; ctx.fillRect(75,75,75,75); ctx.fillStyle = '#FFF'; // set transparency value ctx.globalAlpha = 0.2; // Draw semi transparent circles for (var i=0;i<7;i++){ ctx.beginPath(); ctx.arc(75,75,10+10*i,0,Math.PI*2,true); ctx.fill(); } }

這裡寫圖片描述
2.設定單個圖形的透明度

  很簡單,把rgba格式的字串賦給fillStyle或者strokeStyle就可以了。
建立漸變色
  canvas中我們也可以用線性或者徑向的漸變來填充或描邊。建立漸變色要經過下面幾個步驟:
  
1.建立漸變物件:
•線性漸變:context.createLinearGradient(x1,y1,x2,y2)
方法接受4個引數,表示漸變的起點(x1,y1) 與終點(x2,y2)。
•徑向漸變:context.createRadialGradient(x1,y1,r1,x2,y2,r2)
方法接受6個引數,前三個定義一個以(x1,y1)為原點,半徑為r1的圓,後三個引數則定義另一個以(x2,y2)為原點,半徑為r2的圓。
兩個方法返回響應的漸變物件,下面就可以給這個物件新增漸變顏色了。

2.給漸變物件上色:
  上色:gradientObject.addColorStop(position, color)
  方法接受2個引數,position 引數必須是一個 0.0 與 1.0 之間的數值,表示漸變中顏色所在的相對位置。例如,0.5 表示顏色會出現在正中間;如果第一個色標的該引數值不是0.0,則漸變會預設認為從起點到第一個色標之間都是黑色。
  color 引數必須是一個有效的 CSS 顏色值(如 #FFF, rgba(0,0,0,1),等等)。
  可以根據需要新增任意多個色標(color stops),也就是說漸變的色彩數目是任意的。但是要注意保持色標定義順序和它理想的順序一致,特別是當色標的位置重疊的時候。
3.把漸變物件賦給圖形的fillStyle或strokeStyle屬性。
例子如下所示:

function draw() {  
  var ctx = document.getElementById('lesson01').getContext('2d');  

  // Create gradients  
  var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);  
  radgrad.addColorStop(0, '#A7D30C');  
  radgrad.addColorStop(0.9, '#019F62');  
  radgrad.addColorStop(1, 'rgba(1,159,98,0)');  

  var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50);  
  radgrad2.addColorStop(0, '#FF5F98');  
  radgrad2.addColorStop(0.75, '#FF0188');  
  radgrad2.addColorStop(1, 'rgba(255,1,136,0)');  

  var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40);  
  radgrad3.addColorStop(0, '#00C9FF');  
  radgrad3.addColorStop(0.8, '#00B5E2');  
  radgrad3.addColorStop(1, 'rgba(0,201,255,0)');  

  var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90);  
  radgrad4.addColorStop(0, '#F4F201');  
  radgrad4.addColorStop(0.8, '#E4C700');  
  radgrad4.addColorStop(1, 'rgba(228,199,0,0)');  

  // draw shapes  
  ctx.fillStyle = radgrad4;  
  ctx.fillRect(0,0,150,150);  
  ctx.fillStyle = radgrad3;  
  ctx.fillRect(0,0,150,150);  
  ctx.fillStyle = radgrad2;  
  ctx.fillRect(0,0,150,150);  
  ctx.fillStyle = radgrad;  
  ctx.fillRect(0,0,150,150);  
}

這裡寫圖片描述
建立圖案填充效果
簡單兩步即搞定。
1.建立圖案pattern:context.createPattern(image,type)
  該方法接受兩個引數。Image 可以是一個 Image 物件的引用,或者另一個 canvas 物件。Type 必須是下面的字串值之一:repeat,repeat-x,repeat-y 和 no-repeat。

2.pattern賦給fillStyle或strokeStyle屬性。

function draw() {  
  var ctx = document.getElementById('lesson01').getContext('2d');    
  // create new image object to use as pattern  
  var img = new Image();  
  img.src = 'Penguins.jpg';  
  img.onload = function(){  

    // create pattern  
    var ptrn = ctx.createPattern(img,'repeat');  
    ctx.fillStyle = ptrn;  
    ctx.fillRect(0,0,150,150);  

  }  
}

建立陰影效果(目前Google Chrome 16.0.912.75還是不支援的)
主要是設定一下陰影效果的相關屬性值:

context.shadowOffsetX = float
context.shadowOffsetY = float
context.shadowBlur = float
context.shadowColor = color

shadowOffsetX和shadowOffsetY用來設定陰影在X和Y軸的延伸距離,它們是不受變換矩陣所影響的。負值表示陰影會往上或左延伸,正值則表示會往下或右延伸,他們預設都是0。
shadowBlur用於設定陰影的模糊程度,其數值並不跟畫素數量掛鉤,也不受變換矩陣的影響,預設為0。
shadowColor用於設定陰影效果的延伸,值可以是標準的CSS顏色值,預設是全透明的黑色。

function draw3() {  
  var ctx = document.getElementById('lesson01').getContext('2d');  

  ctx.shadowOffsetX = 3;  
  ctx.shadowOffsetY = 3;  
  ctx.shadowBlur = 3;  
  ctx.shadowColor = "rgba(100, 100, 0, 0.5)";  

  ctx.font = "20px Times New Roman";  
  ctx.fillStyle = "Black";  
  ctx.fillText("Sample String", 5, 30);  
}

這裡寫圖片描述
設定畫筆的型別
畫筆粗細:context.lineWidth = value
  這個屬性設定當前繪線的粗細。屬性值必須為正數。預設值是1.0。

  線寬是指給定路徑的中心到兩邊的粗細。換句話說就是在路徑的兩邊各繪製線寬的一半。因為畫布的座標並不和畫素直接對應,當需要獲得精確的水平或垂直線的時候要特別注意。
端點樣式:context.lineCap = type
  屬性 lineCap 的指決定了線段端點顯示的樣子。它可以為下面的三種的其中之一:butt,round 和 square。預設是 butt。每種設定完的效果如下圖lineCap部分從左到右所示。
連線點樣式:context.lineJoin = type
  lineJoin 的屬性值決定了圖形中兩線段連線處所顯示的樣子。它可以是這三種之一:round, bevel 和 miter。預設是 miter。每種設定完的效果如下圖lineJoin部分從上到下所示。
斜面連線限制:context.miterLimit = value
  當應用miter效果時,線段的外側邊緣會延伸交匯於一點上。線段直接夾角比較大的,交點不會太遠,但當夾角減少時,交點距離會呈指數級增大。這時可以用miterLimit屬性設定外延交點與連線點的最大距離,如果交點距離大於此值,連線效果會變成了 bevel。

function draw6() {  
  var ctx = document.getElementById('lesson01').getContext('2d');  
  var lineCap = ['butt','round','square'];  

  // Draw guides  
  ctx.strokeStyle = '#09f';  
  ctx.beginPath();  
  ctx.moveTo(10,10);  
  ctx.lineTo(140,10);  
  ctx.moveTo(10,140);  
  ctx.lineTo(140,140);  
  ctx.stroke();  

  // Draw lines  
  ctx.strokeStyle = 'black';  
  for (var i=0;i<lineCap.length;i++){  
    ctx.lineWidth = 15;  
    ctx.lineCap = lineCap[i];  
    ctx.beginPath();  
    ctx.moveTo(25+i*50,10);  
    ctx.lineTo(25+i*50,140);  
    ctx.stroke();  
  }  
}  
function draw() {  
  var ctx = document.getElementById('lesson01').getContext('2d');  
  var lineJoin = ['round','bevel','miter'];  
  ctx.lineWidth = 10;  
  for (var i=0;i<lineJoin.length;i++){  
    ctx.lineJoin = lineJoin[i];  
    ctx.beginPath();  
    ctx.moveTo(-5,5+i*40);  
    ctx.lineTo(35,45+i*40);  
    ctx.lineTo(75,5+i*40);  
    ctx.lineTo(115,45+i*40);  
    ctx.lineTo(155,5+i*40);  
    ctx.stroke();  
  }  
}

二、繪製簡單矩形
  矩形是唯一的基本圖形,canvas提供了直接的API支援。
•context.fillRect(x,y,width,height) : 繪製帶填充色的矩形。
•context.strokeRect(x,y,width,height) : 繪製矩形外框。
•context.clearRect(x,y,width,height) : 清空指定的矩形區域,並設定該區域是透明的(Transparent)。
它們都接受四個引數, x 和 y 指定矩形左上角(相對於原點)的位置,width 和 height 是矩形的寬和高。

  除了這種方式,還可以使用繪製路徑的方式繪製矩形,這個參看路徑繪圖部分。
繪製矩形的例子如下:

function draw(){
  var canvas = document.getElementById('tutorial');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    ctx.fillRect(25,25,100,100);
    ctx.clearRect(45,45,60,60);
    ctx.strokeRect(50,50,50,50);
  }
}

三、路徑繪圖

cavas只提供了繪製矩形的API,其他的圖形都是靠路徑繪製。

繪製一個圖形主要的過程如下:
1.啟動路徑
方法:使用context.beginPath()啟動路徑繪圖。
  在記憶體裡,路徑是以一組子路徑(直線,弧線等)的形式儲存的,它們共同構成一個圖形。每次呼叫 beginPath,子路徑組都會被重置,然後可以繪製新的圖形。
2.移動畫筆到起點
方法:使用moveTo(x, y)移動畫筆。
  雖然大多數畫圖的時候,用不到這個方法。我們也不能用這個方法來畫什麼,但是你可以把它想象成是把筆提起,並從一個點移動到另一個點的過程。當你繪製不聯絡的路徑的時候,你就會有這個動作了。
當 canvas 初始化或者呼叫 beginPath 的時候,起始座標設定就是原點(0,0)。有時候,我們需要moveTo方法將起始座標移至其它地方,用於繪製不連續的路徑。
3.記憶體中繪製線段
畫直線:lineTo(x, y)
  該方法接受終點的座標(x,y)作為引數。起始座標取決於前一路徑,前一路徑的終點即當前路徑的起點,起始座標通常也可以通過moveTo方法來設定。
畫圓弧:arc(x, y, radius, startAngle, endAngle, anticlockwise)
  我們用 arc 方法來繪製弧線或圓,方法接受五個引數:x,y 是圓心座標,radius 是半徑,startAngle 和 endAngle 分別是起末弧度(以 x 軸為基準),anticlockwise 為 true 表示逆時針,反之順時針。
注意:arc 方法裡用到的角度是以弧度為單位而不是度。度和弧度直接的轉換可以用這個表示式:var radians = (Math.PI/180)*degrees;
畫二次貝塞爾曲線:quadraticCurveTo(cp1x, cp1y, x, y)
畫三次貝塞爾曲線:bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
  貝塞爾曲線 ,它可以是二次和三次方的形式,一般用於繪製複雜而有規律的形狀。它們都有一個起點一個終點(下圖中的藍點),但二次方貝塞爾曲線只有一個(紅色)控制點點)而三次方貝塞爾曲線有兩個。
  引數x和y是終點座標,cp1x和 cp1y是第一個控制點的座標,cp2x和cp2y是第二個的。
  使用二次方和三次方的貝塞爾曲線是相當有挑戰的,因為缺少直觀性。理論上只要有耐心,再複雜的圖形都可以繪製出來的。
繪製矩形路徑:context.rect(x, y, width, height)
  當rect方法被呼叫時,moveTo方法會自動被呼叫,引數為(0,0),於是起始座標又恢復成初始原點了。
4.關閉路徑
方法:使用context.closePath()關閉路徑。

  該方法它會嘗試用直線連線當前端點與起始端點來關閉路徑,但如果圖形已經關閉或者只有一個點,它會什麼都不做,這一步在某些情況並不是必須的,比如使用fill()繪製實際圖形的時候,就不需要先呼叫closePath。
5.繪製路徑到canvas
畫圖形邊框:context.stroke()
填充實心圖形:context.fill()

最後這一步是呼叫 stroke或 fill方法,這時,圖形才是實際的繪製到 canvas 上去。

呼叫stroke之前必須要先呼叫關閉路徑方法closePath。而呼叫fill之前不需要呼叫closePath關閉路徑,呼叫fill時路徑會自動閉合。
一個複雜的例子如下:

function draw() {
  var ctx = document.getElementById('lesson01').getContext('2d');
  roundedRect(ctx,12,12,150,150,15);
  roundedRect(ctx,19,19,150,150,9);
  roundedRect(ctx,53,53,49,33,10);
  roundedRect(ctx,53,119,49,16,6);
  roundedRect(ctx,135,53,49,33,10);
  roundedRect(ctx,135,119,25,49,10);

  ctx.beginPath();
  ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,false); //chiensexu  ???true??,??
  ctx.lineTo(31,37);
  ctx.fill();
  for(i=0;i<8;i++){
    ctx.fillRect(51+i*16,35,4,4);
  }
  for(i=0;i<6;i++){
    ctx.fillRect(115,51+i*16,4,4);
  }
  for(i=0;i<8;i++){
    ctx.fillRect(51+i*16,99,4,4);
  }
  ctx.beginPath();
  ctx.moveTo(83,116);
  ctx.lineTo(83,102);
  ctx.bezierCurveTo(83,94,89,88,97,88);
  ctx.bezierCurveTo(105,88,111,94,111,102);
  ctx.lineTo(111,116);
  ctx.lineTo(106.333,111.333);
  ctx.lineTo(101.666,116);
  ctx.lineTo(97,111.333);
  ctx.lineTo(92.333,116);
  ctx.lineTo(87.666,111.333);
  ctx.lineTo(83,116);
  ctx.fill();
  ctx.fillStyle = "white";
  ctx.beginPath();
  ctx.moveTo(91,96);
  ctx.bezierCurveTo(88,96,87,99,87,101);
  ctx.bezierCurveTo(87,103,88,106,91,106);
  ctx.bezierCurveTo(94,106,95,103,95,101);
  ctx.bezierCurveTo(95,99,94,96,91,96);
  ctx.moveTo(103,96);
  ctx.bezierCurveTo(100,96,99,99,99,101);
  ctx.bezierCurveTo(99,103,100,106,103,106);
  ctx.bezierCurveTo(106,106,107,103,107,101);
  ctx.bezierCurveTo(107,99,106,96,103,96);
  ctx.fill();
  ctx.fillStyle = "black";
  ctx.beginPath();
  ctx.arc(101,102,2,0,Math.PI*2,true);
  ctx.fill();
  ctx.beginPath();
  ctx.arc(89,102,2,0,Math.PI*2,true);
  ctx.fill();
}

function roundedRect(ctx,x,y,width,height,radius){
  ctx.beginPath();
  ctx.moveTo(x,y+radius);
  ctx.lineTo(x,y+height-radius);
  ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
  ctx.lineTo(x+width-radius,y+height);
  ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
  ctx.lineTo(x+width,y+radius);
  ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
  ctx.lineTo(x+radius,y);
  ctx.quadraticCurveTo(x,y,x,y+radius);
  ctx.stroke();
}