紅書第十五章 Canvas

??????HTML5新增了canvas叉庐,它跟瀏覽器提供的其它組件一樣疯攒,是由幾組API構(gòu)成,并且各瀏覽器支持得有所差別澡罚。
??????除了2D上下文伸但,canvas還建議了名為webGL的3D上下文。

1. 基本用法

??????canvas元素使用前留搔,要先設(shè)置width和height更胖,指定繪圖區(qū)域的大小。也可以用js修改隔显、設(shè)置其對應(yīng)的DOM對象的width和height屬性却妨。也可用CSS設(shè)置其樣式∪僭拢總之管呵,要明確指定繪圖區(qū)域。
??????然后要取得canvas的繪圖上下文哺窄,canvas元素.getContext('2d')
??????調(diào)用toDataURL方法可以導(dǎo)出canvas元素上的圖像捐下,此方法需要傳入?yún)?shù)指定格式(MIME類型格式)账锹。

2. 2D上下文

??????2D上下文提供了一些方法繪制2D圖形。2D上下文的坐標(biāo)始于canvas元素左上角坷襟,x軸方向水平向右奸柬,y軸方向垂直向下。

2.1 填充和描邊

??????2D上下文的兩種基本操作是填充和描邊婴程。
??????2D上下文有兩個屬性廓奕,fillStyle和strokeStyle,默認值都是#000000档叔,可以把它們修改成表示顏色的字符串桌粉,也可以設(shè)為漸變對象或模式對象。填充操作和描邊操作將使用對應(yīng)的style來繪制衙四。

2.2 繪制矩形

??????fillRect方法在指定矩形區(qū)域內(nèi)填充铃肯。
??????strokeRect給指定矩形區(qū)域描邊。
??????clearRect可以把上下文中的一塊矩形區(qū)域變透明传蹈。這個方法可以用來“切”出各種有趣的形狀押逼。
??????小tip:描邊的線條寬度由lineWidth控制,線條末端的形狀(butt平頭/round圓頭/square方頭)由lineCap控制惦界,線條相交的方式(round圓交/bevel斜交/miter斜接)由lineJoin控制挑格。

2.3 繪制路徑

??????開始繪制路徑前,先調(diào)用上下文的beginPath方法沾歪。然后一段一段地畫漂彤,畫的時候可能用到以下方法:arc、arcTo灾搏、bezierCurveTo显歧、lineTo、moveTo确镊、quadraticCurveTo、rect范删。
??????畫了若干段以后蕾域,可以調(diào)用closePath閉合曲線。
??????路徑畫完了可以用fill方法填充圖形到旦,也可以用stroke方法對路徑描邊旨巷。
??????還可以調(diào)用clip在路徑上創(chuàng)建一個剪切區(qū)域。
??????關(guān)于路徑還有個方法添忘,isPointInPath采呐,判斷一個點是否在路徑上。

2.4 繪制文本

??????繪制文本的方法:filText和strokeText搁骑,接受參數(shù):字符串斧吐、x坐標(biāo)又固、y坐標(biāo)、最大像素寬度(可選)
??????繪制文本時煤率,還受上下文這些設(shè)置的影響:font仰冠、textAlign(設(shè)為start時x坐標(biāo)表示文本起點;設(shè)為center時x坐標(biāo)表示文本水平中點蝶糯;設(shè)為end時x坐標(biāo)表示文本終點)洋只、textBaseline(設(shè)為top時,y坐標(biāo)表示文本頂端昼捍;設(shè)為middle時识虚,y坐標(biāo)表示文本垂直中點;設(shè)為bottom時妒茬,y坐標(biāo)表示文本底端担锤,此外還有hanging、alphabetic郊闯、ideographic等值可選)
??????此外妻献,fillText受fillStyle設(shè)置的影響,strokeText受strokeStyle設(shè)置的影響团赁。
??????為了幫助開發(fā)者將文字繪制在特定區(qū)域育拨,2D上下文提供一個方法measureText,傳入要繪制的文本欢摄,它會返回一個TextMetrics對象熬丧,給出文本度量信息。

