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í)贫悄,一般會用到moveTo
與lineTo
兩種方法瑞驱。
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册倒。
接著把fillStyle
或strokeStyle
設(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
竟趾,m21
,m12
宫峦,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
钦购、scale
和rotate
這三個(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
對象,用該對象來裝載圖像文件籍凝。 x
和y
為繪制時(shí)該圖像在畫布中的起始坐標(biāo)周瞎。
第二種方法中前三個(gè)參數(shù)與第一種方法中的使用方法一樣,w
饵蒂、h
是指繪制時(shí)的圖像的寬度與高度声诸。第一種方法中省略了這兩個(gè)參數(shù),所以繪制出來的圖像與原圖大小相同退盯,而第二種方法可以用來進(jìn)行圖像縮放 彼乌。
第三種方法可以用來將畫布中已繪制好的圖像的全部或者局部區(qū)域復(fù)制到畫布中的另一個(gè)位置上。該方法使用九個(gè)參數(shù)渊迁,image
代表被復(fù)制的圖像文件慰照,sx
與sy
分別表示源圖像的被復(fù)制區(qū)域在畫布中的起始橫坐標(biāo)與起始縱坐標(biāo),sw
與sh
表示被復(fù)制區(qū)域的寬度與高度琉朽,dx
與dy
表示復(fù)制后的目標(biāo)圖像在畫布中的起始橫坐標(biāo)與起始縱坐標(biāo)毒租,dw
與dh
表示復(fù)制后的目標(biāo)圖像的寬度與高度。該方法可以只復(fù)制圖像的局部箱叁,只要將sx
與sy
設(shè)為局部區(qū)域的起始點(diǎn)坐標(biāo)蝌衔, 將sw
與sh
設(shè)為局部區(qū)域的寬度與高度就可以了。該方能也可以用來將源圖像進(jìn)行縮放,只要將dw
與dh
設(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
工三,width
,data
等屬性先鱼。data
屬性是一個(gè)保存像素?cái)?shù)據(jù)的數(shù)組俭正,內(nèi)容類似[ r1, g1, b1, a1, r2, g2 ,b2, a2, r3, g3, b3, a3, ...]
,其中焙畔,r1掸读,
g1,
b1宏多,a1
為第一個(gè)像素的紅色值儿惫,綠色值,藍(lán)色值伸但,透明度值肾请;r2
,g2
更胖,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)
save
與restore
這兩個(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;
}
效果如圖: