H5 canvas

canvas元素的基礎(chǔ)知識

在頁面上放置一個(gè)canvas元素扯键,就相當(dāng)于在頁面上放置了一塊畫布颂龙,可以在其中進(jìn)行圖形的描繪。
canvas元素只是一塊無色透明的區(qū)域鳍咱,需要利用JS編寫在其中進(jìn)行繪畫的腳本降盹。

在頁畫中放置canvas元素

首先,應(yīng)該要指定的是·id谤辜、width蓄坏、height三個(gè)屬性 。

<canvas id="canvas" width="400" height="300" />

繪制矩形

canvas元素繪制圖形時(shí)丑念,需要經(jīng)過幾道步驟:

  • 取得canvas元素
  • 取得上下文 (context):圖形上下文中是一個(gè)封裝了很多繪圖功能的對象涡戳。需要使用canvas對象的getContext方法來獲得圖形上下文。將getContext的參數(shù)設(shè)為2d脯倚。
  • 填充與繪制邊框:填充(fill)是指填滿圖形內(nèi)部渔彰,繪制邊框(stroke)只繪制圖形的外邊框。
  • 設(shè)定繪圖樣式 (style)推正,指定顏色值:fillStyle屬性用來設(shè)置填充的樣式和顏色恍涂,strokeStyle屬性用來設(shè)置邊框的樣式和顏色。
  • 指定線寬:lineWidth屬性用來設(shè)置圖形邊框的寬度植榕。
  • 繪制矩形:分別使用fillRect方法與strokeRect方法來填充矩形和繪制矩形邊框再沧。

與矩形相關(guān)的方法有:fillRect()strokeRect()clearRect()尊残。

context.fillRect(x, y, width, height);
context.strokeRect(x, y, width, height);
context.clearRect(x, y, width, height);

這里的context指的是圖形上下文對象炒瘸,這三個(gè)方法使用同樣的參數(shù),x指矩形起點(diǎn)的橫坐標(biāo)夜郁,y指矩形起點(diǎn)的縱坐標(biāo)什燕,坐標(biāo)原點(diǎn)為canvas畫布的最左上角,width指矩形的寬度竞端,height指矩形的高度屎即。
fillRect()方法在畫布上繪制的矩形會填充指定的顏色。
strokeRect()方法在畫布上繪制的矩形區(qū)域會使用指定的顏色描邊事富。
clearRect()方法會擦除指定的矩形區(qū)域中的圖形技俐,使得矩形區(qū)域中的顏色全部變?yōu)橥该鳌?/p>

function draw(id) {
  var canvas = document.getElementById(id);
  if(canvas == null) { return false; }
  var context = canvas.getContext('2d');
  context.fillStyle = '#eeeeff';
  context.fillRect(0, 0, 400, 300);
  context.fillStyle = 'red';
  context.strokeStyle = 'blue';
  context.lineWidth = 1;
  context.fillRect(50, 50, 100, 100);
  context.strokeRect(50, 50, 100, 100);
}

運(yùn)行效果如圖:

使用路徑

繪制圓形

需要執(zhí)行如下步驟:

開始創(chuàng)建路徑

使用圖形上下文對象的beginPath方法。

context.beginPath();

該方法不使用參數(shù)统台,通過該方法開始路徑的創(chuàng)建雕擂。在幾次循環(huán)的創(chuàng)建路徑的過程中,每次開始創(chuàng)建時(shí)都要調(diào)用beginPath()方法贱勃。

創(chuàng)建圖形的路徑

創(chuàng)建圓形路徑時(shí)井赌,需要使用圖形上下文對象的arc方法谤逼。

context.arc(x, y, radius, startAngle, endAngle, anticlockwise);

該方法使用6個(gè)參數(shù),x為繪制圓形的起點(diǎn)橫坐標(biāo)仇穗,y為繪制圓形的起點(diǎn)縱坐標(biāo)流部,radius為圓形半徑,startAngle為開始角度纹坐,endAngle為結(jié)束角度枝冀,anticlockwise為是否按順時(shí)針方向進(jìn)行繪制。anticlockwise參數(shù)為一個(gè)布爾值的參數(shù)耘子,為true時(shí)果漾,按順時(shí)針繪制,為false時(shí)谷誓,按逆時(shí)針繪制绒障。

路徑創(chuàng)建完成后,關(guān)閉路徑

使用圖形上下文對象的closePath方法將路徑閉合片林。

context.closePath();

將路徑閉合后端盆,路徑的創(chuàng)建工作就完成了,但這時(shí)只是路徑創(chuàng)建完畢费封,還沒有真正繪制圖形焕妙。

設(shè)定繪制樣式,調(diào)用繪制方法弓摘,繪制路徑

使用fill()焚鹊、stroke()fillStyle()strokeStyle()指定繪制樣式韧献。

// 繪制圓形
function draw(id) {
  var canvas = document.getElementById(id);
  if(canvas == null) { return false; }
  var context = canvas.getContext('2d');
   context.fillStyle = '#eeeeff';
  context.fillRect(0, 0, 400, 300);
  var n = 0;
  for(var i = 0;i<10; i++) {
    context.beginPath();
    context.arc(i * 25, i * 25, i * 10, 0, Math.PI * 2, true);
    context.closePath();
    context.fillStyle = 'rgba(255, 0, 0, 0.25)';
    context.fill();
  }
}

效果如圖:

路徑未閉合

如果把上例中的開始創(chuàng)建路徑語句和閉合路徑語句刪除末患,在畫布中先是繪制一個(gè)深紅色的半徑最小的圓,然后每次半徑變大的同時(shí)锤窑,圓的顏色也在逐漸變淡璧针。
在循環(huán)時(shí)的具體繪制過程:

  • 創(chuàng)建并繪制第一個(gè)圓
  • 創(chuàng)建第二個(gè)圓,這時(shí)因?yàn)闆]有把第一個(gè)圓的路徑閉合渊啰,所以第一個(gè)圓的路徑也保留著探橱。繪制第二個(gè)圓的時(shí)候,第一個(gè)圓會根據(jù)該路徑重復(fù)繪制绘证,第二個(gè)圓只繪制一次隧膏,而第一個(gè)圓繪制了兩次。
  • 創(chuàng)建第三個(gè)圓嚷那,繪制時(shí)胞枕,第三個(gè)圓只繪制了一次,第二個(gè)圓繪制兩次魏宽,第一個(gè)圓繪制了三次腐泻。
  • 同上......

所以如果不閉合路徑决乎,已經(jīng)創(chuàng)建的路徑會永遠(yuǎn)保留著。
效果如圖:

moveTo與lineTo

繪制直線時(shí)贫悄,一般會用到moveTolineTo兩種方法瑞驱。
moveTo方法的作用是將光標(biāo)移動到指定坐標(biāo)點(diǎn),繪制直線的時(shí)候以這個(gè)坐標(biāo)點(diǎn)為起點(diǎn)窄坦。

moveTo(x, y);

lineTo方法在moveTo方法中指定的直線起點(diǎn)與參數(shù)中指定的直線終點(diǎn)之間繪制一條直線。

lineTo(x, y);

使用該方法繪制完直線后凳寺,光標(biāo)自動移動到lineTo方法的參數(shù)所指定的直線終點(diǎn)鸭津。
因此,在創(chuàng)建路徑時(shí)肠缨,需要使用moveTo方法將光標(biāo)移動到指定的直線起點(diǎn)逆趋,然后使用lineTo方法在直線起點(diǎn)與直線終點(diǎn)之間創(chuàng)建路徑,然后將光標(biāo)移動到直線終點(diǎn)晒奕,在下一次使用lineTo方法的時(shí)候闻书,會以當(dāng)前光標(biāo)所在坐標(biāo)點(diǎn)為直線起點(diǎn),并在下一個(gè)用lineTo方法指定的直線終點(diǎn)之間創(chuàng)建路徑脑慧,它會不斷重復(fù)這個(gè)過程魄眉,來完成復(fù)雜圖形的路徑繪制。