2.5 變換

??????2D上下文可以設(shè)置各種變換怀挠。
??????不設(shè)置2D上下文變換時析蝴,上下文保持一個默認的變換矩陣,如果設(shè)置了上下文變化绿淋,矩陣就會變化闷畸,繪制結(jié)果就會不同。
??????設(shè)置上下文變換的方法有:
????????????rotate 圍繞原點旋轉(zhuǎn)一個角度
????????????scale 縮放吞滞,在x方向上乘scaleX佑菩,在y方向上成scaleY
????????????translate 把坐標(biāo)原點移到指定坐標(biāo)
????????????transform 直接修改矩陣,原矩陣會乘以由參數(shù)構(gòu)成的新矩陣

??????對上下文做的設(shè)置會一直生效裁赠,如果知道自己需要倒回早先的設(shè)置殿漠,可以用save方法,調(diào)用save方法可以生成一張上下文的快照佩捞,并且快照會被保存在一個棧中绞幌。調(diào)用restore方法可以返回到上次save時的設(shè)置,多次調(diào)用restore可以返回到更早時的設(shè)置一忱。

2.6 繪制圖像

??????可以把DOM文檔里的img元素內(nèi)容繪制到canvas中去莲蜘。
??????比如:context.drawImage(document.images[0],10,10)把文檔中的圖形繪制到指定坐標(biāo)
??????這個方法還可以多傳參數(shù)谭确,指定繪制出的圖形的大小,進行縮放菇夸,還能指定截取源圖像的一個區(qū)域琼富,僅將區(qū)域內(nèi)圖像繪制到canvas中。
??????除了用DOM文檔里的img元素庄新,還可以傳入另一個canvas元素作為源圖像鞠眉。
??????圖源有個限制,不能來自其它域择诈,使用其它域的圖源執(zhí)行drawImage會報錯械蹋。

2.7 陰影

??????上下文可以設(shè)置這些屬性:shadowColor、shadowOffsetX羞芍、shadowOffsetY哗戈、shadowBlur,只要在繪制前調(diào)好需要的值荷科,可以在畫路徑或形狀時加上陰影唯咬。

2.8 漸變

??????通過2D上下文可以創(chuàng)建、修改CanvasGradient實例畏浆,創(chuàng)建好漸變對象以后胆胰,把fillStyle或strokeStyle設(shè)置為這個漸變對象,然后再填充圖形或者描邊刻获,就能有漸變效果蜀涨。

2.9 模式

??????模式可以在填充和描邊時,填上重復(fù)的圖像蝎毡。創(chuàng)建模式的方法:createPattern厚柳,
createPattern第一個參數(shù)是HTML的img或video或canvas元素,表示重復(fù)的內(nèi)容沐兵;第二個參數(shù)是個字符串表示重復(fù)的方式别垮,取值為repeat/repeat-x/repeat-y/no-repeat

2.10 使用圖像數(shù)據(jù)

??????調(diào)用2D上下文getImageData可以獲得canvas的圖像數(shù)據(jù),getImageData方法接受四個參數(shù)扎谎,指定要獲取的區(qū)域的起始坐標(biāo)宰闰,以及區(qū)域的寬高。
??????返回的是一個ImageData對象簿透,ImageData對象有3個屬性:寬,高解藻,像素數(shù)據(jù)數(shù)組老充。每一個像素用數(shù)組中的四個元素來表示,像素x的數(shù)據(jù)就保存在data[x*4]螟左、data[x*4+1]data[x*4+2]data[x*4+3]中捧请。4個元素分別表示紅藍綠值和透明度丹壕。
??????所以可以用getImageData方法獲取到圖像原始數(shù)據(jù)并做修改,再用putImageData方法把數(shù)據(jù)寫回去午阵,就能搞灰度處理等各種圖片處理了。

2.11 合成

