做者本人的乾貨,通常人我不給他看。(開玩笑的)web
canvas是一個很實用的工具,難能夠難到頭髮掉光,簡單能夠簡單到幾行代碼就能給人眼前一亮的效果。這裏是做者在開發canvas的道路上遇過的坑,以及如何用簡易地使用canvas作一些平常任務,好比分享圖片的自定義,又好比你們喜歡的X炸天的粒子特效(不知道算不算,反正很COOL就是了)。canvas
你們都知道Canvas能夠作流暢的動畫,功能很強大,可是Canvas中並無像Dom那樣能夠幫助咱們調試的工具。不過如今mac有一款web inspector(webkit.org/downloads//)能夠調試canvas,有興趣的同窗能夠去試一下。api
不過這裏還有一種方式能夠幫助你們調試Canvas。Canvas其實就是一塊繪板,隨便你在上面畫什麼。可是又不像PS那樣有輔助線,所以定位很艱辛。數組
所以,手動給Canvas加上網格,不就能夠了!這裏咱們能夠建立一個繪製網格的方法,而後每次render的時候調用,這樣就能夠對圖形的定位有一個直觀的感覺了。不再用抓瞎。瀏覽器
首先咱們要計算好網格的數量,將全部計算好的網線放入一個數組中。雖然咱們也能夠動態計算,網格的位置,可是從性能上考慮,canvas中凡是在繪圖以前能夠確認的位置都提早計算好,這樣能夠提升性能。這裏我留了一點空間給座標值,所以並非全屏的網格。bash
let Grids=[]
function initGrid(cap,width,height,lineWidth){
const colNum=Math.ceil(width/cap)-1
const rowNum=Math.ceil(height/cap)-1
for(let i=1;i<=colNum;i++){
Grids.push([[cap*i-1, 0,lineWidth,colNum*cap],[i*cap,cap*i-1,colNum*cap+5,"top"]])
}
for(let i=1;i<=rowNum;i++){
Grids.push([[ 0,cap*i-1,rowNum*cap,lineWidth],[i*cap,rowNum*cap+5,cap*i-1,"middle"]])
}
}
initGrid(cap,canvasWidth,canvasHeight,lineWidth);
複製代碼
計算並保存好信息以後,咱們就要開始畫線了。對於線的寬度最好是雙數,而後位置偏1px,然線居中,由於.5px在有些機子上性能很差,好比四捨五入一類的,容易有誤差。微信
function createGrid(){
context.fillStyle = 'green';
context.textAlign="center"
context.font="24px Arial"
Grids.forEach((grid)=>{
context.textBaseline=grid[1][3]
context.fillRect( grid[0][0],grid[0][1], grid[0][2], grid[0][3])
context.fillText (grid[1][0],grid[1][1], grid[1][2]);
})
}
複製代碼
注意這裏beginPath是一切新開始的意思,也就是當前圖和上一個操做已經沒有了任何關係。closePath就是結束的意思,一切回到最初開始的地方,就是最早開始的那個點。lineTo就是畫線的意思,兩個點之間畫一條直線。咱們能夠搭配moveTo使用,moveTo就是移動到當前點,可是並不繪製任何內容。工具
若是咱們只是繪製圖形,並沒有其餘操做,好比每段路徑的顏色不同或者是填充顏色不同,那麼moveTo和beiginPath的做用差很少,可是若是是,那麼每次都須要beginPath一下,切斷與上一個路徑的聯繫,不然會以最後的設置的填充色路徑色爲主。性能
那麼問題來了我直接closePath能夠嗎?固然不行,你能夠說開始就開始,但不能說結束就結束!closePath最大的做用就是鏈接路徑最後一個點和路徑最開始的點。動畫
由於Canvas是畫布,因此每次畫面更新時都是擦乾淨,再畫下一幅畫,否則就會重疊。你們想一想一下幀動畫,就是1s中N幅畫劃過的動態感,變成了會動的動畫。若是是jpg這種不透明的圖片還能夠一層層覆蓋,若是是png透明的圖片,一層層就會堆疊在一塊兒。因此橡皮擦的功能時必不可少的。
其實就是畫一個矩形,矩形所在的地方圖像消失。
在線玩耍地址:
See the Pen canvas No.1 by cherryvenus (@cherryvenus) on CodePen.
Canvas中有幾個小知識點,很是的實用,並且應該是平常開發中基本上都要使用的。
首先就是像素的問題,你們有沒有遇到過Canvas模糊的問題,尤爲是手機,這個現象尤其明顯。那麼有沒有解決方案呢?答案是固然有!並且並不複雜,一個屬性就能夠搞定!
Canvas的尺寸其實又兩個,不知道你們有沒有發現。一個時Canvas的大小,一個是Canvas的樣式大小。
canvas.width=cWidth
canvas.height=cHeight
canvas.style.width=cWidth
canvas.style.height=cHeight
複製代碼
那麼這就好解決的。咱們的圖片若是1:1放在手機上確定是模的,可是咱們會將圖片的樣式寬度減小一半以上,這樣就不模糊了!Canvas也是同理,只要樣式大小小於Canvas大小便可。那麼小多少呢?有沒有一個標準?這個時候就要借用window.devicePixelRatio
這個參數了,告訴咱們屏幕的像素比,若是沒有就2,通常來講像素比是2的狀況下,Canvas就不會模糊。
const dpr=window.devicePixelRatio||2
canvas.width=cWidth*dpr
canvas.height=cHeight*dpr
canvas.style.width=cWidth
canvas.style.height=cHeight
複製代碼
咱們的H5在哪裏的傳播最多?微信啊!咱們常常接到一個功能,讓用戶保存圖片,分享到朋友圈。一般這個圖片是用戶本身填寫內容,而後打印到屏幕上。最後合成,保存的。那麼Canvas該如何幫助咱們保存圖片呢?
Canvas雖然不能直接保存圖片,可是卻能夠生成Base64的文件。咱們將Base64放入img標籤中,用戶就能夠自由保存了。
代碼也很簡單canvas.toDataURL('image/jpeg');
。
代碼玩耍地址:
See the Pen Canvas No.2 by cherryvenus (@cherryvenus) on CodePen.
Canvas的代碼一個不當心就會寫好多好多,每次新建一個操做都要寫好多內容。這個時候就要看看Canvas的複用操做了,一個是減小操做,還有一個就是減小機器的壓力,防止計算量過多。
談到save&restore,可能你們會有點懵,不知道這個是用來作什麼的。也不知道有什麼用。咱們假想全部的canvas的配置,如fillSytle,strokeStyle的狀態都封裝在一個對象之中,而後每次save這個對象,就將這個對象push到一個Cavans狀態的數組之中,以後咱們可能改變了其中的一些屬性,而後咱們又須要以前的哪一個配置,怎麼辦?再寫一遍屬性配置嗎?不,這個時候咱們能夠用restore,一鍵切換至上一個狀態。也就是當前的配置所有失效。全部屬性值回退到以前的一個狀態。咱們能夠一直restore到默認值,也就是Canvas狀態數組空了爲止。
代碼玩耍地址:
See the Pen Canvas No3 save&restore by cherryvenus (@cherryvenus) on CodePen.
解析圖:
我的以爲Canvas中最頭疼的就是圖片的繪製了,drawImage這個一個方法,就能夠幫助咱們完成拉伸,剪切,放大,縮小的功能。
drawImage的總參數有9個,可是平時咱們能夠簡寫。
第一個參數必定是image,也就是咱們的圖片對象。其他的幾個參數,容易搞混。咱們來詳細地看下。
參數 | 做用 |
---|---|
dx,dy | 這個最好理解,這裏是指圖片開始繪製的位置,若是設置這兩個參數,就是從這個(dx,dy)點開始繪製原始完整的圖片 |
dx,dy,dwidth,dheight | 這裏除了開始點(dx,dy),還有圖片在畫布上呈現的大小,這邊須要注意,雖然會畫完整的圖片,可是會按照dwidth和dheight的尺寸來,所以就會產生圖片變形的狀況。 |
sx,sy,swidth,sheight,dx,dy,dwidth,dheight | 這個比較難以理解,前四個是對原始圖片的操做,也就獲取原始圖片的區域,後四個參數就是圖片須要繪製在畫布上的位置和大小。也就是圖片的所選區域放入畫布的所選區域。 |
玩耍地址:
See the Pen Canvas N0.4 by cherryvenus (@cherryvenus) on CodePen.
這個api是最amazing的方法,由於他幫助咱們獲取了畫布的顏色信息,經過這個信息,咱們能夠從新創造新的圖片。這個方法除了體積大,沒啥毛病。由於他的data長度是按照width(寬)*height(高)*4(rgba四個顏色信息)
組成的。
let info=context.getImageData(x,y,width,height)
//返回
data
width
height
複製代碼
這裏要避免遍歷data(data.forEach
),來處理圖片信息,由於很大,瀏覽器容易卡頓。最好按照定位信息,獲取當前座標的顏色信息。
至於最開始的那個特效,我是藉助了matter.js這個庫,才能完成的。若是是手寫特效的話,不如這個庫來的生動有趣。
play地址:
See the Pen canvas No5. COOL by cherryvenus (@cherryvenus) on CodePen.