function draw(id) {  
    var canvas = document.getElementById(id);  
    if (canvas == null)  { return false; }  
    var context = canvas.getContext('2d');  
    context.fillStyle = "#EEEEFF";  
    context.fillRect(0, 0, 400, 300);  
    var n = 0;  
    var dx = 150;  
    var dy = 150;  
    var s = 100;  
    context.beginPath();  
    context.fillStyle = 'rgb(100,255,100)';  
    context.strokeStyle = 'rgb(0,0,100)';  
    var x = Math.sin(0);  
    var y = Math.cos(0);  
    var dig = Math.PI / 15 * 11;  
    for(var i = 0; i < 30; i++) {  
        var x = Math.sin(i * dig);  
        var y = Math.cos(i * dig);  
        context.lineTo( dx + x * s,dy + y * s);  
    }     
    context.closePath();  
    context.fill();  
    context.stroke();  
}

運(yùn)行效果如圖:

使用bezierCurveTo繪制貝濟(jì)埃曲線

繪制貝濟(jì)埃曲線需要使用bezierCurveTo()方法闷袒,該方法可以說是lineTo的曲線版坑律。

context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);

該方法有6個(gè)參數(shù)。繪制曲線時(shí)囊骤,需要兩個(gè)控制點(diǎn)晃择,cp1x為第一個(gè)控制點(diǎn)的橫坐標(biāo),cp1y為第一個(gè)控制點(diǎn)的縱坐標(biāo)也物;cp2x為第二個(gè)控制點(diǎn)的橫坐標(biāo)宫屠,cp2y為第二個(gè)控制點(diǎn)的縱坐標(biāo);x為貝濟(jì)埃曲線的終點(diǎn)橫坐標(biāo)滑蚯,y為貝濟(jì)埃曲線的終點(diǎn)縱坐標(biāo)浪蹂。

function draw(id) {  
    var canvas = document.getElementById(id);  
    if (canvas == null)  { return false; }  
    var context = canvas.getContext('2d');  
    context.fillStyle = "#EEEEFF";  
    context.fillRect(0, 0, 400, 300);  
    var n = 0;  
    var dx = 150;  
    var dy = 150;  
    var s = 100;  
    context.beginPath();  
    context.globalCompositeOperation ='and';  
    context.fillStyle = 'rgb(100,255,100)';  
    var x = Math.sin(0);  
    var y = Math.cos(0);  
    var dig = Math.PI / 15 * 11;  
    context.moveTo(dx,dy);  
    for(var i = 0; i < 30; i++) {  
        var x = Math.sin(i * dig);  
        var y = Math.cos(i * dig);  
        context.bezierCurveTo(dx + x * s,dy + y * s - 100,dx + x * s + 100,dy + y * s,dx + x * s,dy + y * s);  
    }     
    context.closePath();  
    context.fill();  
    context.stroke();  
}

運(yùn)行效果如圖:

另外,還可以使用quadraticCurveTo方法繪制二次樣條曲線膘魄。

context.quadraticCurveTo(in float cpx,in float cpy,in float x,in float y)

這四個(gè)參數(shù)分別是控制點(diǎn)的橫坐標(biāo)乌逐,控制點(diǎn)的縱坐標(biāo),二次樣條曲線終點(diǎn)的橫坐標(biāo)创葡,二次樣條曲線終點(diǎn)的縱坐標(biāo)浙踢。

繪制漸變圖形

繪制線性漸變

漸變是指在填充時(shí)從一種顏色慢慢過渡到另一種顏色。最簡單的是兩點(diǎn)之間的線性漸變灿渴。
繪制線性漸變時(shí)洛波,需要使用到LinearGradient對象胰舆,可以使用圖形上下文對象的createLinearGradient()方法創(chuàng)建該對象。

context.createLinearGradient(xStart, yStart, xEnd, yEnd);

該方法有4個(gè)參數(shù)蹬挤,xStart為漸變起始點(diǎn)的橫坐標(biāo)缚窿,yStart為漸變起始點(diǎn)的縱坐標(biāo),xEnd為漸變結(jié)束點(diǎn)的橫坐標(biāo)焰扳,yEnd為漸變結(jié)束點(diǎn)的縱坐標(biāo)倦零。
在創(chuàng)建linearGradient對象后,使用addColorStop()方法設(shè)定漸變的顏色吨悍。

context.addColorStop(offset, color);

offset參數(shù)為所設(shè)定的顏色離開漸變起始點(diǎn)的偏移量扫茅,該參數(shù)的值是一個(gè)范圍在0~1之間的浮點(diǎn)值,漸變起始點(diǎn)的偏移量為0育瓜,漸變結(jié)束點(diǎn)的偏移量為1葫隙。color為繪制時(shí)的顏色。
因?yàn)槭菨u變躏仇,所以至少需要使用兩次addColorStop方法以追加兩個(gè)顏色(開始顏色和結(jié)束顏色)恋脚,可以追加多個(gè)顏色。例如從藍(lán)色漸變到白色然后漸變到綠色焰手。這時(shí)藍(lán)色的位移量為0糟描,白色的位移量為0.5,綠色的位移量為1册倒。
接著把fillStylestrokeStyle設(shè)定為linearGradient對象蚓挤,然后執(zhí)行填充的方法,就可以繪制漸變圖形了驻子。

function draw(id) {
  var canvas = document.getElementById(id);
  if(canvas == null) { return false; }
  var context = canvas.getContext('2d');
  var g1 = context.createLinearGradient(0, 0, 0, 300);
  g1.addColorStop(0, 'rgb(255, 255, 0)');
  g1.addColorStop(1, 'rgb(0, 255, 255)');
  context.fillStyle = g1;
  context.fillRect(0, 0, 400, 300);
  var n = 0;
  var g2 = context.createLinearGradient(0, 0, 300, 0);
  g2.addColorStop(0, 'rgba(0, 0, 255, 0.5)');
  g2.addColorStop(1, 'rgba(255, 0, 0, 0.5)');
  for(var i = 0; i < 10; i++) {
    context.beginPath();
    context.fillStyle = g2;
    context.arc(i * 25, i * 25, i * 10, 0, Math.PI * 2, true);
    context.closePath();
    context.fill();
  }
}

效果如圖:

繪制徑向漸變

徑向漸變是指沿著圓形的半徑方向向外進(jìn)行擴(kuò)散的漸變方式灿意。比如在描繪太陽時(shí),沿著太陽的半徑方向向外擴(kuò)散出去的光暈崇呵,就是一種徑向漸變缤剧。
使用圖形上下文對象的createRadialGradient方向繪制徑向漸變。

context.createRadialGradient(xStart, yStart, radiusStart, xEnd, yEnd, radiusEnd);

該方法使用六個(gè)參數(shù)域慷,xStart為漸變開始圓的圓心橫坐標(biāo)荒辕,yStart為漸變開始圓的圓心縱坐標(biāo),radiusStart為開始圓的半徑犹褒,xEnd為漸變結(jié)束圓的圓心橫坐標(biāo)抵窒,yEnd為漸變結(jié)束圓的圓心縱坐標(biāo),radiusEnd為結(jié)束圓的半徑叠骑。
在這個(gè)方法中李皇,分別指定了兩個(gè)圓的大小與位置。從第一個(gè)圓的圓心處向外進(jìn)行擴(kuò)散漸變宙枷,一直擴(kuò)散到第二個(gè)圓的外輪廓處掉房。
在設(shè)定顏色時(shí)茧跋,與線性漸變相同,使用addColorStop方法進(jìn)行設(shè)定卓囚。同樣也需要設(shè)定0~1之間的浮點(diǎn)數(shù)來作為漸變轉(zhuǎn)折點(diǎn)的偏移量瘾杭。