??????上下文屬性globalAlpha,用于設(shè)置所有繪制的透明度窘拯,默認值為0,如果把它改了坝茎,接下來所有的繪制都會以設(shè)置的透明度值來畫涤姊。
??????2D上下文屬性globalCompositionOperation,用于設(shè)置后繪制的圖形與先繪制的圖形怎么重合嗤放,默認是后繪制的蓋在先繪制的上面思喊。但可以設(shè)置成各種其它值,呈現(xiàn)許多奇特的效果次酌。這里就不抄了恨课。

3. WebGL

??????webGL是針對canvas的3D上下文,它是基于OpenGL ES 2.0標(biāo)準(zhǔn)設(shè)計的岳服,所以接下來介紹WebGL的時候會牽扯到一些OpenGL的內(nèi)容剂公。

3.1 類型化數(shù)組

??????由于JavaScript的數(shù)據(jù)類型不能滿足3D計算的要求,所以WebGL引入了一個概念:類型化數(shù)組派阱。就是一個叫ArrayBuffer的數(shù)據(jù)類型诬留,創(chuàng)建時,指定字節(jié)長度贫母,就會得到一塊內(nèi)存文兑。
例:var buffer = new ArrayBuffer(20); var len = buffer.byteLength; // len等于20
視圖
??????DataView可以讀取ArrayBuffer上面的某一段(創(chuàng)建它的時候給它傳入ArrayBuffer實例,并指定偏移量和長度)腺劣,然后可以調(diào)用DataView的一些get和set方法绿贞,就可以在DataView所管理的那一段上面以各種(有/無符號)(整/浮點數(shù))(8/16/32/64位)格式讀寫數(shù)據(jù)。
??????這些get和set方法也可以傳入偏移量橘原,但我想此時的偏移量應(yīng)該是相對于DataView所管理的那一段而言的籍铁,跟DataView相對于ArrayBuffer的偏移量應(yīng)該是兩碼事。
??????作者說DataView就是讓我們能在字節(jié)級別上讀寫數(shù)組緩沖器中的數(shù)據(jù)趾断。不過它的缺點是拒名,使用的時候要自己記住數(shù)據(jù)要保存在哪幾位,需要占用多少字節(jié)芋酌,還是比較繁瑣的增显。

類型化視圖
??????也叫類型化數(shù)組,繼承自DataView脐帝,它的元素必須是特定類型同云。
??????每種類型化數(shù)組都有一個BYTES_PER_ELEMENT屬性糖权,表示每個元素占多少字節(jié),比如說Uint8Array.BYTES_PER_ELEMENT就是1炸站。
??????利用BYTES_PER_ELEMENT星澳,可以比較方便地初始化。例:new Int8Array(buffer, 0, 10 * Int8Array.BYTES_PER_ELEMENT)
??????里邊還講了它的一些特點和一些使用方法旱易,我就不抄了
??????類型化視圖的目的在于簡化對二進制數(shù)據(jù)的操作禁偎。
??????類型化數(shù)組是WebGL項目中執(zhí)行各種操作的重要基礎(chǔ)

3.2 WebGL上下文

??????WebGL是OpenGL ES 2.0在Web上的實現(xiàn)。
??????由于有些瀏覽器不支持WebGL咒唆,所以使用前要檢測一下是否能成功獲取WebGL上下文届垫。
??????通過getContext()獲取WebGL上下文時,可以傳入第二個參數(shù)用于設(shè)置WebGL上下文的一些選項全释,這些選項有:
??????alpha 是否為上下文創(chuàng)建一個Alpha通道緩沖區(qū)装处,默認true
??????depth 是否使用16位深緩沖區(qū),默認true
??????stencil 是否使用8位模板緩沖區(qū)浸船,默認true
??????antialias 是否使用默認的抗鋸齒功能妄迁,默認true
??????premultipliedAlpha 繪圖緩沖區(qū)是否預(yù)乘Alpha值,默認true
??????preserveDrawingBuffer 是否在繪圖完成后保留繪圖緩沖區(qū)李命,默認false登淘。
??????這些選項的含義我一個也不懂
??????傳遞這些參數(shù)的代碼是這樣的:

if (canvas.getContext) {
    gl = canvas.getContext('experimental-webgl', {alpha:false...});
    if (gl) {
      ...
    }
}

