html5裏面canvas絕對是大哥級別的,canvas的繪圖是基於js的處理,咱們既然知道canvas,免不了就據說過svg,svg是基於xml擴展而來的,如今圖表插件中國內百度的echarts是基於canvas的,國外一款很是強大的highcharts是基於svg的,svg是可伸縮標記繪圖不支持低級ie,咱們在下一篇html介紹博客也會簡單介紹svg的處理。javascript
1、頁面顯示出咱們的canvascss
咱們在html下面寫入canvas標籤,和加入背景色:html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} #myCanvas{background:#ccc;} </style> <title>demo</title> </head> <body> <canvas id="myCanvas"></canvas> </body> <script type="text/javascript"> </script> </html>
咱們看見了灰色背景的canvas,看來我不作寬高處理,canvas是有默認的值得。html5
咱們經過css去設置寬高:java
#myCanvas{background:#ccc;height: 500px;width: 500px;}
一樣canvas元素也支持寬度和高度屬性的設置;咱們刪除css設置,加入屬性設置css3
<canvas id="myCanvas" height="500" width="500"></canvas>
2、canvas的API預覽chrome
顏色、樣式和陰影canvas
屬性 描述api
fillStyle 設置或返回用於填充繪畫的顏色、漸變或模式數組
strokeStyle 設置或返回用於筆觸的顏色、漸變或模式
shadowColor 設置或返回用於陰影的顏色
shadowBlur 設置或返回用於陰影的模糊級別
shadowOffsetX 設置或返回陰影距形狀的水平距離
shadowOffsetY 設置或返回陰影距形狀的垂直距離
方法 描述
createLinearGradient() 建立線性漸變(用在畫布內容上)
createPattern() 在指定的方向上重複指定的元素
createRadialGradient() 建立放射狀/環形的漸變(用在畫布內容上)
addColorStop() 規定漸變對象中的顏色和中止位置
線條樣式
屬性 描述
lineCap 設置或返回線條的結束端點樣式
lineJoin 設置或返回兩條線相交時,所建立的拐角類型
lineWidth 設置或返回當前的線條寬度
miterLimit 設置或返回最大斜接長度
矩形
方法 描述
rect() 建立矩形
fillRect() 繪製「被填充」的矩形
strokeRect() 繪製矩形(無填充)
clearRect() 在給定的矩形內清除指定的像素
路徑
方法 描述
fill() 填充當前繪圖(路徑)
stroke() 繪製已定義的路徑
beginPath() 起始一條路徑,或重置當前路徑
moveTo() 把路徑移動到畫布中的指定點,不建立線條
closePath() 建立從當前點回到起始點的路徑
lineTo() 添加一個新點,而後在畫布中建立從該點到最後指定點的線條
clip() 從原始畫布剪切任意形狀和尺寸的區域
quadraticCurveTo() 建立二次貝塞爾曲線
bezierCurveTo() 建立三次方貝塞爾曲線
arc() 建立弧/曲線(用於建立圓形或部分圓)
arcTo() 建立兩切線之間的弧/曲線
isPointInPath() 若是指定的點位於當前路徑中,則返回 true,不然返回 false
轉換
方法 描述
scale() 縮放當前繪圖至更大或更小
rotate() 旋轉當前繪圖
translate() 從新映射畫布上的 (0,0) 位置
transform() 替換繪圖的當前轉換矩陣
setTransform() 將當前轉換重置爲單位矩陣。而後運行 transform()
文本
屬性 描述
font 設置或返回文本內容的當前字體屬性
textAlign 設置或返回文本內容的當前對齊方式
textBaseline 設置或返回在繪製文本時使用的當前文本基線
方法 描述
fillText() 在畫布上繪製「被填充的」文本
strokeText() 在畫布上繪製文本(無填充)
measureText() 返回包含指定文本寬度的對象
文本
屬性 描述
font 設置或返回文本內容的當前字體屬性
textAlign 設置或返回文本內容的當前對齊方式
textBaseline 設置或返回在繪製文本時使用的當前文本基線
方法 描述
fillText() 在畫布上繪製「被填充的」文本
strokeText() 在畫布上繪製文本(無填充)
measureText() 返回包含指定文本寬度的對象
像素操做
屬性 描述
width 返回 ImageData 對象的寬度
height 返回 ImageData 對象的高度
data 返回一個對象,其包含指定的 ImageData 對象的圖像數據
方法 描述
createImageData() 建立新的、空白的 ImageData 對象
getImageData() 返回 ImageData 對象,該對象爲畫布上指定的矩形複製像素數據
putImageData() 把圖像數據(從指定的 ImageData 對象)放回畫布上
合成
屬性 描述
globalAlpha 設置或返回繪圖的當前 alpha 或透明值
globalCompositeOperation 設置或返回新圖像如何繪製到已有的圖像上
其餘
方法 描述
save() 保存當前環境的狀態
restore() 返回以前保存過的路徑狀態和屬性
createEvent()
getContext()
toDataURL()
3、canvas的繪製API使用
上面咱們羅列了多有dom針對canvas的api接口,canvas的操做都是經過js控制的,咱們把全部接口作簡單分類,在頁面上預覽接口的做用:
1.建立畫布
canvas.getContext("2d") ,獲取canvas,調用此方法,傳入2d參數能夠獲得2d畫布
代碼以下:
<script type="text/javascript"> var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); </script>
操做canvas,這一步幾乎是準備工做,咱們如今返回了畫布,咱們下面作一些繪製操做
2.畫布直線路徑繪製處理
執行繪製操做的接口:
stroke() 繪製已定義的路徑
路徑繪製的樣式設置:
strokeStyle ="#000"設置或返回用於筆觸的顏色、漸變或模式
lineWidth =10設置或返回當前的線條寬度
路徑繪製的繪製點設置:
moveTo(x,y) 把路徑移動到畫布中的指定點,不建立線條
lineTo(x,) 添加一個新點,而後在畫布中建立從該點到最後指定點的線條
路徑繪製的開始和結束:
beginPath() 起始一條路徑,或重置當前路徑
closePath() 建立從當前點回到起始點的路徑
咱們在畫布進行一條直線的繪製,咱們設置好樣式和線寬,
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =5; context.strokeStyle ="#000"; context.beginPath(); context.moveTo(10,10) ; context.lineTo(10,50) ; context.closePath(); context.stroke();
咱們的操做是:
1.建立2d畫布
2.設置路徑的樣式(寬度和顏色)
3.開始路徑
4.繪製路徑開始座標和下一個鏈接座標
5.關閉路徑處理,而且繪製
咱們作一次作個線條繪製的實例:
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =5; context.strokeStyle ="#000"; context.beginPath(); context.moveTo(10,10) ; context.lineTo(10,50) ; context.lineTo(150,200) ; context.moveTo(101,10) ; context.lineTo(101,50) ; context.closePath(); context.stroke();
js的控制是同步處理,moveto和緊接着的lineto會分到一塊兒,再有moveto的操做會和他下面的lineto配合處理。
若是咱們去掉開始和結束路徑方法的而設置,看看效果:
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =5; context.strokeStyle ="#000"; context.moveTo(10,10) ; context.lineTo(10,50) ; context.lineTo(150,200) ; context.moveTo(101,10) ; context.lineTo(101,50) ; context.stroke();
發現和上面沒有區別,會不會由於分紅2組致使開始的move和最後line不能識別了,咱們留下一組路徑處理:
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =5; context.strokeStyle ="#000"; context.beginPath(); context.moveTo(10,10) ; context.lineTo(10,50) ; context.lineTo(150,200) ; context.closePath(); context.stroke();
在開始路徑和結束路徑處理的路徑繪製move和最後的line頭尾相連了,看來開始和結束路徑的方法有效必須是一組路徑處理。
咱們繪製的路徑可能多條,咱們看見折線的鏈接點是直角,咱們可能但願是圓形的,咱們可進行設置
lineCap="round" 設置或返回線條的結束端點樣式,
lineJoin ="round" 設置或返回兩條線相交時,所建立的拐角類型
咱們把路徑的端點和鏈接點都設置爲圓形
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =10; context.strokeStyle ="#000"; context.lineCap="round"; context.lineJoin="round"; context.moveTo(10,10) ; context.lineTo(10,50) ; context.lineTo(150,100) ; context.moveTo(101,10) ; context.lineTo(101,50) ; context.stroke();
咱們繪製的線條就是折線鏈接處和端點爲橢圓了。
3.畫布矩形和圓形繪製處理
經過上面線條繪製,咱們其實也能夠拼出來矩形,那太麻煩了,咱們不用想,api確定會提供這種矩形繪製處理
咱們繪製矩形:
rect(x,y,width,height) 繪製矩形(無填充)
繪製的處理就是描邊的處理,相似div邊框的設置,固然還有填充的處理,就是div背景設置
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =10; context.strokeStyle ="#000"; context.rect(100,100,200,200); context.stroke();
api還爲咱們提供了集成方法,建立矩形和繪製進行一塊兒處理:
strokeRect(x,y,width,height) 繪製矩形(無填充)
ar canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =10; context.strokeStyle ="#000"; context.strokeRect(100,100,200,200);
4各參數,分別是橫座標,縱座標和寬度高度值
咱們繪製圓形:
arc(x,y,r,sangle,eangle,counterclockwise) 建立弧/曲線(用於建立圓形或部分圓)
參數表示:圓心橫從座標,開始弧度,結束弧度,是順時針(true)仍是逆時針(false)默認順時針
要用弧度參數,2pi=360度
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =10; context.strokeStyle ="#000"; context.arc(100,100,50,0,2*Math.PI) context.stroke();
在js中,獲取pi值是經過Math對象的PI屬性獲取
咱們可能要繪製半圓:
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =10; context.strokeStyle ="#000"; context.arc(100,100,50,0,1*Math.PI) context.stroke();
如今是順時針繪製,咱們在繪製90度的圓弧,就知道繪製圓形的開始座標位置了
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =10; context.strokeStyle ="#000"; context.arc(100,100,50,0,Math.PI/2) context.stroke();
得出圓心的水平右側的座標就是開始點
咱們想要獲得閉合的圓弧,咱們有開始和結束路徑的方法,咱們知道使用後會首尾鏈接,咱們會致收尾鏈接的圓弧:
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =10; context.strokeStyle ="#000"; context.beginPath(); context.arc(100,100,50,0,Math.PI) context.closePath(); context.stroke();
咱們成功繪製出相連的圓弧。
4.畫布弧線繪製處理
咱們在使用moveto和lineto繪製線條時,可能但願鏈接位置是圓弧,和操場的跑道同樣,
arcTo(x1,y1,x2,y2,r) 建立兩切線之間的弧/曲線
參數x1 y1表示圓弧起點,x2 y2 表示結束,r爲半徑
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =10; context.strokeStyle ="#000"; context.moveTo(20,20); // 建立開始點 context.lineTo(100,20); // 建立水平線 context.arcTo(150,20,150,70,50); // 建立弧 context.lineTo(150,120); // 建立垂直線 context.stroke();
咱們其實路徑是20 20,下一步鏈接到100 20,而後開始繪製弧形,鏈接到150 20繪製爲半徑爲50的弧度,而後鏈接到150 120繪製爲半徑爲50的弧度,最後鏈接到150 120繪製爲半徑爲50的弧度;
咱們得出,調用一次arcto就會出現三個弧線。
5.畫布貝塞爾曲線繪製處理
咱們在ps裏面用鋼筆工具繪製路徑的時候,點好起點和終點。中間會出現2個控制線,調節中間的弧形,貝塞爾就是這個處理
相關介紹:咱們在css3的過渡效果和動畫效果都是貝塞爾的處理,執行效果函數設置。那裏面只有2個座標,其實貝塞爾包含4個座標,開始座標,結束座標,2個控制座標。css裏面的開始和結束已經被固定了,咱們拿過渡效果舉例,他的起始座標就是開始的css某個屬性效果設置,結束座標就是變化結束屬性效果的設置,css裏面設置成0,0和1,1做爲起始和終止座標值,因此只須要設置控2制點座標就行了,介於0和1之間。可是咱們在畫布上4個座標都要設置,他的位置是自定義的,起始和終點。
quadraticCurveTo(kx1,ky1,kx2,ky2,ex,ey) 建立二次貝塞爾曲線
三組參數,前2組是控制點座標,最後是結束點,咱們的起始點事經過moveto建立的。
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =10; context.strokeStyle ="#000"; context.moveTo(20,20); // 建立開始點 context.bezierCurveTo(20,100,200,100,200,20) context.stroke();
6.畫布文字繪製處理
strokeText(text,x,y) 在畫布上繪製文本(無填充)
參數意義,第一個表示要繪製的文本內容,x,y表示繪製文本的起始座標
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.lineWidth =2; context.strokeStyle ="#000"; context.strokeText("2",200,200) context.stroke();
我css同樣還有文本對齊方式和大小,什麼字的設置,你們能夠對着api添加
7.畫布填充效果處理
填充和繪製的區別就是描邊仍是背景,咱們對照上面的處理做出對已填充繪製
fill() 填充當前繪圖(路徑)
fillStyle 設置或返回用於填充繪畫的顏色、漸變或模式
fillRect() 繪製「被填充」的矩形
arc() 建立弧/曲線(用於建立圓形或部分圓)
fillText() 在畫布上繪製「被填充的」文本
填充矩形:
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#ffa"; context.fillRect(100,100,200,200);
填充圓形:
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#ffa"; context.arc(100,100,50,0,2*Math.PI); context.fill();
填充文本:
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#ffa"; context.fillText("2",200,200)
各個方法參數幾乎不變,不過是繪製換成了fill。
8.畫布繪製圖片
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); var img=new Image(); img.src="calend.jpg"; img.onload=function(){context.drawImage(img,100,100,30,30);}
繪製圖片的第一個參數是img對象,下面依次是顯示的座標和寬高設置;
咱們經過Image()能夠建立img對象,賦值src屬性讓圖片有資源,load事件保證圖片加載完成後執行繪製
除了繪製圖片外,第一個參數img也能夠用video對象,把video視頻正在播放的圖片繪製到canvas畫布上。
4、canvas的高級API使用
針對其餘api的使用,咱們結合事件處理。
1.清除畫布操做
咱們給頁面添加一個清空按鈕,點擊執行清除操做,
咱們先在畫布繪製一些矩形和圓形還有線條,添加清除按鈕,在js代碼獲取按鈕:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} #myCanvas{background:#ccc;} </style> <title>demo</title> </head> <body> <canvas id="myCanvas" height="500" width="500"></canvas> <input type="button" value="清除" id="clear"> </body> <script type="text/javascript"> window.onload=function(){ var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); var clear=document.getElementById("clear"); context.lineWidth =5; context.strokeStyle ="#000"; context.strokeRect(100,100,200,200); context.arc(300,300,50,0,2*Math.PI); context.moveTo(10,10) ; context.lineTo(10,50) ; context.stroke(); }; </script> </html> <!-- -->
canvas的api提供的清除操做接口:
clearRect(x,y,width,height) 在給定的矩形內清除指定的像素(清除位置和清除的寬高);
咱們點擊按鈕整個畫布清除,因此位置是0,0,寬高就是畫布寬高,咱們加入以下事件處理代碼;
clearhandle.onclick=function(){ context.clearRect(0,0,canvas.width,canvas.height) };
2.畫布變換處理
1.對畫布作縮放處理:
scale(calewidth,scaleheight) 縮放當前繪圖至更大或更小
對水平設置縮放比例,對垂直設置縮放比例
咱們看到有縮放,旋轉,移動等,和咱們css3提供的2d變換處理幾乎同樣,咱們分別測試,
咱們接着上面代碼加入縮放處理:
window.onload=function(){ var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); var clearhandle=document.getElementById("clear"); context.lineWidth =5; context.strokeStyle ="#000"; context.scale(0.8,1.2); context.strokeRect(100,100,200,200); context.arc(300,300,50,0,2*Math.PI); context.moveTo(10,10) ; context.lineTo(10,50) ; context.stroke(); clearhandle.onclick=function(){ context.clearRect(0,0,canvas.width,canvas.height) }; };
咱們設置縮放後,明顯對後面繪製的圖形形成了影響。
2.對畫布作旋轉處理:
rotate(angle) 旋轉當前繪圖,弧度單位
咱們把縮放代碼替換爲旋轉:
context.rotate(Math.PI/4);
2.對畫布作移動處理:
translate(x,y) 從新映射畫布上的 (0,0) 位置
context.translate(100,100);
3.畫布狀態的保存和釋放
save() 保存當前環境的狀態
restore() 返回以前保存過的路徑狀態和屬性
調用save就會保存以前的畫布狀態,調用restore釋放以前狀態。
咱們爲啥要保存處理,咱們上面使用了變換的操做,知道那種操做都是對畫布的破壞性處理,只要使用了變化的而處理,後面繪製都會受到變換後的影響,因此咱們在變化處理前進行畫布爲破壞前保存,而後作破壞處理,處理後,再釋放到破壞前畫布狀態,咱們就能夠保證變換後的處理不受破壞影響。
咱們要這樣處理一段繪製:
正常畫布繪製一個圓
畫布移動100px後,繪製一個矩形
正常畫布繪製一個矩形,位置大小同2,可是2處理作了移動,因此正常不會覆蓋
咱們不用save和restore的處理看效果:
window.onload=function(){ var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); var clearhandle=document.getElementById("clear"); context.lineWidth =5; context.strokeStyle ="#000"; context.arc(300,300,50,0,2*Math.PI); context.translate(100,100); context.strokeRect(100,100,200,200); context.strokeRect(100,100,200,200); context.stroke(); clearhandle.onclick=function(){ context.clearRect(0,0,canvas.width,canvas.height) }; };
只有一個矩形,這是不正確的,咱們此次在變換前save,在繪製第二個矩形restore
var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); var clearhandle=document.getElementById("clear"); context.lineWidth =5; context.strokeStyle ="#000"; context.arc(300,300,50,0,2*Math.PI); context.save(); context.translate(100,100); context.strokeRect(100,100,200,200); context.restore(); context.strokeRect(100,100,200,200); context.stroke(); clearhandle.onclick=function(){ context.clearRect(0,0,canvas.width,canvas.height) };
三個形狀出現,咱們也得出這一組方法就是爲了對破壞前畫布存儲的處理。
4.畫布轉爲圖片
既然是畫布,那就是繪圖,若是隻是看不能用的圖,讓人是寒心的,咱們隊畫好的圖
1.顯示在html頁面裏
2.後臺接收,保存
canvas.toDataURL("image/png") 轉爲圖片,以base64的形式保存
咱們能夠看到,這個處理是基於canvas的不是基於畫布,這是要注意的,咱們傳入的參數指定生成圖片,格式是png,支持最好,這個方法返回的是一個圖片地址,咱們經過img的src屬性能夠看見。
咱們在頁面加入生成圖片按鈕,加入一個img標籤,代碼以下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} #myCanvas{background:#ccc;} </style> <title>demo</title> </head> <body> <canvas id="myCanvas" height="500" width="500"></canvas> <input type="button" value="清除" id="clear"> <input type="button" value="生成圖片" id="newimg"> <img src="" alt="我是canvas生成的圖片" id="hasimg"> </body> <script type="text/javascript"> window.onload=function(){ var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); var clearhandle=document.getElementById("clear"); context.lineWidth =5; context.strokeStyle ="#000"; context.arc(300,300,50,0,2*Math.PI); context.save(); context.translate(100,100); context.strokeRect(100,100,200,200); context.restore(); context.strokeRect(100,100,200,200); context.stroke(); clearhandle.onclick=function(){ context.clearRect(0,0,canvas.width,canvas.height) }; var newimghandle=document.getElementById("newimg"); var hasimg=document.getElementById("hasimg"); newimghandle.onclick=function(){ var imgsrc=canvas.toDataURL("image/png"); hasimg.src=imgsrc; }; }; </script> </html>
5.其餘說明
固然還有陰影和漸變的設置和處理,你們能夠看一看,不在實例處理。
5、canvas的實用API使用
咱們也能夠大概看出,沒有介紹的api,我先放在下面:
getImageData() 返回 ImageData 對象,該對象爲畫布上指定的矩形複製像素數據
putImageData() 把圖像數據(從指定的 ImageData 對象)放回畫布上
globalCompositeOperation 設置或返回新圖像如何繪製到已有的圖像上
這幾個就比較厲害了,一些交互實例中,這三個api無疑是大拿級別的,這些的使用咱們必須結合處理,咱們一次實例演示。
咱們放棄上面全部的代碼,下面針對這些屬性,從新繪製實例處理:
1.靜態結構搭建
咱們建立一個基本結構,總體代碼以下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} </style> <title>demo</title> </head> <body> <canvas id="myCanvas" height="200" width="300"></canvas> </body> <script type="text/javascript"> window.onload=function(){ var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#000" context.fillRect(0,0,300,200); }; </script> </html>
咱們建立canvas,獲取canvas,返回畫布,而且填充黑色矩形,整個覆蓋畫布。
2.鼠標在畫布上按下後移動時繪製圓形
這個操做相似於咱們之前作的拖拽效果,也要設置狀態變量,咱們作出組合事件的處理,代碼以下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} </style> <title>demo</title> </head> <body> <canvas id="myCanvas" height="200" width="300"></canvas> <div id="posi"></div> </body> <script type="text/javascript"> window.onload=function(){ var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#000" context.fillRect(0,0,300,200); var posi = document.getElementById("posi"); //獲取canvas var isdown=false; canvas.onmousedown=function(event){ isdown=true; }; canvas.onmousemove=function(event){ if(isdown){ posi.innerHTML="座標x:"+event.layerX+";"+"座標u:"+event.layerY; }; }; canvas.onmouseup=function(event){ if(isdown){ isdown=false; }; }; }; </script> </html>
咱們在canvas進行按下移動操做時,咱們在下面的div輸出了移動事件對象的座標值,咱們爲什麼要獲取這些座標值?這個座標值就是咱們事件繪製圓形的圓心座標。
咱們繪製的圓形:圓心就是事件對象的座標值,半徑自定義,弧度0~2pi
咱們把後繪製與黑色矩形分分開,把圓形顏色設置爲白色;咱們下面在移動事件處理加入繪製處理,代碼以下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} </style> <title>demo</title> </head> <body> <canvas id="myCanvas" height="200" width="300"></canvas> <div id="posi"></div> </body> <script type="text/javascript"> window.onload=function(){ var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#000"; context.fillRect(0,0,300,200); var posi = document.getElementById("posi"); var isdown=false; canvas.onmousedown=function(event){ isdown=true; }; context.fillStyle="#fff"; canvas.onmousemove=function(event){ if(isdown){ posi.innerHTML="座標x:"+event.layerX+";"+"座標u:"+event.layerY; context.arc(event.layerX,event.layerY,5,0,2*Math.PI); context.fill(); }; }; canvas.onmouseup=function(event){ if(isdown){ isdown=false; }; }; }; </script> </html>
咱們按下移動時,畫布會不斷繪製出白色圓形,咱們得出,後繪製的圖形會覆蓋在原始繪製圖形上面。
3.畫布後繪製圖形與原始繪製圖形相交處理屬性
globalCompositeOperation 設置或返回新圖像如何繪製到已有的圖像上
咱們能夠把一開始就在畫布上的繪製處理叫作目標對象,後事件添加繪製叫作源對象。
咱們看看這個屬性的參數設置:
source-over 默認值,後繪製覆蓋已有,咱們上面已經驗證
destination-out 後繪製與已有繪製相交部分透明
其餘我就不介紹了,你們看具體api
咱們把globalCompositeOperation ="destination-out ", 處理,
咱們代碼修改添加以下:
window.onload=function(){ var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#000"; context.fillRect(0,0,300,200); var posi = document.getElementById("posi"); var isdown=false; canvas.onmousedown=function(event){ isdown=true; }; context.fillStyle="#fff"; context.globalCompositeOperation ="source-out ", canvas.onmousemove=function(event){ if(isdown){ posi.innerHTML="座標x:"+event.layerX+";"+"座標u:"+event.layerY; context.arc(event.layerX,event.layerY,5,0,2*Math.PI); context.fill(); }; }; canvas.onmouseup=function(event){ if(isdown){ isdown=false; }; }; };
咱們看不出來什麼,透明下面看見也是白色,咱們html結構進行調整:
咱們把canvas放在一個父容器div內部,與canvas同級添加一個div,都相對父容器定位,canvas的層深大於兄弟元素,蓋住操做:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} .box{position: relative;; width: 300px;height: 200px;} .box .chi{ position: absolute;; left: 0px;top: 0px;width: 300px;height: 200px;line-height: 200px;text-align: center;font-size: 50px;z-index: 9;} .box #myCanvas{position: absolute;; left: 0px;top: 0px;z-index: 99;cursor: pointer;} </style> <title>demo</title> </head> <body> <div class="box"> <canvas id="myCanvas" height="200" width="300"></canvas> <div class="chi">一等獎</div> </div> <div id="posi"></div> </body> <script type="text/javascript"> window.onload=function(){ var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#000"; context.fillRect(0,0,300,200); var posi = document.getElementById("posi"); var isdown=false; canvas.onmousedown=function(event){ isdown=true; }; context.fillStyle="#fff"; context.globalCompositeOperation ="destination-out"; canvas.onmousemove=function(event){ if(isdown){ posi.innerHTML="座標x:"+event.layerX+";"+"座標u:"+event.layerY; context.arc(event.layerX,event.layerY,5,0,2*Math.PI); context.fill(); }; }; canvas.onmouseup=function(event){ if(isdown){ isdown=false; }; }; }; </script> </html>
canvas在div存放「一等獎」的上面,咱們在canvas上按下移動時,繪製內容與已有繪製相交變爲透明,canvas下面的元素就會顯示出來,全部咱們 就能夠看見canvas下面的div了。
4.生成隨機文字
咱們經過上面繪製相交屬性設置爲透明,咱們能夠看到下面的內容,咱們下面div的文字若是不是固定,是隨機出現的是否是就很相似刮刮卡了?
咱們使用js提供的下面處理:
Math.random() 生成0-1之間隨機數
Math.floor() 向下獲取整數
我要獲得0-3之間的整數,咱們怎麼處理?
有個規律,獲取幾到幾,就把Math.random() *n,而後向下取整,代碼以下:
alert(Math.floor(Math.random()*4))
咱們n此刷新測試,發現彈出數字是0 1 2 3,知足咱們的要求,咱們獎項多個(一等獎,二等獎,三等獎,未中獎);
咱們存入數組,而後alert輸出:
var con=['一等獎','二等獎','三等獎','未中獎']; alert(con[Math.floor(Math.random()*4)]);
咱們把alert的內容賦值給div就行了,這樣咱們每次就出隨機賦值,代碼修改以下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} .box{position: relative;; width: 300px;height: 200px;} .box .chi{ position: absolute;; left: 0px;top: 0px;width: 300px;height: 200px;line-height: 200px;text-align: center;font-size: 50px;z-index: 9;} .box #myCanvas{position: absolute;; left: 0px;top: 0px;z-index: 99;cursor: pointer;} </style> <title>demo</title> </head> <body> <div class="box"> <canvas id="myCanvas" height="200" width="300"></canvas> <div class="chi" id="conb"></div> </div> <div id="posi"></div> </body> <script type="text/javascript"> window.onload=function(){ var con=['一等獎','二等獎','三等獎','未中獎']; var conb= document.getElementById("conb"); conb.innerHTML=con[Math.floor(Math.random()*4)]; var arcr=10; var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#000"; context.fillRect(0,0,300,200); var posi = document.getElementById("posi"); var isdown=false; canvas.onmousedown=function(event){ isdown=true; }; context.fillStyle="#fff"; context.globalCompositeOperation ="destination-out"; canvas.onmousemove=function(event){ if(isdown){ posi.innerHTML="座標x:"+event.layerX+";"+"座標u:"+event.layerY; context.arc(event.layerX,event.layerY,arcr,0,2*Math.PI); context.fill(); }; }; canvas.onmouseup=function(event){ if(isdown){ isdown=false; }; }; }; </script> </html>
咱們每次刷新後颳去畫布,咱們把移動繪製圓形的半徑提出,用自定義變量處理,方便更改。
4.獲取畫布內容的rgba值
咱們在颳去時,確定不可能所有刮完,在看到文字時就中止了颳去,一樣也會alert提示我颳去出來看見的內容。
咱們作個假設,咱們在颳去時,黑色區域愈來愈小,若是咱們能夠判斷出黑色區域佔總區域比例,當不足20%應該會看見文字,彈出獎項值。
getImageData(x,y,w,h) 返回 ImageData 對象,該對象爲畫布上指定的矩形複製像素數據
返回圖片數據對象,咱們調用
getImageData(x,y,w,h) .data 屬性能夠返回全部像素分析,方法會把畫布按1px分解分析,咱們的畫布是300*200.那麼就會分析到300*200個結果。
咱們輸出調用data屬性後的長度是否是300*200=60000;
var imgdata=context.getImageData(0,0,300,200); alert(imgdata.data.length)
返回分析數組長度是240000;是猜測的4倍,咱們查看api可知,針對每一像素,都會進行RGBA的分析,咱們實例是60000像素,那麼1px返回4個值,240000是對的。
咱們能夠把圖片數據對象的數據結果每4個當作一組,作出單位像素顏色的判斷分析,咱們的判斷代碼應該放在擡起的事件內部,判斷剩餘黑色比例,也就是數據對象的數據結果rgba爲0 0 0 255在總數組的出現比例。
咱們在擡起事件,把一維結果數組先每4個一組,造成一個按rgba爲基準的新數組(分析數組,按照rgba劃分獲得):
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} .box{position: relative;; width: 300px;height: 200px;} .box .chi{ position: absolute;; left: 0px;top: 0px;width: 300px;height: 200px;line-height: 200px;text-align: center;font-size: 50px;z-index: 9;} .box #myCanvas{position: absolute;; left: 0px;top: 0px;z-index: 99;cursor: pointer;} </style> <title>demo</title> </head> <body> <div class="box"> <canvas id="myCanvas" height="200" width="300"></canvas> <div class="chi" id="conb"></div> </div> <div id="posi"></div> </body> <script type="text/javascript"> window.onload=function(){ var con=['一等獎','二等獎','三等獎','未中獎']; var conb= document.getElementById("conb"); conb.innerHTML=con[Math.floor(Math.random()*4)]; var arcr=10; var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#000"; context.fillRect(0,0,300,200); var posi = document.getElementById("posi"); var isdown=false; canvas.onmousedown=function(event){ isdown=true; }; context.fillStyle="#fff"; context.globalCompositeOperation ="destination-out"; canvas.onmousemove=function(event){ if(isdown){ posi.innerHTML="座標x:"+event.layerX+";"+"座標u:"+event.layerY; context.arc(event.layerX,event.layerY,arcr,0,2*Math.PI); context.fill(); }; }; canvas.onmouseup=function(event){ if(isdown){ isdown=false; var imgdata=context.getImageData(0,0,300,200); var len=imgdata.data.length; var rgbaarr=[]; for(var i=0;i<len;i+=4){ var temp=imgdata.data[i]+" "+imgdata.data[i+1]+" "+imgdata.data[i+2]+" "+imgdata.data[i+3]; rgbaarr.push(temp); }; console.log(rgbaarr); }; }; }; </script> </html>
咱們把返回的數組按照rgba4個一組,咱們輸出新數組,獲得了分析數組。
這時候咱們只要判斷出分析數組中出現,「0 0 0 255」的個數和佔總像素個數(60000)的比例。
咱們建立一個方法,返回分析數組中出現0 0 0 255的個數
function percent(obj,arr){ var count=0; for(var i=0;i<arr.length;i++){ if(arr[i]==obj){count+=1;} }; return count; };
obj表示0 0 0 255,arr就是分析後數組;
咱們返回比例,在擡起事件中,代碼以下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} .box{position: relative;; width: 300px;height: 200px;} .box .chi{ position: absolute;; left: 0px;top: 0px;width: 300px;height: 200px;line-height: 200px;text-align: center;font-size: 50px;z-index: 9;} .box #myCanvas{position: absolute;; left: 0px;top: 0px;z-index: 99;cursor: pointer;} </style> <title>demo</title> </head> <body> <div class="box"> <canvas id="myCanvas" height="200" width="300"></canvas> <div class="chi" id="conb"></div> </div> <div id="posi"></div> </body> <script type="text/javascript"> window.onload=function(){ var con=['一等獎','二等獎','三等獎','未中獎']; var conb= document.getElementById("conb"); conb.innerHTML=con[Math.floor(Math.random()*4)]; var arcr=10; var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#000"; context.fillRect(0,0,300,200); var posi = document.getElementById("posi"); var isdown=false; canvas.onmousedown=function(event){ isdown=true; }; context.fillStyle="#fff"; context.globalCompositeOperation ="destination-out"; canvas.onmousemove=function(event){ if(isdown){ posi.innerHTML="座標x:"+event.layerX+";"+"座標u:"+event.layerY; context.arc(event.layerX,event.layerY,arcr,0,2*Math.PI); context.fill(); }; }; canvas.onmouseup=function(event){ if(isdown){ isdown=false; var imgdata=context.getImageData(0,0,300,200); var len=imgdata.data.length; var rgbaarr=[]; for(var i=0;i<len;i+=4){ var temp=imgdata.data[i]+" "+imgdata.data[i+1]+" "+imgdata.data[i+2]+" "+imgdata.data[i+3]; rgbaarr.push(temp); }; alert(percent("0 0 0 255",rgbaarr)/rgbaarr.length); }; }; function percent(obj,arr){ var count=0; for(var i=0;i<arr.length;i++){ if(arr[i]==obj){count+=1;} }; return count; }; }; </script> </html>
咱們在擡起事件調用方法,除以總個數,獲取了黑色區域所佔百分比了。咱們的參考比例是不足20%。也就是黑色不足0.2,咱們在擡起事件加入這個比例判斷,若是知足彈出獎項內容。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <style type="text/css"> *{ margin:0; padding:0;} .box{position: relative;; width: 300px;height: 200px;} .box .chi{ position: absolute;; left: 0px;top: 0px;width: 300px;height: 200px;line-height: 200px;text-align: center;font-size: 50px;z-index: 9;} .box #myCanvas{position: absolute;; left: 0px;top: 0px;z-index: 99;cursor: pointer;} </style> <title>demo</title> </head> <body> <div class="box"> <canvas id="myCanvas" height="200" width="300"></canvas> <div class="chi" id="conb"></div> </div> <div id="posi"></div> </body> <script type="text/javascript"> window.onload=function(){ var con=['一等獎','二等獎','三等獎','未中獎']; var conb= document.getElementById("conb"); conb.innerHTML=con[Math.floor(Math.random()*4)]; var arcr=10; var canvas = document.getElementById("myCanvas"); //獲取canvas var context = canvas.getContext('2d'); //canvas追加2d畫圖anvas = document.getElementById("canvas"); context.fillStyle="#000"; context.fillRect(0,0,300,200); var posi = document.getElementById("posi"); var isdown=false; canvas.onmousedown=function(event){ isdown=true; }; context.fillStyle="#fff"; context.globalCompositeOperation ="destination-out"; canvas.onmousemove=function(event){ if(isdown){ posi.innerHTML="座標x:"+event.layerX+";"+"座標u:"+event.layerY; context.arc(event.layerX,event.layerY,arcr,0,2*Math.PI); context.fill(); }; }; canvas.onmouseup=function(event){ if(isdown){ isdown=false; var imgdata=context.getImageData(0,0,300,200); var len=imgdata.data.length; var rgbaarr=[]; for(var i=0;i<len;i+=4){ var temp=imgdata.data[i]+" "+imgdata.data[i+1]+" "+imgdata.data[i+2]+" "+imgdata.data[i+3]; rgbaarr.push(temp); }; if(percent("0 0 0 255",rgbaarr)/rgbaarr.length<0.2){ alert(con[Math.floor(Math.random()*4)]); }; }; }; function percent(obj,arr){ var count=0; for(var i=0;i<arr.length;i++){ if(arr[i]==obj){count+=1;} }; return count; }; }; </script> </html>
咱們颳去畫布,當剩下黑色不足0.2,咱們就看到彈出了獎項,這個比例是能夠隨便設置的。
6、canvas總結
咱們經過getImageData(x,y,w,h) 獲取選取區域圖片數據對象,返回他的數據屬性,獲取選取區域rgba具體分析值,咱們作出判斷就能夠實現動態彈出的處理。
經過globalCompositeOperation ="destination-out ", 處理,相交透明看到下面的文字。
這2個api就是刮刮卡效果的重要處理接口。
關於刮刮效果的一個實例處理:http://www.oschina.net/code/snippet_2352644_49815
其餘canvas的實例處理:http://www.oschina.net/code/snippet_2352644_49814