function draw(id) {
  var canvas = document.getElementById(id);
  if(canvas == null) { return false; }
  var context = canvas.getContext('2d');
  var g1 = context.createRadialGradient(400, 0, 0, 400, 0, 400);
  g1.addColorStop(0.1, 'rgb(255, 255, 0)');
  g1.addColorStop(0.3, 'rgb(255, 0, 255)');
  g1.addColorStop(1, 'rgb(0, 255, 255)');
  context.fillStyle = g1;
  context.fillRect(0, 0, 400, 300);
  var n = 0;
  var g2 = context.createRadialGradient(250, 250, 0, 250, 250, 300);
  g2.addColorStop(0.1, 'rgba(255, 0, 0, 0.5)');
  g2.addColorStop(0.7, 'rgba(255, 255, 0, 0.5)');
  g2.addColorStop(1, 'rgba(0, 0, 255, 0.5)');
  for(var i = 0; i < 10; i++) {
    context.beginPath();
    context.fillStyle = g2;
    context.arc(i * 25, i * 25, i * 10, 0, Math.PI * 2, true);
    context.closePath();
    context.fill();
  }
}

效果如圖:

繪制變換圖形

坐標(biāo)變換

繪制圖形的時(shí)候,我們經(jīng)常想要旋轉(zhuǎn)圖形哪亿,或?qū)D形使用變形處理粥烁,使用Canvas的坐標(biāo)變換處理功能,可以實(shí)現(xiàn)這個(gè)效果锣夹。
在計(jì)算機(jī)上繪制圖形的時(shí)候页徐,是以坐標(biāo)單位為基準(zhǔn)來進(jìn)行圖形繪制的。默認(rèn)情況下银萍,Canvas畫布的最左上角對應(yīng)于坐標(biāo)軸原點(diǎn)(0, 0)。
對坐標(biāo)的變形處理有三種方式恤左。

平移

使用圖形上下文對象的translate方法移動坐標(biāo)軸原點(diǎn)贴唇。

context.translate(x, y);

x表示坐標(biāo)軸原點(diǎn)向左移動多少個(gè)單位,默認(rèn)情況下為像素飞袋;y表示將坐標(biāo)軸原點(diǎn)向下移動多少個(gè)單位戳气。

擴(kuò)大

使用圖形上下文對象的scale方法將圖形放大。

context.scale(x, y);

x是水平方向放大的倍數(shù)巧鸭,y是垂直方向放大的倍數(shù)瓶您。

旋轉(zhuǎn)

使用圖形上下文對象的rotate方法將圖形進(jìn)行旋轉(zhuǎn)。

context.rotate(angle);

rotate方法接收一個(gè)參數(shù)angle纲仍,angle是指旋轉(zhuǎn)的角度呀袱,旋轉(zhuǎn)的中心點(diǎn)是坐標(biāo)軸的原點(diǎn)。旋轉(zhuǎn)是以順時(shí)針方向進(jìn)行的郑叠,要想逆時(shí)針旋轉(zhuǎn)夜赵,將angle設(shè)定為負(fù)數(shù)就可以了。

function draw(id) {
  var canvas = document.getElementById(id);
  if(canvas == null) { return false; }
  var context = canvas.getContext('2d');
  context.fillStyle = '#eeeeff';
  context.fillRect(0, 0, 400, 300);
  // 圖形繪制
  context.translate(200, 50);
  context.fillStyle = 'rgba(255, 0, 0, 0.25)';
  for(var i = 0; i <50; i++) {
    context.translate(200, 50);
    context.scale(0.95, 0.95);
    context.rotate(Math.PI / 10);
    context.fillRect(0, 0, 100, 50);
  }
}

運(yùn)行效果如圖:

坐標(biāo)變換與路徑的結(jié)合使用

如果要對矩形進(jìn)行變形乡革,使用坐標(biāo)變換就行了寇僧。但對使用路徑繪制出來的圖形進(jìn)行變換的時(shí)候,考慮的事情就多了沸版。因?yàn)槭褂昧俗鴺?biāo)變換之后嘁傀,已經(jīng)創(chuàng)建好的路徑就不能用了,必須要重新創(chuàng)建路徑视粮。重新創(chuàng)建好路徑后细办,坐標(biāo)變換方法又失效了。
必須先另外寫一個(gè)創(chuàng)建路徑的函數(shù)馒铃,然后在坐標(biāo)變換的同時(shí)調(diào)用該函數(shù)蟹腾,這樣才能解決這個(gè)問題痕惋。

function draw(id) {
  var canvas = document.getElementById(id);
  if(canvas == null) { return false; }
  var context = canvas.getContext('2d');
  context.fillStyle = '#eeeeff';
  context.fillRect(0, 0, 400, 300);
  // 圖形繪制
  context.translate(200, 50);
  for(var i = 0; i < 50; i++) {
    context.translate(25, 25);
    context.scale(0.95, 0.95);
    context.rotate(Math.PI / 10);
    create5Star(context);
    context.fill();
  }
}
function create5Star(context) {
  var n = 0;
  var dx = 100;
  var dy = 0;
  var s = 50;
  // 創(chuàng)建路徑
  context.beginPath();
  context.fillStyle = 'rgba(255, 0, 0, 0.5)';
  var x = Math.sin(0);
  var y = Math.cos(0);
  var dig = Math.PI / 5 * 4;
  for (var i = 0; i < 5; i++) {
    var x = Math.sin(i * dig);
    var y = Math.cos(i * dig);
    context.lineTo(dx + x * s, dy + y * s);
  }
  context.closePath();
}

上面的代碼可以繪制一個(gè)將五角星一邊旋轉(zhuǎn)一邊縮小的圖形。在create5Star函數(shù)中娃殖,創(chuàng)建了一個(gè)五角星的路徑值戳,然后在draw函數(shù)的for循環(huán)中,首先依次執(zhí)行translate炉爆、scale堕虹、rotate方法,然后執(zhí)行create5Star函數(shù)創(chuàng)建路徑芬首,最后執(zhí)行fill填充赴捞。
create5Star函數(shù)中,只創(chuàng)建了一個(gè)五角星郁稍,因坐標(biāo)軸變換赦政,在畫布中,此五角星一邊縮小一邊旋轉(zhuǎn)耀怜,之后產(chǎn)生一個(gè)新的五角星新的五角星又采用同樣的方法進(jìn)行繪制恢着,最終繪制出來一串具有變形效果的五角星的圖形。
效果如圖:

矩陣變換

變換矩陣是專門用來實(shí)現(xiàn)圖形變形的财破,它與坐標(biāo)一起配合使用掰派,以達(dá)到變形的目的。當(dāng)圖形上下文被創(chuàng)建完畢時(shí)左痢,事實(shí)上也創(chuàng)建了一個(gè)默認(rèn)的變換矩陣靡羡,如果不對這個(gè)變換矩陣進(jìn)行修改,那么接下來繪制的圖形將以畫布的最左上角為坐標(biāo)原點(diǎn)繪制圖形俊性,繪制出來的圖形也不經(jīng)過縮放略步、變形的處理,但如果對這個(gè)變換矩陣進(jìn)行修改磅废,那么情況就完全不一樣了纳像。
使用圖形上下文對象的transform方法修改變換矩陣。

context.transform(m11, m22, m21, dx, dy);

該方法使用一個(gè)新的變換矩陣與當(dāng)前變換矩陣進(jìn)行乘法運(yùn)算拯勉。

m11  m21  dx
m12  m22  dy
 0    0   1

m11竟趾,m21m12宫峦,m22四個(gè)參數(shù)用來修改使用這個(gè)方法之后岔帽,繪制圖形時(shí)的計(jì)算方法,以達(dá)到變形目的导绷,dx和dy參數(shù)移動坐標(biāo)原點(diǎn)犀勒,dx表示將坐標(biāo)原點(diǎn)在x軸上向右移動x個(gè)單位,默認(rèn)情況下以像素為單位,dy表示將坐標(biāo)原點(diǎn)在y軸上向下移動y個(gè)單位贾费。
translate钦购、scalerotate這三個(gè)方法實(shí)際上都是隱式的修改了變換矩陣,都可以使用transform方法來進(jìn)行代替褂萧。
translate(x, y)可以使用context.transform(1, 0, 0, 1, x, y)context.transform(0, 1, 1, 0, x, y)方法進(jìn)行代替押桃,前面四個(gè)參數(shù)表示不對圖形進(jìn)行縮放、變形导犹,將dx設(shè)為x表示將坐標(biāo)原點(diǎn)向右移動x個(gè)單位唱凯,dy設(shè)為y表示將坐標(biāo)原點(diǎn)向下移動y個(gè)單位。
scale(x, y)可以使用context.transform(x, 0, 0, y, 0, 0)context.transform(0, y, x, 0, 0, 0)方法代替谎痢,前面四個(gè)參數(shù)表示將圖形橫向擴(kuò)大x倍磕昼,縱向擴(kuò)大y倍。dx节猿,dy為0表示不移動坐標(biāo)原點(diǎn)票从。
rotate(angle)替換方法如下:

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

其中前面四個(gè)參數(shù)以三角函數(shù)的形式結(jié)合起來,共同完成圖形按angle角度的順時(shí)針旋轉(zhuǎn)處理滨嘱,dx纫骑,dy為0表示不移動坐標(biāo)原點(diǎn)。

function draw(id) {
  var canvas = document.getElementById(id);
  if(canvas == null) { return false; }
  var context = canvas.getContext('2d');
  // 定義顏色
  var colors = ['red', 'orange', 'yellow', 'green', 'blue', 'navy', 'purple'];
  // 定義線寬
  context.lineWidth = 10;
  context.transform(1, 0, 0, 1, 100, 0);
  // 循環(huán)繪制圓弧
  for(var i = 0; i < colors.length; i++) {
    // 定義每次向下移動10個(gè)像素的變換矩陣
    context.transform(1, 0, 0, 1, 0, 10);
    // 設(shè)定顏色
    context.strokeStyle = colors[i];
    // 繪制圓弧
    context.beginPath();
    context.arc(50, 100, 100, 0, Math.PI, true);
    context.stroke();
  }
}

上面的代碼用循環(huán)的方法繪制了幾個(gè)圓弧九孩,圓弧的大小與位置均不變,只是使用了transform方法讓坐標(biāo)原點(diǎn)每次向下移動10個(gè)像素发框,使得繪制出來的圓弧相互重疊躺彬,然后對圓弧設(shè)置七彩顏色,使這些圓弧的外觀達(dá)到彩虹的效果梅惯。
效果如圖:

使用了transform方法后宪拥,接下來要繪制的圖形都會按照移動后的坐標(biāo)原點(diǎn)與新的變換矩陣相結(jié)合的方法進(jìn)行繪制,必要時(shí)可以使用setTransform方法將變換矩陣進(jìn)行重置铣减。

context.setTransform(m11, m12, m21, m22, dx, dy);

該方法的參數(shù)與transform相同她君,事實(shí)上,該方法的作用為將畫布上的最左上角重置為坐標(biāo)原點(diǎn)葫哗,當(dāng)圖形上下文創(chuàng)建完畢時(shí)將所創(chuàng)建的初始變換矩陣設(shè)置為當(dāng)前變換矩陣缔刹,然后使用transform方法。

function draw(id) {
  var canvas = document.getElementById(id);
  if(canvas == null) { return false; }
  var context = canvas.getContext('2d');
  // 繪制紅色長方形
  context.strokeStyle = 'red';
  context.strokeRect(30, 10, 60, 20);
  // 繪制順時(shí)針旋轉(zhuǎn)45°后的藍(lán)色長方形
  // 繪制45°圓弧
  var rad = 45 * Math.PI / 180;
  // 定義順時(shí)針旋轉(zhuǎn)45°的變換矩陣
  context.setTransform(Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), 0, 0);
  // 繪制圖形
  context.strokeStyle = 'blue';
  context.strokeRect(30, 10, 60, 20);
  // 繪制方法2.5倍后的綠色長方形
  // 定義放大2.5倍的變換矩陣
  context.setTransform(2.5, 0, 0, 2.5, 0, 0);
  // 繪制圖形
  context.strokeStyle = 'green';
  context.strokeRect(30, 10, 60, 20);
  // 將坐標(biāo)原點(diǎn)向右移動40像素劣针,向下移動80像素后繪制灰色長方形
  // 定義將坐標(biāo)原點(diǎn)向右移動40像素校镐,向下移動80像素的矩陣
  context.setTransform(1, 0, 0, 1, 40, 80);
  // 繪制圖形
  context.strokeStyle = 'gray';
  context.strokeRect(30, 10, 60, 20);
}

上面的代碼先創(chuàng)建了一個(gè)紅色邊框的長方形,然后將該長方形順時(shí)針旋轉(zhuǎn)45度捺典,繪制出一個(gè)新的長方形鸟廓,并繪制其邊框?yàn)樗{(lán)色,然后將紅色長方形擴(kuò)大2.5倍繪制新的長方形,邊框?yàn)榫G色引谜,最后在紅色長方形右下方繪制同樣大小的長方形牍陌,邊框?yàn)榛疑?br> 效果如圖:

圖形組合

在H5中,只要用圖形上下文對象的globalCompositeOperation屬性就能自己決定圖形的組合方式了员咽。

context.globalCompositeOperation = type;

type的值必須是下面幾種字符串之一:

  • source-over(默認(rèn)值):表示新圖形覆蓋在原有圖形之上
  • destination-over:表示在原有圖形之下繪制新圖形
  • source-in:新圖形與原有圖形作in運(yùn)算毒涧,只顯示新圖形中與原有圖形相重疊的部分,新圖形與原有圖形的其他部分均變成透明
  • destination-in:原有圖形與新圖形作in運(yùn)算骏融,只顯示原有圖形中與新圖形相重疊的部分链嘀,新圖形與原有圖形的其他部分均變成透明
  • source-out:新圖形與原有圖形作out運(yùn)算,只顯示新圖形中與原有圖形不重疊的部分档玻,新圖形與原有圖形的其他部分均變成透明
  • destination-out:原有圖形與新圖形作out運(yùn)算怀泊,只顯示原有圖形中與新圖形不重疊的部分,新圖形與原有圖形的其他部分均變成透明
  • source-atop:只繪制新圖形中與原有圖形重疊的部分與未被重疊覆蓋的原有圖形误趴,新圖形的其他部分變成透明
  • destination-atop:只繪制原有圖形中被新圖形重疊覆蓋的部分與新圖形的其他部分 霹琼,原有圖形中的其他部分變成透明,不繪制新圖形中與原有圖形相重疊的部分
  • lighter:原有圖形與新圖形均繪制凉当,重疊部分做加色處理
  • xor:只繪制新圖形中與原有圖形不重疊的部分枣申,重疊部分變成透明
  • copy:只繪制新圖形,原有圖形中未與新圖形重疊的部分變成透明

