要使用<canvas>元素,必須先設置其width和height屬性,指定能夠繪圖的區域大小。出如今開始和結束標籤中的內容是後備信息,若是瀏覽器不支持<canvas>元素,就會顯示這些信息。以下例子:web
<canvas id="drawing" width="200" height="200"> A drawing of something.</canvas>
與其它元素同樣,<canvas>元素對應的DOM元素對象也有width和height屬性,能夠隨意修改。並且,也能夠經過CSS爲該元素添加樣式,若是不添加任何樣式或者不繪製任何圖形,在頁面中是看不到該元素的。canvas
要在這塊畫布(canvas)上繪圖,須要取得繪圖上下文。以下代碼:數組
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); //更多代碼 }
使用toDataURL()方法,能夠導出在<canvas>元素上繪製的圖像。這個方法接收一個參數,即圖像的MIME類型格式,並且適合用於建立圖像的任何上下文。好比,要取得畫布中的一副PNG格式的圖像,以下代碼:瀏覽器
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ //取得圖像數據的URI var imgURI = drawing.toDataURL("image/png"); //顯示圖像 var image = document.createElement("img"); image.src = imgURI; document.body.appendChild(image); }
使用2D繪圖上下文提供的方法,能夠繪製簡單的2D圖形,好比矩形、弧線和路徑。2D上下文的座標開始於<canvas>元素的左上角,原點座標是(0,0)。全部座標值都基於這個原點計算。x值越大越靠右,y值越大越靠下。app
2D上下文的兩種基本繪圖操做是填充和描邊。填充,就是用指定的樣式(顏色、漸變或圖像)填充圖形;描邊,就是隻在圖形的邊緣畫線。大多數2D上下文操做都會細分爲填充和描邊兩個操做,而操做的結果取決於兩個屬性:fillStyle和strokeStyle。ide
這兩個屬性的值能夠是字符串、漸變對象或模式對象。並且他們的默認值都是「#000000」。若是爲他們指定表示顏色的字符串值,可使用CSS中指定顏色值的任何格式,包括顏色名、十六進制碼、rgb、rgba、hsl或hsla,以下例子:函數
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); context.strokeStyle = "red"; context.fillStyle = "#0000ff"; }
矩形是惟一一種能夠直接在2D上下文中繪製的形狀。與矩形有關的方法包括fillRect()、strokeRect()和clearRect()。這三個方法都能接收4個參數:矩形的x座標、矩形的y座標、矩形的寬度和高度。這些參數的單位都是像素。性能
首先fillRect()方法在畫布上繪製的矩形會填充指定的顏色。填充的顏色經過fillStyle屬性指定,好比:字體
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); //繪製紅色矩形 context.fillStyle = "#ff0000"; context.fillRect(10,10,50,50); //繪製半透明的藍色矩形 context.fillStyle = "rgba(0,0,255,0.5)"; context.fillRect(30,30,50,50); }
strokeRect()方法在畫布上繪製的矩形會使用指定的顏色描邊。描邊顏色經過strokeStyle屬性指定。好比:webgl
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); //繪製紅色描邊矩形 context.strokeStyle = "#ff0000"; context.strokeRect(10,10,50,50); //繪製半透明的藍色描邊矩形 context.strokeStyle = "rgba(0,0,255,0.5)"; context.strokeRect(30,30,50,50); }
以上代碼繪製了兩個重疊的矩形。不過,這兩個矩形都只有框線,內部並無填充顏色。
最後,clearRect()方法用於清除畫布上的矩形區域。本質上,這個方法能夠把繪製上下文中的某一矩形區域變透明。經過繪製形狀而後再清除指定區域,就能夠生成有意思的效果,例如把某個形狀切掉一塊。以下例子:
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); //繪製紅色矩形 context.fillStyle = "#ff0000"; context.fillRect(10,10,50,50); //繪製半透明的藍色矩形 context.fillStyle = "rgba(0,0,255,0.5)"; context.fillRect(30,30,50,50); //在兩個矩形重疊的地方清除一個小矩形 context.clearRect(40,40,10,10); }
2D繪製上下文支持不少在畫布上繪製路徑的方法。經過路徑能夠創造出複雜的形狀和線條。要繪製路徑,首先必須調用beginPath()方法,表示要開始繪製新路徑。而後,在經過下列方法來實際的繪製路徑。
建立了路徑後,接下來有幾種可能的選擇。若是想繪製一條想鏈接到路徑起點的線條,能夠調用closePath()。若是路徑已經完成,你想用fillStyle填充它,能夠調用fill()方法。另外,還能夠調用stroke()方法對路徑描邊,描邊使用的是strokeStyle。最後還能夠調用clip(),這個方法能夠在路徑上建立一個剪切區域。
以下例子,繪製一個不帶數字的時鐘錶盤。
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.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.strokeStyle = "#ff0000"; context.stroke(); }
因爲路徑的使用很頻繁,因此就有了一個名爲isPointInPath()的方法。這個方法接收x和y座標做爲參數,用於在路徑被關閉以前肯定畫布上的某一點是否位於路徑上,例如:
if(context.isPointInPath(100,100)){ console.log("Point(100,100) is in the path") }
繪製文本主要有兩個方法:fillText()和strokeText()。這兩個方法均可以接收4個參數:要繪製的文本字符串、x座標、y座標和可選的最大像素寬度。並且,這兩個方法都如下列3個屬性爲基礎。
這幾個屬性都有默認值,所以不必每次使用它們都從新設置一遍值。fillText()方法使用fillStyle屬性繪製文本,而strokeText()方法使用strokeStyle屬性爲文本描邊。相對來講,仍是使用fillText()的時候更多,由於該方法模仿了在網頁中正常顯示文本。例以下面代碼在前面建立的錶盤上方繪製了數字12:
context.font = "bold 14px Arial"; context.textAlign = "center"; context.textBaseline = "middle"; context.fillText("12",100,20);
上面座標(100,20)表示的是文本水平和垂直中點的座標。
//正常 context.font = "bold 14px Arial"; context.textAlign = "center"; context.textBaseline = "middle"; context.fillText("12",100,20); //起點對齊 context.textAlign = "start"; context.fillText("12",100,40); //終點對齊 context.textAlign = "end"; context.fillText("12",100,60);
因爲繪製文本比較複雜,特別是須要把文本控制在某一區域中的時候,2D上下文提供了輔助肯定文本大小的方法measureText()。這個方法接收一個參數,即要繪製的文本;返回一個TextMetrics對象。返回的對象目前只有一個width屬性,但未來還會增長更多度量屬性。
measureText()方法利用font、textAlign和textBaseline的當前值計算指定文本的大小。好比,假設你想在一個140像素寬的矩形區域中繪製文本 Hello world!,下面的代碼從100像素的字體大小開始遞減,最終會找到合適的字體大小。
var fontSize = 100; context.font = fontSize + "px Arial"; while(context.measureText("Hello world!").width > 140){ fontSize--; context.font = fontSize + "px Arial"; } context.fillText("Hello world!",10,100); context.fillText("Font size is" + fontSize + "px", 10,150);
經過上下文的變換,能夠把處理後的圖像繪製到畫布上。2D繪製上下文支持各類基本的繪製變換。建立繪製上下文時,會以默認值初始化變換矩陣,在默認的變換矩陣下,全部處理都按描述直接繪製。爲繪製上下文應用變換,會致使不一樣的變換矩陣應用處理,從而產生不一樣的結果。
能夠經過以下方法來修改變換矩陣。
m1_1 m1_2 dx
m2_1 m2_2 dy
0 0 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); //繪製內圓 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.strokeStyle = "#ff0000"; context.stroke(); }
把原點變換到時鐘錶盤的中心點(100,100)後,在同一方向上繪製線條就變成了簡單的數學問題了。全部數學計算都基於(0,0),而不是(100,100)。還能夠更進一步,像下面這樣使用rotate()方法旋轉時針的錶針。
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.moveTo(194,100); context.arc(100,100,94,0,2*Math.PI,false); //變換原點 context.translate(100,100); //旋轉錶針 context.rotate(1); //繪製分針 context.moveTo(0,0); context.lineTo(0,-85); //繪製時針 context.moveTo(0,0); context.lineTo(-65,0); //繪製描邊 context.strokeStyle = "#ff0000"; context.stroke(); }
雖然沒有什麼辦法把上下文中的一切都重置回默認值,但有兩個方法能夠跟蹤上下文的狀態變化。若是你知道未來還要返回某組屬性與變換的組合,能夠調用save()方法。調用這個方法後,當時的全部設置都會進入一個棧結構,得以妥善保管。而後能夠對上下文進行其它修改。等想要回到以前保存的設置時,能夠調用restore()方法,在保存設置的棧結構中向前返回一級,恢復以前的狀態。連續調用save()能夠把更多設置保存到棧結構中,以後在連續調用restore()則能夠一級一級返回,以下例子:
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"; context.fillRect(0,0,100,200); //從點(100,100)開始繪製藍色矩形 context.restore(); context.fillRect(10,10,100,200); //從點(110,110)開始繪製綠色矩形 context.restore(); context.fillRect(0,0,100,200); //從點(0,0)開始繪製紅色矩形 }
須要注意的是,save()方法保存的只是對繪圖上下文的設置和變換。不會保存繪圖上下文的內容。
使用drawImage()方法能夠把圖像繪製到畫布上。調用這個方法時,可使用三種不一樣的參數組合。最簡單的調用方式是傳入一個HTML<img>元素,以及繪製該圖像的起點的x和y座標,以下:
window.onload = function(){ var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); var img = document.images[0]; context.fillStyle = "#000000"; context.fillRect(0,0,200,200); context.drawImage(img,10,10); } }
若是你想改變繪製後的圖像大小,能夠多傳兩個參數,分別表示目標寬度和目標高度。以下:
window.onload = function(){ var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); var img = document.images[0]; context.fillStyle = "#000000"; context.fillRect(0,0,200,200); context.drawImage(img,10,10,100,200); } }
執行後圖像的大小變成了100*200。
除了上述兩種方式,還能夠選擇把圖像中的某個區域繪製到上下文中。drawImage()方法的這種調用方式總共須要傳入9個參數:要繪製的圖像、源圖像的x座標、源圖像的y座標、源圖像的寬度、源圖像的高度、目標圖像的x座標、目標圖像的y座標、目標圖像的寬度、目標圖像的高度。以下:
context.drawImage(img,0,10,50,50,0,100,40,60);
這行代碼只把原始圖像的一部分繪製到畫布上。原始圖像的這一部分起點爲(0,10),寬和高都是50像素。最終繪製到上下文中的圖像的起點爲(0,100),而大小變成了40*60像素。
2D上下文會根據如下幾個屬性的值,自動爲形狀或路徑繪製出陰影。
這些屬性均可以經過context對象來修改。
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); //設置陰影 context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowBlur = 4; context.shadowColor = "rgba(0,0,0,0.5)"; //繪製紅色矩形 context.fillStyle = "#ff0000"; context.fillRect(10,10,50,50); //繪製藍色矩形 context.fillStyle ="rgba(0,0,255,1)"; context.fillRect(30,30,50,50); }
漸變由CanvasGradient實例表示,很容易經過2D上下文來建立和修改。要建立一個新的線性漸變,能夠調用createLinearGradient()方法。這個方法接收4個參數:起點的x座標、起點的y座標、終點的x座標、終點的y座標。調用這個方法後,它就會建立一個指定大小的漸變,並返回CanvasGradient對象的實例。
建立了漸變對象後,下一步就是使用addColorStop()方法來指定色標。這個方法接收2個參數:色標位置和CSS顏色值。色標位置是一個0(開始的顏色)到1(結束的顏色)之間的數字。以下:
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); var gradient = context.createLinearGradient(30,30,70,70); gradient.addColorStop(0,"white"); gradient.addColorStop(1,"black"); //繪製紅色矩形 context.fillStyle = "#ff0000"; context.fillRect(10,10,50,50); //繪製漸變矩形 context.fillStyle =gradient; context.fillRect(30,30,50,50); }
確保漸變也形狀對齊,以下代碼:
function createRectLinearGradient(context,x,y,width,height){ return context.createLinearGradient(x,y,x+width,y+height); }
這個函數基於起點的x和y座標以及寬度和高度值來建立漸變對象,從而讓咱們能夠在fillRect()中使用相同的值,以下:
function createRectLinearGradient(context,x,y,width,height){ return context.createLinearGradient(x,y,x+width,y+height); } var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); var gradient = createRectLinearGradient(context,30,30,50,50); gradient.addColorStop(0,"white"); gradient.addColorStop(1,"black"); //繪製紅色矩形 context.fillStyle = "#ff0000"; context.fillRect(10,10,50,50); //繪製漸變矩形 context.fillStyle =gradient; context.fillRect(30,30,50,50); }
要建立徑向漸變(或放射漸變),可使用createRadialGradient()方法。這個方法接收6個參數,對應這兩個圓的圓心和半徑。前三個參數指定的是起點圓的原心(x和y)以及半徑,後三個參數指定的是終點圓的原心(x和y)以及半徑。
若是想從某個形狀的中心點開始建立一個向外擴散的徑向漸變效果,就要將兩個圓定義爲同心圓。好比,拿前面建立的矩形來講,徑向漸變的兩個圓的圓心都應該在(55,55),由於矩形的區域是從(30,30)到(80,80),看下面代碼:
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); var gradient = context.createRadialGradient(55,55,10,55,55,30); gradient.addColorStop(0,"white"); gradient.addColorStop(1,"black"); //繪製紅色矩形 context.fillStyle = "#ff0000"; context.fillRect(10,10,50,50); //繪製漸變矩形 context.fillStyle =gradient; context.fillRect(30,30,50,50); }
效果以下所示:
模式其實就是重複的圖像,能夠用來填充或描邊圖形。要建立一新模式,能夠調用createPattern()方法並傳入兩個參數:一個THML<img>元素和一個 表示如何重複圖像的字符串。其中,第二個參數的值與CSS的background-repeat的屬性值相同,包括「repeat」、「repeat-x」、「repeat-y」和「no-repeat」。以下例子:
window.onload = function(){ var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); var image = document.images[0], pattern = context.createPattern(image,"repeat"); //繪製矩形 context.fillStyle =pattern; context.fillRect(10,10,150,150); } }
效果如圖:
createPattern()方法的第一個參數也能夠是一個<video>元素,或者另外一個<canvas>元素。
2D上下文的一個明顯長處就是,能夠經過getImageData()取得原生圖像數據。這個方法接收4個參數:要取得其數據的畫面區域的x和y座標以及該區域的像素寬度和高度。例如要取得左上角座標爲(10,5)、大小爲50*50像素區域的圖像數據,以下代碼:
var imageData = context.getImageData(10,5,50,50);
這裏返回的對象是imageData的實例。每一個imageData對象都有三個屬性:width、height和data。其中data屬性是一個數組,保存着圖像中每個像素的數據。在data數組中,每個像素用4個元素來保存,分別表示紅、綠、藍和透明度值。所以,第一個像素的數據就保存在數組的第0到第3個元素中,例如:
var data = imageData.data, red = data[0], green = data[1], blue = data[2], alpha = data[3];
數組中每一個元素的值都介於0到255之間(包括0和255)。可以直接訪問到原始圖像數據,就可以以各類方式來操做這些數據。例如,經過修改圖像數據,能夠像下面這樣建立一個簡單的灰階過濾器。
window.onload = function(){ var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"), image = document.images[0], imageData,data, i,len,average, red,green,blue,alpha; //繪製原始圖像 context.drawImage(image,0,0); //取得圖像數據 imageData = context.getImageData(0,0,image.width,image.height); data = imageData.data; for( i = 0, len = data.length; i < len; i+=4){ red = data[i]; green = data[i+1]; blue = data[i+2]; alpha = data[i+3]; //求得rgb平均值 average = Math.floor((red + green + blue) / 3); //設置顏色值,透明度不變 data[i] = average; data[i+1] = average; data[i+2] = average; } //回寫圖像數據並顯示結果 imageData.data = data; context.putImageData(imageData,0,0); } }
如上代碼,在把data數組回寫到imageData對象後,調用putImageData()方法把圖像數據繪製到畫布上。最終獲得了圖像的黑白版。
效果以下:
還有兩個會應用到2D上下文中全部繪製操做的屬性:globalAlpha和globalCompositionOperation。其中globalAlpha是一個介於0到1之間的值(包括0和1),用於指定全部繪製的透明度。默認值爲0。若是全部後續操做都要基於相同的透明度,就能夠先把globalAlpha設置爲適當的值,而後繪製,最後再把它設置爲默認值0。以下例子:
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); //繪製紅色矩形 context.fillStyle = "#ff0000"; context.fillRect(10,10,50,50); //修改全局透明度 context.globalAlpha = 0.5; //繪製藍色矩形 context.fillStyle = "rgba(0,0,255,1)"; context.fillRect(30,30,50,50); //重置全局透明度 context.globalAlpha = 0; }
在上面例子中,咱們把藍色矩形繪製到了紅色矩形上面,由於在繪製藍色矩形前,globalAlpha設置爲了0.5,因此藍色矩形會呈現半透明效果,透過它能夠看到下面的紅色矩形。
第二個屬性globalCompositionOperation表示後繪製的圖形怎樣與先繪製的圖形結合。這個屬性的值是字符串,可能的值以下:
var drawing = document.getElementById('drawing'); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext("2d"); //繪製紅色矩形 context.fillStyle = "#ff0000"; context.fillRect(10,10,50,50); //設置合成操做 context.globalCompositeOperation = "xor"; //繪製藍色矩形 context.fillStyle = "rgba(0,0,255,1)"; context.fillRect(30,30,50,50); }
webGL是針對Canvas的3D上下文。與其它web技術不一樣,webGL並非W3C指定的標準。而是由Khronos Group制定的。Khronos Group也設計了其餘圖像處理API,好比openGL ES2.0。瀏覽器使用的webGL就是基於openGL ES2.0制定的。
webGL涉及的複雜計算須要提早知道數值的精度,而標準的JavaScript數值沒法知足須要。爲此,webGL引入了一個概念,叫類型化數組(typed arrays)。類型化數組也是數組,只不過其元素被設置爲特定類型的值。
類型化數組的核心就是一個名爲ArrayBuffer的類型。每一個ArrayBuffer對象表示的只是內存中指定的字節數,但不會指定這些字節用於保存什麼類型的數據。經過ArrayBuffer所能作的,就是爲了未來使用而分配必定數量的字節。例如,下面這行代碼會在內存中分配20B。
var buffer = new ArrayBuffer(20);
建立了ArrayBuffer對象後,可以經過該對象得到的信息只有它包含的字節數,方法是訪問其byteLength屬性:
var bytes = buffer.byteLength;
雖然ArrayBuffer對象自己沒有什麼可說的,但對webGL而言,使用它是極其重要的。並且,在涉及視圖的時候,你纔會發現它原來仍是頗有意思的。
使用ArrayBuffer(數組緩衝器類型) 的一種特別的方式就是用它來建立數組緩衝器視圖。其中,最多見的視圖是DataView,經過它能夠選擇ArrayBuffer的一小段字節。爲此,能夠在建立DataView實例的時候傳入一個ArrayBuffer、一個可選的字節偏移量(從該字節開始選擇)和一個可選的要選擇的字節數。例如:
var buffer = new ArrayBuffer(20); //基於整個緩衝器建立一個新視圖 var view = new DataView(buffer); //建立一個開始於字節9的新視圖 var view = new DataView(buffer,9); //建立一個從字節9開始到字節18的新視圖 var view = new DataView(buffer,9,10);
實例化後,DataView對象會把字節偏移量以及字節長度信息分別保存在byteOffset和byteLength屬性中。
console.log(view.byteOffset); //9 console.log(view.byteLength); //10
讀取和寫入DataView的時候,要根據實際操做的數據類型,選擇相應的getter和setter方法。下表列出了DataView支持的數據類型以及相應的讀寫方法。
數據類型 | getter | setter |
有符號8位整數 | getInt8(byteOffset) | setInt8(byteOffset,value) |
無符號8位整數 | getUint8(byteOffset) | setUint8(byteOffset,value) |
有符號16位整數 | getInt16(byteOffset,littleEndian) | setInt16(byteOffset,value,littleEndian) |
無符號16位整數 | getUint16(byteOffset,littleEndian) | setUint16(byteOffset,value,littleEndian) |
有符號32位整數 | getInt32(byteOffset,littleEndian) | setInt32(byteOffset,value,littleEndian) |
無符號32位整數 | getUint32(byteOffset,littleEndian) | setUint32(byteOffset,value,littleEndian) |
32位浮點數 | getFloat32(byteOffset,littleEndian) | setFloat32(byteOffset,value,littleEndian) |
64位浮點數 | getFloat64(byteOffset,littleEndian) | setFloat64(byteOffset,value,littleEndian) |
littleEndian:可選。若是爲 false 或未定義,則應寫入 big-endian 值;不然應寫入 little-endian 值。詳細瞭解《MSDN:DataView對象》
全部這些方法的第一個參數都是一個字節偏移量,表示要從哪一個字節開始讀取或者寫入。不要忘了,要保存有些數據類型的數據,可能須要不止1B。好比,無符號8位整數要用1B,而32爲浮點數則要用4B。使用DataView,就須要你本身來管理這些細節,即要明確本身的數據須要多少字節,並選擇正確的讀寫方法。例如:
var buffer = new ArrayBuffer(20), view = new DataView(buffer), value; view.setUint16(0,25); view.setUint16(2,50); //不能從字節1開始,由於16位整數要用2B value = view.getUint16(0);
以上代碼把兩個無符號16位整數保存到了數組緩衝器中。由於每一個16位整數要用2B,因此保存第一個數的字節偏移量爲0,而保存第二個數的字節偏離量爲2。
能夠經過幾種不一樣的方式來訪問同一字節。例如:
var buffer = new ArrayBuffer(20), view = new DataView(buffer), value; view.setUint16(0,25); value = view.getInt8(0); console.log(value); //0
在這個例子中,數值25以16位無符號整數的形式被寫入,字節偏移量爲0。而後,再以8位有符號整數的方式讀取該數據,獲得的結果爲0。這是由於25的二進制形式的前8位(第一個字節)全是0,如圖所示:
可見,雖然DataView能讓咱們在字節級別上讀寫數組緩衝器中的數據,但咱們必須本身記住要將數據保存到哪裏,須要佔用多少字節。這樣一來,就會帶來不少工做量,所以,類型化視圖也就應運而生。
類型化視圖通常也被稱爲類型化數組,由於他們除了元素必須是某種特定的數據類型外,與常規的數組無異。類型化視圖也分爲幾種,並且它們都繼承了DataView。
每種視圖類型都以不一樣的方式表示數據,而同一數據視選擇的類型不一樣有可能佔用一或多字節。例如,20B的ArrayBuffer能夠保存20個Int8Array或Uint8Array,或者10個Int16Array或Uint16Array,或者5個Int32Array、Uint32Array或Float32Array,或者2個Float64Array。
因爲這些視圖都繼承自DataView,於是可使用相同的構造函數參數來實例化。第一個參數是要使用ArrayBuffer對象,第二個參數是做爲起點的字節偏移量(默認爲0),第三個參數是要包含的字節數。三個參數只有第一個是必須的。以下例子:
var buffer = new ArrayBuffer(200); //建立一個新數組,使用整個緩衝器 var int8s = new Int8Array(buffer); //只使用從字節10開始的緩衝器 var int16s = new Int16Array(buffer,10); //只使用從字節10到字節19的的緩衝器 var uint16s = new Uint16Array(buffer,10,10);
可以指定緩衝器中可用的字節段,意味着能在同一個緩衝器中保存不一樣類型的數值。好比,下面的代碼就是在緩衝器的開頭保存8位整數,而在其它字節中保存16位整數。
var buffer = new ArrayBuffer(32); //使用緩衝器的一部分保存8位整數另外一部分保存在16位整數 var int8s = new Int8Array(buffer,0,11); var uint16s = new Uint16Array(buffer,12,10);
每一個視圖構造函數都有一個名爲BYTES_PER_ELEMENT的屬性,表示類型化數組的每一個元素須要多少字節。所以,Uint8Array.BYTES_PER_ELEMENT就是1,而Float32Array.BYTES_PER_ELEMENT則爲4。能夠利用這個屬性來輔助初始化。
var buffer = new ArrayBuffer(32); //須要11個元素空間 var int8s = new Int8Array(buffer,0,11*Int8Array.BYTES_PER_ELEMENT); //須要5個元素空間 var uint16s = new Uint16Array(buffer,int8s.byteOffset + int8s.byteLength + 1,5*Uint16Array.BYTES_PER_ELEMENT);
類型化視圖的目的在於簡化對二進制數據的操做。除了前面看到的優勢以外,建立類型化視圖還能夠不用首先建立ArrayBuffer對象。只要傳入但願數組保存的元素數,相應的構造函數就能夠自動建立一個包含足夠字節數的ArrayBuffer對象,例如:
//建立一個數組保存10個8位整數(10字節) var int8s = new Int8Array(10); //建立一個數組保存10個16位整數(20字節) var int16s = new Int16Array(10);
另外,也能夠把常規數組轉換爲類型化視圖,只要把常規數組傳入到類型化視圖的構造函數便可:
//建立一個數組保存5個8位整數(10字節) var int8s = new Int8Array([10,20,30,40,50]);
這是用默認值來初始化類型化視圖的最佳方式,也是webGL項目中最經常使用的方式。
使用類型化視圖時,能夠經過length屬性肯定數組中有多少元素,以下:
//建立一個數組保存5個8位整數(10字節) var int8s = new Int8Array([10,20,30,40,50]); for(var i = 0,len = int8s.length; i < len; i++){ console.log("value at position" + i + " is " + int8s[i]); }
固然也可使用方括號語法爲類型化視圖的元素賦值。若是爲相應的元素指定字節數放不下相應的值,則實際保存的值是最大可能值的模。例如,無符號16位整數所能表示的最大數值是65535,若是你想保存65536,那實際保存的值是0;若是你想保存65537,那實際保存的值是1,依次類推。
var uint16s = new Uint16Array(10); uint16s[0] = 65537; console.log(uint16s[0]); //1
類型化視圖還有一個方法subarray(),使用這個方法能夠基於底層數組緩衝器的子集建立一個新視圖。這個方法接收兩個參數:開始元素的索引和可選的結束元素的索引。返回的類型與與調用該方法的視圖類型相同。例如:
var uint16s = new Uint16Array(10), sub = uint16s.subarray(2,5); console.log(sub); //[0, 0, 0]
在以上代碼中,sub也是Uint16Array的一個實例,並且底層與uint16s都基於同一個ArrayBuffer。
目前,在支持的瀏覽器中,webGL的名字叫「experimental-webgl」,這是由於webGL的規範仍然未制定完成。制定完成後,這個名字就會變成簡單的「webgl」。若是瀏覽器不支持webGL,取得上下文時會返回null。在使用webGL時,務必先檢測一下返回值:
var drawing = document.getElementById("drawing"); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var gl = drawing.getContext("experimental-webgl"); if(gl){ //使用webGL } }
經過給getContext()傳遞第二個參數,能夠爲webGL上下文設置一些選項。這個參數自己是一個對象,能夠包含下列屬性。
傳遞這個選項對象的方式以下:
var drawing = document.getElementById("drawing"); //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ var gl = drawing.getContext("experimental-webgl",{alpha:false}); if(gl){ //使用webGL } }
大多數上下文選項只在高級技巧中使用。不少時候,各個選項的默認值就能知足咱們的需求。
若是getContext()沒法建立webGL上下文,最好把調用封裝在try-catch塊中,以下:
var drawing = document.getElementById("drawing"), gl; //肯定瀏覽器支持<canvas>元素 if(drawing.getContext){ try{ gl = drawing.getContext("experimental-webgl"); }catch(ex){ //什麼也不作 } if(gl){ //使用webGL }else{ alert("webGL context could not be created"); } }
若是你屬性openGL,那確定會對各類操做中使用很是多的常量印象深入。這些常量在openGL中都帶前綴GL_。在webGL中,保存在上下文對象中的這些常量都沒有GL_前綴。好比,GL_COLOR_BUFFER_BIT常量在webGL上下文就是gl.COLOR_BUFFER_BIT。webGL以這種方式支持大多數openGL常量(有一部分常量是不支持的)。
openGL(以及webGL)中的不少方法都視圖經過名字傳達有關數據類型的信息。若是某種方法能夠接收不一樣類型以及不一樣數量的參數,看方法名的後綴就能夠知道。方法名的後綴會包含參數個數(1到4)和接收的數據類型(f表示浮點數,i表示整數)。例如,gl.uniform4f()意味着要接收4個浮點數,而gl.uniform3i()則表示要接收3個整數。
也有不少方法接收數組參數而非一個個單獨的參數。這樣的方法其名字中會包含字母v(即vector,矢量)。所以,gl.uniform3iv()能夠接收一個包含3個值的整數數組。請你們記住以上命名約定,這樣對理解後面關於webGL的討論頗有幫助。
在實際操做webGL上下文以前,通常都要使用某種實色清除<canvas>,爲繪圖作好準備。爲此,首先必須使用clearColor()方法來指定要使用的顏色值,該方法接收4個參數:紅、綠、藍和透明度。每一個參數必須是一個0到1之間的數值,表示每種份量在最終顏色中的強度,以下代碼:
gl.clearColor(0,0,0,1); //black gl.clear(gl_COLOR_BUFFER_BIT);
以上代碼把清理顏色緩衝區的值設置爲黑色,而後調用clear()方法,這個方法與openGL中的glClear()等價。傳入的參數gl_COLOR_BUFFER_BIT告訴webGL使用以前定義的顏色來填充相應區域。通常來講,都要先清理緩衝區,而後再執行其餘繪圖操做。
開始繪圖以前,一般要先定義webGL的視口(viewport)。默認狀況下視圖可使用整個<canvas>區域。要改變視口大小,能夠調用viewport()方法並傳入4個參數:(視口相對於<canvas>元素的)x座標、y座標、寬度和高度。例如,下面的調用就使用了<canvas>元素:
gl.viewport(0,0,drawing.width,drawing.height);
視口座標與咱們熟悉的網頁座標不同。視口座標的原點(0,0)在<canvas>元素的左下角,x軸和y軸的正方向分別是向右和向上,能夠定義爲(width-1,height-1),以下圖所示:
知道怎麼定義視口大小,就能夠只在<canvas>元素的部分區域中繪圖。以下例子:
//視口是<canvas>左下角的四分之一區域 gl.viewport(0,0,drawing.width/2,drawing.height/2); //視口是<canvas>左上角的四分之一區域 gl.viewport(0,drawing.height/2,drawing.width/2,drawing.height/2); //視口是<canvas>右下角的四分之一區域 gl.viewport(drawing.width/2,0,drawing.width/2,drawing.height/2);
另外,視圖內部的座標系與定義視口的座標系也不同。在視口內部,座標原點(0,0)是視口的中心點,所以,視口左下角座標爲(-1,-1),而右上角座標爲(1,1)。以下圖所示:
若是在視口內部繪圖時使用視口外部的座標,結果可能被視口剪切。好比,要繪製的形狀有一個頂點在(1,2),那麼該形狀在視口右側的部分會被剪切掉。
建立緩衝區:gl.createBuffer(),使用gl.bindBuffer()綁定到webGL上下文,gl.deleteBuffer()釋放內存。
webGL操做通常不會拋出錯誤,手工調用gl.getError()方法。
webGL有兩種着色器:頂點着色器和片斷(或像素)着色器。