常量
??????WebGL支持OpenGL中的大部分常量。只是不像OpenGL里那樣帶有GL_前綴封字。比如黔州,OpenGL里的GL_COLOR_BUFFER_BIT就是WebGL里的gl.COLOR_BUFFER_BIT。

方法命名
??????OpenGL(以及WebGL)中很多方法都在名字中體現(xiàn)其數(shù)據(jù)類型的信息阔籽,比如流妻,gl.uniform4f()表示這個方法要接收4個浮點數(shù),gl.uniform3i()表示要接收3個整數(shù)(f表示浮點數(shù)笆制,i表示整數(shù))绅这。而gl.uniform3iv()表示方法接收3個整數(shù)數(shù)組(v表示vector)。

準(zhǔn)備繪圖
??????在實際操作WebGL上下文之前在辆,一般要使用一種實色清除canvas证薇,所以首先要使用clearColor方法指定這個顏色。
??????下面是清理緩沖區(qū)的代碼:
??????gl.clearColor(0, 0, 0, 1) // 參數(shù)分別代表RGBA
??????gl.clear(gl.COLOR_BUFFER_BIT) // 把屏幕顏色清除成當(dāng)前設(shè)置清除顏色

視口與坐標(biāo)
??????開始繪圖前匆篓,先要定義webGL的視口浑度。默認情況下WebGL的視口為整個canvas區(qū)域。
也可以調(diào)用gl.viewport()方法設(shè)定視口大小鸦概。viewport方法接收4個參數(shù)俺泣,前兩個指定坐標(biāo),后兩個指定寬高。
??????指定視口的坐標(biāo)時伏钠,以canvas元素的左下角為坐標(biāo)原點(而不是平常網(wǎng)頁坐標(biāo)那樣從左上角開始)
??????另外,視口內(nèi)部的坐標(biāo)系與定義視口時的坐標(biāo)系也不一樣谨设,在視口內(nèi)部熟掂,坐標(biāo)原點為視口的中心。

緩沖區(qū)
碎碎念:WebGL有個緩沖區(qū)的概念扎拣。它是什么意思赴肚?
作者說,頂點信息保存在類型化數(shù)組中二蓝,使用前必須轉(zhuǎn)換到WebGL緩沖區(qū)誉券。

我不知道這個數(shù)據(jù)被讀取的鏈條是怎么樣的,首先數(shù)據(jù)在類型化數(shù)組中刊愚?然后被搬到緩沖區(qū)踊跟?然后被繪制到頁面上?


書上只說了緩沖區(qū)的用法:
??????gl.createBuffer()創(chuàng)建緩沖區(qū)
??????gl.bindBuffer(target, buffer)綁定緩沖區(qū)到WebGL上下文的某個指定對象鸥诽。因為不能直接向緩沖區(qū)寫入數(shù)據(jù)商玫,而只能向“目標(biāo)”寫入數(shù)據(jù),所以要想緩沖區(qū)寫數(shù)據(jù)牡借,必須先綁定拳昌。
??????gl.bufferData(target, data, usage)往緩沖區(qū)寫入內(nèi)容
??????gl.deleteBuffer(buffer)刪除緩沖區(qū),釋放內(nèi)存钠龙。如果不deleteBuffer炬藤,則在頁面重新加載前,緩沖區(qū)始終保留在內(nèi)存中碴里。
??????幾個方法接收的參數(shù)我也看不懂作者說的什么意思
??????網(wǎng)上查了一下沈矿,緩沖區(qū)主要是用于一口氣畫多個點。

錯誤
??????WebGL與JavaScript的一個最大區(qū)別在于并闲,WebGL操作一般不會拋出錯誤细睡。為了知道是否有錯誤發(fā)生,必須在一個可能出錯的語句后面帝火,加上一句gl.getError()溜徙,getError方法將返回一個常量,常量的值表示了錯誤情況犀填。
??????有時候一個語句可能會出多個錯蠢壹,為了保證能把所有錯誤信息都讀取來,最好用循環(huán)語句調(diào)用gl.getError()九巡,直到得到的常量值為0(也就是gl.NO_ERROR)為止图贸。