如果指定的type不在這幾個(gè)字符串當(dāng)中看杭,則按默認(rèn)方式組合圖形忠藤。

function draw(id) {  
  var canvas = document.getElementById(id);  
  if (canvas == null) { return false; }
  var context = canvas.getContext('2d'); 
  var oprtns = new Array(
    "source-atop",
    "source-in",
    "source-out",
    "source-over",
    "destination-atop",
    "destination-in",
    "destination-out",
    "destination-over",
    "lighter",
    "copy",
    "xor"
    );
    i=8;   
    // 顯示想要查看的組合效果
    // 繪制原有圖形(藍(lán)色長方形)
    context.fillStyle = "blue";
    context.fillRect(10, 10, 60, 60);
    /* 設(shè)置組合方式,從組合的參數(shù)數(shù)組中挑選組合方式楼雹,此處因?yàn)閕是8模孩,
   所以選擇oprtns數(shù)組中第9(數(shù)組從0開始計(jì)算)個(gè)組合方式lighter */
    context.globalCompositeOperation = oprtns[i];
    //設(shè)置新圖形(紅色圓形)
    context.beginPath();
    context.fillStyle = "red";
    context.arc(60, 60, 30, 0, Math.PI * 2, false);
    context.fill();
} 

上面的代碼將所有的圖形組合方式放在一個(gè)數(shù)組中,然后通過變量i來指定挑選哪種組合方式進(jìn)行顯示贮缅。
效果如圖:

給圖形繪制陰影

使用Canvas元素可以給圖形添加陰影效果榨咐。
圖形上下文對象的關(guān)于陰影繪制的屬性:

  • shadowOffsetX:陰影的橫向位移量,默認(rèn)為0谴供。
  • shadowOffsetY:陰影的縱向位移量块茁,默認(rèn)為0。
  • shadowColor:陰影的顏色桂肌。
  • shadowBlur:陰影的模糊范圍数焊,可選。屬性值是比0大的數(shù)字轴或,否則將被忽略昌跌。
function draw(id) {  
  var canvas = document.getElementById(id);  
  if (canvas == null) { return false; }
  var context = canvas.getContext('2d');  
  context.fillStyle = "#EEEEFF";  
  context.fillRect(0, 0, 400, 300);  
  context.shadowOffsetX = 10;  
  context.shadowOffsetY = 10;  
  context.shadowColor = 'rgba(100,100,100,0.5)';  
  context.shadowBlur = 7.5;  
  // 圖形繪制  
  context.translate(0,50);  
  for(var i = 0;i < 3;i++){  
    context.translate(50,50);  
    create5Star(context);  
    context.fill();  
  }  
}  
function create5Star(context) {  
  var n = 0;  
  var dx = 100;  
  var dy = 0;  
  var s = 50;  
  //創(chuàng)建路徑  
  context.beginPath();  
  context.fillStyle = 'rgba(255,0,0,0.5)';  
  var x = Math.sin(0);  
  var y = Math.cos(0);  
  var dig = Math.PI / 5 * 4;  
  for(var i = 0; i < 5; i++) {  
    var x = Math.sin(i * dig);  
    var y = Math.cos(i * dig);  
    context.lineTo( dx + x * s,dy + y * s);  
  }     
  context.closePath();  
}

效果如圖:

上面的代碼使用translate方法繪制了幾個(gè)呈移動狀態(tài)的五角星。同時(shí)給每個(gè)五角星都加上了陰影效果照雁。繪制陰影的時(shí)候使用了圖形上下文對象的繪制陰影屬性蚕愤,這幾個(gè)屬性與路徑無關(guān)答恶,只要設(shè)定一次之后,全部五角星就都具有陰影效果了萍诱。
如果不想讓全部五角星都具有陰影效果悬嗓,需要把shadowColor屬性設(shè)定為rgba(0, 0, 0, 0)

使用圖像

繪制圖像

繪制圖像使用drawlmage()方法裕坊。

context.drawlmage(image,x,y);
context.drawlmage(image,x,y,w,h);
cont ext.drawlmage(image,sx,sy,sw,sh,dx,dy,dw,dh);

第一種方法只使用三個(gè)參數(shù)包竹,image是一個(gè)Image對象,用該對象來裝載圖像文件籍凝。 xy為繪制時(shí)該圖像在畫布中的起始坐標(biāo)周瞎。
第二種方法中前三個(gè)參數(shù)與第一種方法中的使用方法一樣,w饵蒂、h是指繪制時(shí)的圖像的寬度與高度声诸。第一種方法中省略了這兩個(gè)參數(shù),所以繪制出來的圖像與原圖大小相同退盯,而第二種方法可以用來進(jìn)行圖像縮放 彼乌。
第三種方法可以用來將畫布中已繪制好的圖像的全部或者局部區(qū)域復(fù)制到畫布中的另一個(gè)位置上。該方法使用九個(gè)參數(shù)渊迁,image代表被復(fù)制的圖像文件慰照,sxsy分別表示源圖像的被復(fù)制區(qū)域在畫布中的起始橫坐標(biāo)與起始縱坐標(biāo),swsh表示被復(fù)制區(qū)域的寬度與高度琉朽,dxdy表示復(fù)制后的目標(biāo)圖像在畫布中的起始橫坐標(biāo)與起始縱坐標(biāo)毒租,dwdh表示復(fù)制后的目標(biāo)圖像的寬度與高度。該方法可以只復(fù)制圖像的局部箱叁,只要將sxsy設(shè)為局部區(qū)域的起始點(diǎn)坐標(biāo)蝌衔, 將swsh設(shè)為局部區(qū)域的寬度與高度就可以了。該方能也可以用來將源圖像進(jìn)行縮放,只要將dwdh設(shè)為縮放后的寬度與高度就可以了。
繪制圖像時(shí)首先使用不帶參數(shù)的new方法創(chuàng)建Image對象巴元,然后設(shè)定Image對象的src屬性為需要繪制的圖像文件的路徑论矾。

image = new Image();
image.src = "image1.jpg"; //設(shè)置圖像路徑

然后就可以使用drawlmage方能繪制該圖像文件了。
事實(shí)上沛简,即使設(shè)定好Image對象的src屬性后齐鲤,也不一定立刻就能把圖像繪制完畢,譬如椒楣,有時(shí)該圖像文件是一個(gè)來源于網(wǎng)絡(luò)的比較大的圖像文件给郊,這時(shí)就得耐心等待圖像全部裝載完畢才能看見該圖像。
這種情況下捧灰,需要先等圖形加載完畢再繪制圖像文件淆九。

image.onload = function(){ 
  // 繪制圖像的函數(shù) 
}

Image對象的onload事件中同步執(zhí)行繪制圖像的函數(shù),就可以一邊裝載一邊繪制了。

function draw(id) {  
  var canvas = document.getElementById(id);  
  if (canvas == null)  { return false; }  
  var context = canvas.getContext('2d');  
  context.fillStyle = "#EEEEFF";  
  context.fillRect(0, 0, 400, 300);  
  image = new Image(); 
  image.src = "tyl.jpg";  
  image.onload = function() {  
    drawImg(context, image);  
  };       
}  
function drawImg(context, image){  
  for(var i = 0;i < 7;i++)  {
    context.drawImage(image, 0 + i * 50, 0 + i * 25, 100, 100);
  }
}

效果如圖:

下面的代碼使用了八個(gè)參數(shù)的drawlmage方法將圖像的局部放大炭庙,并復(fù)制到畫布中另一個(gè)地方饲窿,該示例通常用來做圖像局部的特寫放大處理。

