參考資料
前言
本人菜鳥坟募,入IT只為當(dāng)鼓勵師背亥。本編文章旨在總結(jié)《Javascript高級層序設(shè)計(第3版)》一書中第15章canvas的一些api拨扶。第(一)篇只總結(jié)2D上下文糊余。
一焊唬、<canvan>元素
出處:HTML5坟岔。
用途:設(shè)定一個區(qū)域,通過JS動態(tài)地在區(qū)域上繪制圖形独令。
組成:由幾組API構(gòu)成端朵,可分為 2D上下文(基本繪圖能力) 和 3D上下文(WebGL)。
兼容性:
- 瀏覽器:IE9+燃箭、Firefox1.5+冲呢、Safari2+、Opera9+招狸、Chrome敬拓、IOS版Safari、Android版WebKit裙戏。
- 操作系統(tǒng):Windows XP因缺少必要的繪圖程序乘凸,不管用什么瀏覽器都不支持。
二累榜、基本用法
1. 建立區(qū)域
要使用<canvas>元素营勤,必須設(shè)置width和height屬性,指定可以繪圖的區(qū)域大小壹罚。設(shè)置完后葛作,如果瀏覽器兼容<canvas>標(biāo)簽,則建立的區(qū)域應(yīng)是空白的猖凛;否則赂蠢,會顯示其中的文本:A drawing of something。
<canvas id="drawing" width="200" height="200">A drawing of something</canvas>
2. 取得繪圖上下文(<canvas>元素的DOM對象)
要在這塊畫布上繪圖辨泳,需要取得繪圖上下文虱岂。繪圖上下文也就是取得相應(yīng)<canvas>元素的DOM對象玖院。
// 取得DOM對象呻疹,也為canvas對象
var drawing = document.getElementById("drawing");
3. 取得2D上下文對象 getContext("2d")
只取得DOM對象還不行先舷,還要調(diào)用<canvas>DOM對象擁有的 getContext(param)
方法。其中傳入?yún)?shù)為一個字符串俩功,因為本篇文章總結(jié)的是2D上下文(平面)绍傲,故傳入"2d",獲得2D上下文對象耍共。后面一切關(guān)于繪圖的方法和屬性烫饼,其實都是圍繞著2D上下文對象開展的,也就是代碼示例中的context试读。
method | param | return |
---|---|---|
getContext(param) | 上下文對象的類型杠纵,有如下選擇:</br>"2d"(2d上下文)</br>"3d"(3d上下文) | 上下文對象 |
在調(diào)用該方法之前,為了保證程序的健壯性钩骇,最好加入檢測代碼比藻。
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
// 取得2D上下文對象
var context = drawing.getContext("2d");
// 更多代碼
}
4. 導(dǎo)出在<canvas>元素上繪制的圖像
當(dāng)在<canvas>元素上繪制完圖像后,可以調(diào)用DOM對象的 toDataURL(param)
方法倘屹,將該圖像導(dǎo)出成為一張圖片银亲,傳入?yún)?shù)為欲導(dǎo)出圖片的MIME類型,例如:image/png
纽匙、image/jpeg
等等务蝠。擁有該方法的對象是<canvas>元素的DOM對象,并不是2d上下文對象context烛缔,兩者要區(qū)分開來馏段。
method | param | return | compatibility |
---|---|---|---|
toDataURL(param) | 圖像的MIME類型格式,有如下選擇:</br>"image/jpeg"(Firefox和Opera默認(rèn))</br>"image/png"(其他默認(rèn)) | 圖像的數(shù)據(jù)URI | IE9+践瓷、Firefox3.5+ 院喜、Opera10 |
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
// 取得圖像的數(shù)據(jù)URI
var imgURI = drawing.toDataURI("image/png");
// 顯示圖像
var image = document.createElement("img");
image.src = imgURI;
document.body.appendChild(image);
}
三、2D上下文 context
(0, 0)為<canvas>元素所占區(qū)域的原點坐標(biāo)晕翠,x向右遞增喷舀,y向下遞增
1. 填充和描邊
attribute | value | effect |
---|---|---|
fillStyle | String類型:顏色名、十六進(jìn)制碼崖面、rgb等元咙,如"#0000ff" | 設(shè)置填充顏色 |
strokeStyle | String類型:顏色名、十六進(jìn)制碼巫员、rgb等庶香,如"red" | 設(shè)置描邊顏色 |
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 以紅色描邊
context.strokeStyle = "red";
// 以藍(lán)色填充
context.fillStyle = "#0000ff";
// 繪制描邊矩形
context.strokeRect(10, 10, 50, 50);
// 繪制填充矩形 context.fillRect
(65, 10, 50, 50);
}
2. 繪制矩形
2.1 填充矩形
method | param | effect |
---|---|---|
fillRect(param1,param2, param3,param4) | param1:矩形的x坐標(biāo)</br>param2:矩形的y坐標(biāo)</br>param3:矩形的寬度</br>param4:矩形的高度 | 繪制填充矩形,默認(rèn)為黑色简识,可給fillStyle賦值改變其填充顏色 |
// 填充
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 以紅色填充
context.fillStyle = "#ff0000";
// 繪制填充矩形
context.fillRect(10, 10, 50, 50);
// 以半透明的藍(lán)色填充
context.fillStyle = "rgba(0, 0, 255, 0.5)";
// 繪制填充矩形
context.fillRect(30, 30, 50, 50);
}
2.2 描邊矩形
method | param | effect |
---|---|---|
strokeRect(param1, param2, param3, param4) | param1:矩形的x坐標(biāo)</br>param2:矩形的y坐標(biāo)</br>param3:矩形的寬度</br>param4:矩形的高度 | 繪制描邊矩形赶掖,默認(rèn)為黑色感猛,可給strokeStyle賦值改變其邊框顏色 |
// 描邊
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 以紅色描邊
context.strokeStyle = "#ff0000";
// 繪制描邊矩形
context.strokeRect(10, 10, 50, 50);
// 以藍(lán)色描邊
context.strokeStyle = "rgba(0, 0, 255, 0.5)";
// 繪制描邊矩形 context.strokeRect(30, 30, 50, 50);
}
2.3 清除矩形
method | param | effect |
---|---|---|
clearRect(param1, param2, param3, param4) | param1:矩形的x坐標(biāo)</br>param2:矩形的y坐標(biāo)</br>param3:矩形的寬度</br>param4:矩形的高度 | 清除一塊矩形區(qū)域 |
// 清除矩形區(qū)域
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 繪制紅色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
// 繪制半透明的藍(lán)色矩形
context.fillStyle = "rgba(0, 0, 255, 0.5)";
context.fillRect(30, 30, 50, 50);
// 在兩個矩形重疊的地方清楚一個小矩形
context.clearRect(40, 40, 10, 10);
}
3. 繪制路徑
3.1 創(chuàng)建路徑
method | param | effect |
---|---|---|
arc(x,y,radius,startAngle,counterclockwise) | (x, y):圓心的坐標(biāo)</br>radius:弧線半徑</br>startAngle:起始角度</br>endAngle:結(jié)束角度</br>counterclockwise:角度的方向(true:逆時針方向,false:順時針方向 | 給定圓心(x,y)和半徑radius奢赂、起始和結(jié)束的角度陪白、方向,繪制一條弧線 |
arcTo(x1,y1,x2,y2,radius) | (x1, y1):需穿過的點的坐標(biāo)</br>(x2, y2):終點坐標(biāo)</br>radius:以給定的半徑穿過(x1, y1) | 從上一點繪制一條弧線膳灶,到(x2,y2)為止咱士,并且以給定的半徑穿過(x1, y1) |
bezierCurveTo(c1x,c1y,c2x,c2y,x,y) | (c1x,c1y):控制點</br>(c2x,c2y):另一個控制點</br>(x, y):終點坐標(biāo) | 從上一點繪制一條弧線,到(x,y)為止轧钓,并且以(c1x,c1y)和(c2x,c2y)為控制點 |
lineTo(x,y) | (x,y):終點坐標(biāo) | 從上一點開始繪制一條直線序厉,到(x,y)為止 |
moveTo(x,y) | (x,y):繪圖游標(biāo)移動到的點的坐標(biāo) | 將繪圖游標(biāo)移動到(x,y),不畫線 |
quadraticCurveTo(cx,cy,x,y) | (cx,cy):控制點</br>(x,y):終點坐標(biāo) | 從上一點開始繪制一條二次曲線毕箍,到(x,y)為止弛房,并且以(cx,cy)為控制點 |
rect(x,y,width,height) | (x,y):起點坐標(biāo)</br>width:矩形的寬</br>height:矩形的高 | 從點(x,y)開始繪制一個矩形,寬高分別為width和height而柑。這個方法繪制的是矩形路徑文捶,而不是strokeRect()和fillRect()所繪制的獨立形狀 |
3.2 處理路徑
method | param | effect |
---|---|---|
beginPath() | null | 開始創(chuàng)建路徑 |
closePath() | null | 關(guān)閉路徑,回到起點 |
fill() | null | 用fillStyle來填充路徑 |
stroke() | null | 用strokeStyle來對路徑描邊 |
clip() | null | 在路徑上創(chuàng)建一個剪切區(qū)域 |
3.2.1 用上面某些方法描繪一個時鐘
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 開始路徑
context.beginPath();
// 繪制外圓
context.arc(100, 100, 99, 0, 2*Math.PI, false);
// 繪制內(nèi)圓
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2*Math.PI, false);
// 繪制分針
context.moveTo(100, 100);
context.lineTo(100, 15);
// 繪制時針
context.moveTo(100, 100);
context.lineTo(35, 100);
// 為路徑描邊
context.stroke();
}
3.2.2 用fill()方法填充路徑
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 開始路徑
context.beginPath();
// 繪制圓
context.arc(100, 100, 99, 0, 2*Math.PI, false);
// 填充路徑
context.fill();
}
3.2.3 當(dāng)路徑不閉合時fill()方法無效
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 繪制一條對角線
context.moveTo(0, 0);
context.lineTo(200, 200);
// 填充路徑
context.fill();
}
3.3 判斷路徑點
method | param | effect |
---|---|---|
isPointInPath(x,y) | (x,y):某一任意點的坐標(biāo) | 在路徑被關(guān)閉前確定判斷畫布上的點(x,y)是否在路徑上 |
4. 繪制文本
4.1 2d上下文的文本屬性
attribute | value | effect |
---|---|---|
font | String類型媒咳,如"bold 14px Arial" | 字體粗細(xì)粹排、大小和樣式 |
textAlign | String類型,有如下選擇:</br>"start"(x坐標(biāo)表示文本左端)伟葫,"center"(正中)恨搓,"end"(右端) | 文本的水平對齊方式 |
textBaseline | String類型,有如下選擇:</br>"top"(y坐標(biāo)表示文本頂端)筏养,"middle"(正中)斧抱,"bottom"(底端),"hanging"渐溶、"alphabetic"辉浦、"ideographic"(y坐標(biāo)指向特定基線坐標(biāo)) | 文本的垂直對齊方式 |
其實,fillText()和strokeText()方法都可以接受第四個參數(shù)茎辐,表示文本的最大像素寬度宪郊,如果傳入字符串大于最大寬度,會收縮以適應(yīng)最大寬度拖陆。但這個可選參數(shù)尚未得到大多數(shù)瀏覽器的支持弛槐。
4.2 用fillText()繪制數(shù)字12
method | param | effect |
---|---|---|
fillText(string,x,y) | string:要繪制的文本字符串</br>x:x坐標(biāo)可選的最大像素寬度</br>y:y坐標(biāo)可選的最大像素寬度 | 使用fillStyle屬性繪制文本 |
strokeText(string,x,y) | string:要繪制的文本字符串</br>x:x坐標(biāo)可選的最大像素寬度</br>y:y坐標(biāo)可選的最大像素寬度 | 使用strokeStyle屬性為文本描邊 |
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 開始路徑
context.beginPath();
// 繪制外圓
context.arc(100, 100, 99, 0, 2*Math.PI, false);
// 繪制內(nèi)圓
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2*Math.PI, false);
// 繪制分針
context.moveTo(100, 100);
context.lineTo(100, 15);
// 繪制時針
context.moveTo(100, 100);
context.lineTo(35, 100);
// 為路徑描邊
context.stroke();
// 繪制數(shù)字12
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);
}
</br>
4.3 給定寬度的區(qū)域,找到文本合適的字體大小
method | param | return | effect |
---|---|---|---|
mearsureText(string) | string類型:要確定大小的文本字符串 | object:返回一個對象依啰,該對象只有一個width屬性 | 獲得存有文本大小的對象 |
var fontSize = 100,
context.font = fontSize + "px Arial";
if (context.measureText) {
while(context.measureText("Hello world!").width > 140) {
fontSize--;
context.font = fontSize + "px Arial";
}
}
context.fillText("Hello world!", 10, 10);
context.fillText("Font size is " + fontSize + "px", 10, 50);
上面的代碼從100像素的字體大小開始遞減乎串,最終會找到合適的字體大小,在一個140像素的矩形區(qū)域中繪制文本 Hello world!
5. 變換
5.1 用translate()方法變換原點位置
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if (drawing.getContext) {
var context = drawing.getContext("2d");
// 開始路徑
context.beginPath();
// 繪制外圓
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
// 繪制內(nèi)圓
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
// 變換原點
context.translate(100, 100);
// 繪制分針
context.moveTo(0,0);
context.lineTo(0, -85);
// 繪制時針
context.moveTo(0, 0);
context.lineTo(-65, 0);
// 繪制路徑
context.stroke();
}
可以看出結(jié)果與3.2.1的圖形相同速警,但把原點變換到時鐘表盤中心點(100, 100)后叹誉,在同一方向上繪制線條的數(shù)學(xué)計算就變得簡單起來了鸯两。
5.2 用rotate()方法旋轉(zhuǎn)表針
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if (drawing.getContext) {
var context = drawing.getContext("2d");
// 開始路徑
context.beginPath();
// 繪制外圓
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
// 繪制內(nèi)圓
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
// 變換原點
context.translate(100, 100);
// 繪制分針
context.moveTo(0,0);
context.lineTo(0, -85);
// 繪制時針
context.moveTo(0, 0);
context.lineTo(-65, 0);
// 旋轉(zhuǎn)表針,旋轉(zhuǎn)弧度值為1长豁,2π對應(yīng)360°钧唐,則1對應(yīng)(360/2π)°,約為57.30°
context.rotate(1);
// 繪制路徑
context.stroke();
}
圖中紅色的部分不存在匠襟,是我做給大家的提示和比較而已钝侠,用來指明不加最后一句代碼的指針原來的位置。
5.3 跟蹤上下文的狀態(tài)變化
棧:先進(jìn)后出酸舍。
method | param | effect |
---|---|---|
save() | null | 當(dāng)下所有設(shè)置都會進(jìn)入一個棧結(jié)構(gòu) |
restore() | null | 在保存設(shè)置的棧結(jié)構(gòu)中向前返回一級 |
var drawing = document.getElementById("drawing");
// 確定瀏覽器支持<canvas>元素
if (drawing.getContext) {
var context = drawing.getContext("2d");
context.fillStyle = "#ff0000";
context.save();
context.fillStyle = "#00ff00";
context.translate(100, 100);
context.save();
context.fillStyle = "#0000ff";
//從點(100,100)開始繪制藍(lán)色矩形
context.fillRect(0,0,100,200);
context.restore();
//從點(110,110)開始繪制綠色矩形
context.fillRect(10,10,100,200);
context.restore();
//從點(0, 0)開始繪制紅色矩形
context.fillRect(0,0,100,200);
}
6. 繪制圖像
把一幅圖像繪制到畫布上机错,可以使用drawImage()方法。
method | param | effect |
---|---|---|
drawImage(image,</br>tx,ty) | image:要繪制的圖像</br>tx:目標(biāo)圖像的x坐標(biāo)</br>ty:目標(biāo)圖像的y坐標(biāo) | 把圖像繪制到畫布上父腕,起點坐標(biāo)為(tx,ty) |
drawImage(image,</br>tx,ty,twidth,theight) | image:要繪制的圖像</br>tx:目標(biāo)圖像的x坐標(biāo)</br>ty:目標(biāo)圖像的y坐標(biāo)</br>twidth:目標(biāo)圖像的寬度</br>theight:目標(biāo)圖像的高度 | 把圖像繪制到畫布上,起點坐標(biāo)為(tx,ty),繪制到畫布上的圖像的寬度為twidth青瀑,高度為theight |
drawImage(image,</br>sx,sy,swidth,sheight,</br>tx,ty,twidth,theight) | image:要繪制的圖像</br>sx:源圖像的x坐標(biāo)</br>sy:源圖像的y坐標(biāo)</br>swidth:源圖像的寬度</br>sheight:源圖像的高度</br>tx:目標(biāo)圖像的x坐標(biāo)</br>ty:目標(biāo)圖像的y坐標(biāo)</br>twidth:目標(biāo)圖像的寬度</br>theight:目標(biāo)圖像的高度 | 先對源圖像做一些處理璧亮,該處理為:以(sx,sy)為起點截取寬度為swidth斥难,高度為sheight的新圖像枝嘶。處理后再把新圖像繪制到畫布上,起點坐標(biāo)為(tx,ty),繪制到畫布上的新圖像的寬度為twidth哑诊,高度為theight |
7. 陰影
attribute | value | effect |
---|---|---|
shadowColor | String類型:顏色名群扶、十六進(jìn)制碼、rgb等镀裤,如"#0000ff"竞阐,默認(rèn)為黑色 | 用CSS顏色格式表示的陰影顏色 |
shadowOffsetX | Number類型,默認(rèn)為0 | 形狀或路徑x軸方向的陰影偏移量 |
shadowOffsetY | Number類型暑劝,默認(rèn)為0 | 形狀或路徑y(tǒng)軸方向的陰影偏移量 |
shadowBlur | Number類型骆莹,默認(rèn)為0,即不模糊 | 模糊的像素數(shù) |
8. 漸變
method | param | return |
---|---|---|
createLinearGradient | 起點的x坐標(biāo)</br>起點的y坐標(biāo)</br>終點的x坐標(biāo)</br>終點的y坐標(biāo) | 返回CanvasGradient對象的實例 |