著色器
??????著色器shader是OpenGL中的另一個概念。在WebGL中有兩種著色器,頂點著色器和像素著色器疏日。
??????頂點著色器用于將3D的頂點轉(zhuǎn)換為需要渲染的2D點偿洁。
??????像素著色器用于計算要繪制的每個像素的顏色。
??????WebGL著色器不是用JavaScript寫的沟优,而是用GLSL語言寫的涕滋。

編寫著色器
??????GLSL是一種類C語言,專門用于編寫OpenGL著色器挠阁。因為WebGL是按OpenGL ES2.0實現(xiàn)的宾肺,所以O(shè)penGL中的著色器可以在webGL中使用,因此方便了將桌面圖形應(yīng)用移植到瀏覽器中侵俗。

編寫著色器程序
略(我看不懂锨用,以后再去了解WebGL)

為著色器傳入值

調(diào)試著色器和程序

繪圖
??????WebGL只能繪制3種形狀:點、線和三角隘谣。其它所有形狀都是由這三種基本形狀合成后再繪制到三維空間中的增拥。
??????執(zhí)行繪圖操作要調(diào)用gl.drawArrays()或gl.drawElements()方法,前者用于繪制數(shù)組緩沖區(qū)洪橘,后者用于繪制元素數(shù)組緩沖區(qū)跪者。
??????gl.drawArrays()和gl.drawElements()的第一個參數(shù)都是一個常量,用于指定繪制的形狀熄求。(比方說渣玲,把數(shù)組中每個頂點當(dāng)作一個點來繪制/把數(shù)組中的點當(dāng)作若干個線段的頂點來繪制,因為是若干個線段弟晚,每個線段要兩個點來表示忘衍,所以數(shù)組長度應(yīng)當(dāng)是偶數(shù)/把數(shù)組中的每個頂點當(dāng)作一個多邊形的各頂點,畫成一個閉合形狀……)

紋理
??????WebGL可以使用DOM中的image卿城、video枚钓、其它canvas當(dāng)作紋理。用作紋理的圖像必須與包含頁面來自同一個域瑟押,或者服務(wù)器允許資源跨域共享搀捷。

讀取像素
??????與canvas 2D上下文類似,WebGL上下文也能讀取像素值多望。


3.3 支持

??????要注意嫩舟,瀏覽器實現(xiàn)了WebGL以后,還需要計算機顯示驅(qū)動程序也要支持怀偷,才能使用WebGL家厌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市椎工,隨后出現(xiàn)的幾起案子饭于,更是在濱河造成了極大的恐慌蜀踏,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掰吕,死亡現(xiàn)場離奇詭異果覆,居然都是意外死亡,警方通過查閱死者的電腦和手機殖熟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門随静,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吗讶,你說我怎么就攤上這事×道Γ” “怎么了照皆?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沸停。 經(jīng)常有香客問我膜毁,道長,這世上最難降的妖魔是什么愤钾? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任瘟滨,我火速辦了婚禮,結(jié)果婚禮上能颁,老公的妹妹穿的比我還像新娘杂瘸。我一直安慰自己,他們只是感情好伙菊,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布败玉。 她就那樣靜靜地躺著,像睡著了一般镜硕。 火紅的嫁衣襯著肌膚如雪运翼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天兴枯,我揣著相機與錄音血淌,去河邊找鬼。 笑死财剖,一個胖子當(dāng)著我的面吹牛悠夯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播峰伙,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼疗疟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瞳氓?” 一聲冷哼從身側(cè)響起策彤,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤栓袖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后店诗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裹刮,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年庞瘸,在試婚紗的時候發(fā)現(xiàn)自己被綠了捧弃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡擦囊,死狀恐怖违霞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瞬场,我是刑警寧澤买鸽,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站贯被,受9級特大地震影響眼五,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜彤灶,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一看幼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧幌陕,春花似錦诵姜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至搬卒,卻和暖如春瑟俭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背契邀。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工摆寄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人坯门。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓微饥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親古戴。 傳聞我的和親對象是個殘疾皇子欠橘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359