function draw(id) {   
  var canvas = document.getElementById(id);  
  if (canvas == null) { return false; }
  var context = canvas.getContext('2d');  
  context.fillStyle = "#EEEEFF";  
  context.fillRect(0, 0, 400, 300);  
  image = new Image(); 
  image.src = "tyl.jpg";  
  image.onload = function() {  
    drawImg(context, image);  
  };       
}  
function drawImg(context, image){  
  var i = 0;
  // 首先調(diào)用該方法繪制原始圖像
  context.drawImage(image, 0, 0, 100, 100); 
  // 繪制將局部區(qū)域進(jìn)行放大后的圖像
  context.drawImage(image, 23, 5, 57, 80, 110, 0, 100, 100);  
}

運(yùn)行效果如圖:

圖像平鋪

圖像平鋪就是用按一定比例縮小后的圖像將畫布填滿焕蹄,有兩種方法可以實(shí)現(xiàn)圖像平鋪逾雄,一種是使用drawImage方法。

function draw(id) {  
  var image = new Image();      
  var canvas = document.getElementById(id);  
  if (canvas == null) { return false; }   
  var context = canvas.getContext('2d'); 
  image.src = "tyl2.jpg"; 
  image.onload = function(){  
    drawImg(canvas, context, image);  
  };        
}  
function drawImg(canvas, context, image){  
  //平鋪比例
  var scale = 5;
  //縮小后圖像寬度
  var n1 = image.width / scale;
   //縮小后圖像高度
  var n2 = image.height / scale;
  //平鋪橫向個(gè)數(shù)
  var n3 = canvas.width / n1;
  //平鋪縱向個(gè)數(shù)
  var n4 = canvas.height / n2;
  for(var i = 0;i < n3;i++) {
    for(var j = 0;j < n4;j++) {
      context.drawImage(image, i * n1, j * n2, n1, n2);
    }
  }
}

運(yùn)行效果如圖:

在H5中腻脏,要達(dá)到平鋪效果鸦泳,還可以使用更簡便的圖形上下文對象的createPattern方法。

context.createPattern(image,type);

該方法使用兩個(gè)參數(shù)永品,image參數(shù)為要平鋪的圖像 做鹰,type參數(shù)的值必須是下面的字符串值之一:

  • no-repeat:不平鋪
  • repeat-x:橫方向平鋪
  • repeat-y:縱方 向平鋪
  • repeat:全方向平鋪

創(chuàng)建了lmage對象并指定圖像文件后,使用createPattern方法創(chuàng)建填充樣式腐碱,然后將該樣式指定繪圖形上下文對象的fillStyle屬性誊垢,最后再填充畫布,就可以看到重復(fù)填充的效果了症见。

function draw(id) {  
  var image = new Image();      
  var canvas = document.getElementById(id);  
  if (canvas == null) { return false; }   
  var context = canvas.getContext('2d'); 
  image.src = "tyl3.jpg"; 
  image.onload = function() {  
    //創(chuàng)建填充樣式喂走,全方向平鋪
    var ptrn = context.createPattern(image, 'repeat'); 
    //指定填充樣式
    context.fillStyle = ptrn;  
    //填充畫布
    context.fillRect(0,0,400,300);  
  };        
}

圖像裁剪

圖像裁剪功能是指在畫布內(nèi)使用路徑,只繪制該路徑所包括區(qū)域內(nèi)的圖像谋作,不繪制路徑外部的圖像芋肠。
使用圖形上下文對象的不帶參數(shù)的clip方法來實(shí)現(xiàn)Canvas元素的圖像裁剪功能。該方法使用路徑來對Canvas畫布設(shè)置一個(gè)裁剪區(qū)域遵蚜。因此帖池,必須先創(chuàng)建好路徑。路徑創(chuàng)建完成后吭净,調(diào)用clip方法設(shè)置裁剪區(qū)域睡汹。

function draw(id) {  
  var canvas = document.getElementById(id);
  if (canvas == null) { return false; }
  var context = canvas.getContext('2d');
  var gr = context.createLinearGradient(0, 400, 300, 0);
  gr.addColorStop(0, 'rgb(255, 255, 0)');
  gr.addColorStop(1, 'rgb(0, 255, 255)');
  context.fillStyle = gr;
  context.fillRect(0, 0, 400, 300);
  image = new Image();
  image.onload = function(){
    drawImg(context, image);
  };
  image.src = "tyl.jpg";  
}
function drawImg(context, image) {  
  create5StarClip(context);  
  context.drawImage(image, -50, -150, 300, 300);  
}  
function create5StarClip(context) {  
  var n = 0;  
  var dx = 100;  
  var dy = 0;  
  var s = 150;  
  context.beginPath();  
  context.translate(100, 150);  
  var x = Math.sin(0);  
  var y = Math.cos(0);  
  var dig = Math.PI / 5 * 4;  
  for(var i = 0; i < 5; i++) {  
    var x = Math.sin(i * dig);  
    var y = Math.cos(i * dig);  
      context.lineTo(dx + x * s, dy + y * s);  
    }  
    context.clip();  
}

運(yùn)行效果如圖:

在上面的代碼中,把畫布背景繪制完成后寂殉,調(diào)用create5StarClip函數(shù)囚巴。在函數(shù)中,創(chuàng)建一個(gè)五角星的路徑友扰,然后使用clip方法設(shè)置裁剪區(qū)域彤叉。
裁剪區(qū)域一旦設(shè)置好之后,后面繪制的所有圖形就都可以用這個(gè)裁剪區(qū)域村怪。如果要取消這個(gè)已經(jīng)設(shè)置好的裁剪區(qū)域秽浇,需要使用繪制狀態(tài)的保存與恢復(fù)功能。這兩個(gè)功能保存與恢復(fù)圖形上下文的臨時(shí)狀態(tài)甚负。在設(shè)置圖像裁剪區(qū)域時(shí)柬焕,首先調(diào)用save方法保存圖形上下文的當(dāng)前狀態(tài)审残,在繪制完經(jīng)過裁剪的圖像后,再調(diào)動restore恢復(fù)之前保存的圖形上下文的狀態(tài)击喂,通過這種方法维苔,對之后繪制的圖像取消裁剪區(qū)域。

function draw(id) {
  var canvas =document.getElementById(id);
  if(canvas == null) {return false; }
  var context = canvas.getContext('2d');
  var gr = context.createLinearGradient(0, 400, 300, 0);
  gr.addColorStop(0, 'rgb(255, 255, 0)');
  gr.addColorStop(1, 'rgb(0, 255, 255)');
  context.fillStyle = gr;
  context.fillRect(0, 0, 400, 300);
  image = new Image();
  image.onload = function() {
    drawImg(context, image);
  };
  image.src = 'tyl.jpg';
}
function drawImg(context, image) {
  create5StarClip(context);
  context.drawImage(image, -50, -150, 300, 300);
}
function create5StarClip(context) {
  var n = 0;
  var dx = 100;
  var dy = 0;
  var s = 150;
  context.beginPath();
  context.translate(100, 150);
  var x = Math.sin(0);
  var y = Math.cos(0);
  var dig = Math.PI / 5 * 4;
  for(var i = 0; i < 5; i++) {
    var x = Math.sin(i * dig);
    var y = Math.cos(i * dig);
    context.lineTo(dx + x * s, dy + y * s);
  }
  context.clip();
}

效果如圖:

像素處理

使用Canvas API能夠獲取圖像中的每一個(gè)像素懂昂,然后得到該像素顏色的rgb值或rgba值介时。使用圖形上下文對象的getImageData方法來獲取圖像中的像素。

var imageData = context.getImageData(sx, sy, sw, sh);

該方法使用四個(gè)參數(shù)凌彬,sx沸柔、sy分別表示所獲取區(qū)域的起點(diǎn)橫坐標(biāo)、起點(diǎn)縱坐標(biāo)铲敛,sw褐澎、sh分別表示所獲取區(qū)域的寬度和高度。
imagedata變量是一個(gè)CanvasPixelArray對象伐蒋,具有height工三,widthdata等屬性先鱼。data屬性是一個(gè)保存像素?cái)?shù)據(jù)的數(shù)組俭正,內(nèi)容類似[ r1, g1, b1, a1, r2, g2 ,b2, a2, r3, g3, b3, a3, ...],其中焙畔,r1掸读,g1b1宏多,a1為第一個(gè)像素的紅色值儿惫,綠色值,藍(lán)色值伸但,透明度值肾请;r2g2更胖,b2筐喳,a2分別為第二個(gè)像素的紅色值,綠色值函喉,藍(lán)色值,透明度值荣月,依此類推管呵。data.length為所取得像素的數(shù)量。

var image = new Image();
var context = canvas.getContext('2d'); 
image.onload = function () {
  context.drawImage(image, 0, 0);
  var imageData;
  context.drawImage(image, 0, 0);
  imageData = context.getImageData(0, 0, image.width, image.height);
}

取得了這些像素后哺窄,就可以對這些像素進(jìn)行處理了捐下,接下來可以進(jìn)行諸如蒙版處理账锹、面部識別等較復(fù)雜的圖像處理操作。
下面的代碼用Canvas API將圖像進(jìn)行了反顯操作坷襟。在得到像素?cái)?shù)組后奸柬,將該數(shù)組中的每個(gè)像素顏色進(jìn)行了反顯操作,然后保存回像素?cái)?shù)組婴程,最后使用圖形上下文對象的putImageData方法將反顯操作后的圖形重新繪制在畫布上廓奕。

context.putImageData(imageData, dx, dy[, dirtyX, dirtyY, dirtyWidth, dirtyHeight]);

該方法使用七個(gè)參數(shù),imageData為像素?cái)?shù)組档叔,dx桌粉、dy分別表示重繪圖像的起點(diǎn)橫坐標(biāo)、起點(diǎn)縱坐標(biāo)衙四。后面的四個(gè)參數(shù)為可選參數(shù)铃肯,給出一個(gè)矩形的起點(diǎn)橫坐標(biāo)、起點(diǎn)縱坐標(biāo)传蹈、寬度和高度押逼,如果加上后邊這四個(gè)參數(shù),則只繪制像素?cái)?shù)組中這個(gè)矩形范圍內(nèi)的圖像惦界。

function draw(id) {
  var canvas = document.getElementById(id);
  if (canvas == null) { return false; }
  var context = canvas.getContext('2d');
  var image = new Image();
  image.src = 'tyl.jpg';
  image.onload = function () {
    context.drawImage(image, 0, 0);
    var imageData = context.getImageData(0, 0, image.width, image.height);
    for(var i = 0,n = imageData.length; i < n; i += 4) {
      imageData.data[i + 0] = 255 - imageData.data[i + 0];  // red
      imageData.data[i + 1] = 255 - imageData.data[i + 1];  // green
      imageData.data[i + 2] = 255 - imageData.data[i + 2];  // blue
    }
    context.putImageData(imageData, 0, 0);
  }
}

對于像素操作只有部分瀏覽器支持挑格。

繪制文字

可以在Canvas畫布中進(jìn)行文字的繪制,同時(shí)也可以指定繪制文字的字體表锻、大小恕齐、對齊方式等,還可以進(jìn)行文字的紋理填充等瞬逊。
繪制文字時(shí)可以使用fillText方法或strokeText方法显歧。
fillText方法用填充方式繪制字符串。

void fillText(text,x,y,[maxWidth]); 

該方法接受四個(gè)參數(shù)确镊,第一個(gè)參數(shù)text表示要繪制的文字士骤,第二個(gè)參數(shù)x表示繪制文字的起點(diǎn)橫坐標(biāo),第三個(gè)參數(shù)y表示繪制文字的起點(diǎn)縱坐標(biāo)蕾域,第四個(gè)參數(shù)maxWidth為可選參數(shù)拷肌, 表示顯示文字時(shí)的最大寬度,可以防止文字溢出旨巷。
strokeText方法用輪廓方式繪制字符串巨缘。

void strokeText(text,x,y,[maxWidth]);

該方法參數(shù)部分的解釋與fillText方法相同。
在進(jìn)行文字的繪制之前采呐,可以先對該對象的有關(guān)文字繪制的屬性進(jìn)行設(shè)置:

  • font屬性:設(shè)置文字字體
  • textAlign屬性:設(shè)置文字水平對齊方式若锁,屬性值可以為start 、end斧吐、left又固、right仲器、center。默認(rèn)值為start
  • textBaseline屬性 : 設(shè)置文字垂直對齊方式仰冠,屬性值可以為top乏冀、hanging、middle洋只、alphabetic辆沦、ideographic、bottom木张。默認(rèn)值為alphabetic
function draw(id) {  
  var canvas = document.getElementById(id);  
  if (canvas == null) { return false; }
  var context = canvas.getContext('2d'); 
  context.fillStyle = '#00f';
  context.font = 'italic 30px sans-serif';
  context.textBaseline = 'top';
  //填充字符串
  context.fillText('示例文字', 0, 0);
  context.font = 'bold  30px sans-serif';
  //輪廓字符串
  context.strokeText('示例文字', 0, 50);
}

運(yùn)行效果:

在使用CSS樣式的時(shí)候众辨,有時(shí)我們會希望能在文字周圍制作一個(gè)漂亮的邊框,在定義邊框?qū)挾鹊臅r(shí)候舷礼,我們需要首先計(jì)算出在這個(gè)邊框里最長一行的文字的寬度鹃彻。這時(shí),我們可以使用圖形上下文對象的measureText方能來得到文字的寬度妻献。

metrics = context.measureText(text)

measureText方法接受一個(gè)參數(shù)text蛛株,該參數(shù)為需要繪制的文字,該方法返回一個(gè)TextMetrics對象育拨, TextMetrics對象的width屬性表示使用當(dāng)前指定的字體后text參數(shù)中指定的文字的總文字寬度谨履。

function draw(id) { 
  var canvas = document.getElementById(id);  
  if (canvas == null) { return false; }
  var context = canvas.getContext('2d'); 
  context.font = 'italic 20px sans-serif';
  /* 定義繪制文字*/
  var txt = "字符串的寬度為";
  /* 獲取文字寬度 */
  var tm1 = context.measureText(txt);
  /* 繪制文字 */
  context.fillText(txt, 10, 30);
  context.fillText(tm1.width, tm1.width + 10, 30);
  /* 改變字體 */
  context.font = "bold  30px sans-serif";
  /* 重新獲取文字寬度 */
  var tm2 = context.measureText(txt);
  /* 重新繪制文字*/
  context.fillText(txt, 10, 70);
  context.fillText(tm2.width, tm2.width + 10, 70);
}

效果如圖:

補(bǔ)充知識

保存與恢復(fù)狀態(tài)

saverestore這兩個(gè)方能均不帶參數(shù),分別保存與恢復(fù)圖形上下文的當(dāng)前繪畫狀態(tài)熬丧。在需要保存與恢復(fù)當(dāng)前狀態(tài)時(shí)笋粟,首先調(diào)用save方法將當(dāng)前狀態(tài)、保存到棧中析蝴,在做完想做的工作后害捕,再調(diào)用restore從棧中取出之前保存的圖形上下文的狀態(tài)進(jìn)行恢復(fù)。

var x, y;
for (var j = 1; j < 50; j++){
  ctx.save() ;
  // 改變繪畫狀態(tài)闷畸,進(jìn)行想要的操作
  ctx.fillStyle = '#fff';
  x = 75 - Math.floor(Math.random() * 150); 
  y = 75 - Math.floor(Math.random() * 150); 
  ctx.translate(x, y);
  drawStar(ctx, Math.floor(Math.random() * 4) + 2); 
  ctx.restore();
}

保存與恢復(fù)狀態(tài)可以應(yīng)用在以下場合:

  • 圖像或圖形變形
  • 圖像裁剪
  • 改變圖形上下文的以下屬性:fillStyle尝盼、font、lineWidth佑菩、shadowBlur盾沫、shadowColor、shadowOffsetX殿漠、shadowOffsetY赴精、textAlign、strokeStyle绞幌、textBaseline蕾哟、lineJoin、lineCap、miterLimit渐苏、globalAlpha、globalCompositeOperation菇夸。

保存文件

在畫布中繪制完成一幅圖形或圖像后琼富,很多時(shí)候我們需要將該圖形或圖像保存到文件中, 使用Canvas API可以完成這步工作庄新。
Canvas API保存文件的原理實(shí)際上是把當(dāng)前的繪畫狀態(tài)輸出到一個(gè)data URL地址所指向的數(shù)據(jù)中的過程鞠眉,所謂data URL, 是指目前大多數(shù)瀏覽器能夠識別的一種base64位編碼的URL择诈,主要用于小型的械蹋、可以在網(wǎng)頁中直接嵌入,而不需要從外部文件嵌入的數(shù)據(jù)羞芍,比如img元素中的圖像文件等哗戈。data URL的格式類似于data:image/png;base64,iVBORdfoAAA...
Canvas API使用toDataURL方法把繪畫狀態(tài)輸出到一個(gè)data URL中荷科,然后重新裝載唯咬,客戶可直接把裝載后的文件進(jìn)行保存。

canvas.toDataURL(type);

參數(shù)type表示要輸出數(shù)據(jù)的MIME類型畏浆。

function draw(id) {  
  var canvas = document.getElementById(id);  
  if (canvas == null) { return false; }
  var context = canvas.getContext('2d'); 
  context.fillStyle = "rgb(0, 0, 255)";
  context.fillRect(0, 0, canvas.width, canvas.height);
  context.fillStyle = "rgb(255, 255, 0)";
  context.fillRect(10, 20, 50, 50); 
  window.location = canvas.toDataURL("image/jpeg");     
}

效果如圖:

簡單動畫的制作

在Canvas 中制作動面實(shí)際上就是一個(gè)不斷擦除胆胰、重繪、擦除刻获、 重繪的過程蜀涨,具體步驟如下 :

  • 預(yù)先編寫好用來繪圖的函數(shù),在該函數(shù)中先用clearRect方法將畫布整體或局部擦除蝎毡。
  • 使用setInterval方法設(shè)置動畫的間隔時(shí)間厚柳。
var context;
var width,height;
var i;
function draw(id) {
  var canvas = document.getElementById(id);  
  if (canvas == null) { return false; }
  context = canvas.getContext('2d'); 
  width = canvas.width;
  height = canvas.height;
  i = 0;
  setInterval(rotate, 100);
}
function rotate() {   
  context.clearRect(0, 0, width, height);
  context.fillStyle = "red";
  context.fillRect(i, 0, 20, 20);
  i = i + 20;
}

上面的代碼將繪制一個(gè)紅色小方塊,使其在畫布中從左向右緩慢移動顶掉。
效果如圖:

下面的代碼給出一個(gè)通過動畫來循環(huán)顯示所有參數(shù)組合效果草娜。

var globalId;
var i = 0;
function draw(id) {
  globalId = id;
  setInterval(Composite, 1000);
}
function Composite() {  
  var canvas = document.getElementById(globalId);  
  if (canvas == null) { return false; }
  var context = canvas.getContext('2d'); 
  var oprtns = new Array(
    "source-atop",
    "source-in",
    "source-out",
    "source-over",
    "destination-atop",
    "destination-in",
    "destination-out",
    "destination-over",
    "lighter",
    "copy",
    "xor"
    );
  if(i > 10) { i=0; }
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.save();
  //繪制原有圖形(藍(lán)色長方形)
  context.fillStyle = "blue";
  context.fillRect(10, 10, 60, 60);
  //設(shè)置組合方式 
  context.globalCompositeOperation = oprtns[i];
  //設(shè)置新圖形(紅色圓形)
  context.beginPath();
  context.fillStyle = "red";
  context.arc(60, 60, 30, 0, Math.PI * 2, false);
  context.fill();
  context.restore();
  i = i + 1;
}

效果如圖:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市痒筒,隨后出現(xiàn)的幾起案子宰闰,更是在濱河造成了極大的恐慌,老刑警劉巖簿透,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件移袍,死亡現(xiàn)場離奇詭異,居然都是意外死亡老充,警方通過查閱死者的電腦和手機(jī)葡盗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啡浊,“玉大人觅够,你說我怎么就攤上這事胶背。” “怎么了喘先?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵钳吟,是天一觀的道長。 經(jīng)常有香客問我窘拯,道長红且,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任涤姊,我火速辦了婚禮暇番,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘思喊。我一直安慰自己壁酬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布搔涝。 她就那樣靜靜地躺著厨喂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪庄呈。 梳的紋絲不亂的頭發(fā)上蜕煌,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機(jī)與錄音诬留,去河邊找鬼斜纪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛文兑,可吹牛的內(nèi)容都是我干的盒刚。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼绿贞,長吁一口氣:“原來是場噩夢啊……” “哼因块!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起籍铁,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤涡上,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拒名,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吩愧,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年增显,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雁佳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖糖权,靈堂內(nèi)的尸體忽然破棺而出堵腹,到底是詐尸還是另有隱情,我是刑警寧澤星澳,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布秸滴,位于F島的核電站,受9級特大地震影響募判,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜咒唆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一届垫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧全释,春花似錦装处、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至李命,卻和暖如春登淘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背封字。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工黔州, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人阔籽。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓流妻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親笆制。 傳聞我的和親對象是個(gè)殘疾皇子绅这,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • ??HTML5 添加的最受歡迎的功能就是 元素证薇。這個(gè)元素負(fù)責(zé)在頁面中設(shè)定一個(gè)區(qū)域,然后就可以通過 JavaScri...
    霜天曉閱讀 2,993評論 0 2
  • canvas基本標(biāo)簽 < /canvas>寬高寫在內(nèi)部跟樣式有區(qū)別的(樣式設(shè)置-畫出的圖形寬高改變开缎,內(nèi)部設(shè)置-畫出...
    閆子揚(yáng)閱讀 450評論 0 0
  • --繪圖與濾鏡全面解析 概述 在iOS中可以很容易的開發(fā)出絢麗的界面效果棕叫,一方面得益于成功系統(tǒng)的設(shè)計(jì),另一方面得益...
    韓七夏閱讀 2,710評論 2 10
  • 晚上在為班級整理信息表格時(shí)奕删,剛上高一的妹妹冷不丁發(fā)了張截圖給我俺泣,是她在QQ空間在她自己的留言板留了言,內(nèi)容是她...
    小肥肥肉圓閱讀 718評論 0 2
  • 大部分時(shí)候都談不少收獲,只是經(jīng)歷過后伏钠,發(fā)現(xiàn)原來自己還這樣生活過横漏。 一個(gè)和我一樣喜歡看玄幻小說的朋友發(fā)問,你說我和你...
    你的眼睛好大閱讀 504評論 0 0