這篇是canvas API系列的首尾之作,這篇以后,所有的canvas的屬性和方法就將完了,哦,不對,應該是大部分常用的,還有部分不常用的屬性和方法,因為種種原因,就不介紹了,后期的重點就是多寫一點canvas的實踐小實例了,恩,我覺得這才是最實用的,俗話說一例抵千言啊,廢話不多說,我們來看看剩下的一些屬性和方法吧!
1、createPattern
createPattern(image,"repeat|repeat-x|repeat-y|no-repeat") 在指定的方向上重復指定的元素
參數: image指實用的圖片,畫布或者是視頻對象 第二個參數表示重復的方式
看這后面的參數,很容易想到css中的background-repeat,第一個參數我得說一下,這里跟background不一樣,不是引用的圖片地址,而是一個圖片對象,這里特別注意,我們分別看一下這些重復方式的表現:
var aImg = new Image(); aImg.src = '4.jpg'; aImg.onload = function(){ draw(this); } function draw(obj){ //這里為了演示方便,把其他的先注釋 //var bg = ctx.createPattern(obj,"repeat"); //var bg = ctx.createPattern(obj,"repeat-x"); //var bg = ctx.createPattern(obj,"repeat-y"); var bg = ctx.createPattern(obj,"no-repeat"); ctx.fillStyle = bg; ctx.fillRect(0,0,400,400); }
恩,跟css的background-repeat的效果是一樣的,那就好理解了,但是canvas是沒有background-position的,恩,這個效果就是這樣,沒什么好講的!
具體效果看這里 —— canvas 背景重復
2、gloableCompositeOperation
gloableCompositeOperation() 設置或返回新圖像如何繪制到已有的圖像上
參數:
source-over 默認,在目標圖像上顯示源圖像。
source-atop 在目標圖像頂部顯示源圖像。源圖像位於目標圖像之外的部分是不可見的。
source-in 在目標圖像中顯示源圖像。只有目標圖像內的源圖像部分會顯示,目標圖像是透明的。
source-out 在目標圖像之外顯示源圖像。只會顯示目標圖像之外源圖像部分,目標圖像是透明的。
destination-over 在源圖像上方顯示目標圖像。
destination-atop 在源圖像頂部顯示目標圖像。源圖像之外的目標圖像部分不會被顯示。
destination-in 在源圖像中顯示目標圖像。只有源圖像內的目標圖像部分會被顯示,源圖像是透明的。
destination-out 在源圖像外顯示目標圖像。只有源圖像外的目標圖像部分會被顯示,源圖像是透明的。
lighter 顯示源圖像 + 目標圖像,即相交部分圖形先后填充來增加亮度
copy 顯示源圖像。忽略目標圖像,即只顯示源圖像
xor 使用異或操作對源圖像與目標圖像進行組合,即相交部分為透明
不常用的:
multiply 源圖像的像素乘以目標圖像的像素
screen
overlay
darken 加深,相交部分圖形先后填充來降低亮度
lighten 加亮,相交部分圖形先后填充來增加亮度
color-dodge 將底層調到頂層,即將目標圖像調到源圖像上方
color-burn 將底層調到頂層,然后反轉
hard-light 將底層調到頂層,然后 multiply效果與screen疊加
soft-light
difference
exclusion
hue
saturation
color
luminosity
由於英文不好,部分的常用的參數的意思不太好解釋,為了不誤導大家,我就不翻譯了,如果有英文比較好的,看看這里 gloableCompositeOperation參數解釋 ,要是能比較清楚的翻譯的話,希望你能把翻譯的意思告訴我,不勝感謝,英語是硬傷啊!不過后面的運行結果我會給到大家參考!
參數很多,我們先看看常用的,前面八個很好理解,就是一個反的,首先我們需要理解,什么是目標圖形?什么是源圖形?
目標圖像 = 您已經放置在畫布上的繪圖;源圖像 = 您打算放置到畫布上的繪圖。這是官方的解釋,如果你對這個解釋不理解,我們可以這么理解,就是先畫的圖像是目標圖形,后畫的圖像是源圖像,例如:
//目標圖像 ctx.fillStyle="red"; ctx.fillRect(20,20,75,50); ctx.globalCompositeOperation="source-over"; //源圖像 ctx.fillStyle="blue"; ctx.fillRect(50,50,75,50);
當然這個gloableCompositeOperation的位置不是固定的,可以放到目標圖像前面,也可以放到目標圖像后面,但是不能放到源圖像后面(你們懂的),參數意思如不好理解,看下圖,看看是什么表現:
var arr = ['source-over','source-atop','source-in','source-out','destination-over','destination-atop','destination-in','destination-out','lighter','copy','xor','multiply','screen','overlay','darken','lighten','color-dodge','color-burn','hard-light','soft-light','difference','exclusion','hue','saturation','color','luminosity']; for(var i=0;i<arr.length;i++){ document.write("<div id='p_" + i + "' style='float:left;'>" + arr[i] + ":<br>"); var canvas = document.createElement("canvas"); canvas.width = 120; canvas.height = 100; canvas.style.border = "1px solid #000"; canvas.style.marginRight = '10px'; document.getElementById("p_" + i).appendChild(canvas); var ctx = canvas.getContext("2d"); ctx.fillStyle="red"; ctx.fillRect(10,10,50,50); ctx.globalCompositeOperation=arr[i]; ctx.beginPath(); ctx.fillStyle="green"; ctx.fillRect(30,30,50,50); ctx.fill(); document.write("</div>"); }
紅與綠
紅與藍
具體效果你也可以看這里 —— canvas圖形組合模式
里面的代碼我故意把canvas的代碼留在上面,方便你們查看,不知道你看到這些參數有什么感想,我的第一感覺就是有些熟悉比clip好用,也讓我第一時間想到了這一個效果:
ctx.fillStyle="red"; ctx.arc(150,150,100,0,360*Math.PI/180,false); ctx.fill(); ctx.globalCompositeOperation="xor"; ctx.beginPath(); ctx.arc(150,150,80,0,360*Math.PI/180,false); ctx.fill();
如果配合前面的扇形方法,很容易做一個圓形進度條什么的,當然,還有很多屬性可以有大的作用,比如說裁切一個圖形,發揮的發達的大腦吧,這里我就不演示了
3、setLineDash
setLineDash(arr) 在畫布上畫一條虛線
參數:arr 表示的是一個數組集合,里面的參數可以有多個,這里面的參數很有意思,舉個栗子說明:
ctx.beginPath(); ctx.moveTo(0,100); ctx.lineTo(400, 100); ctx.setLineDash([10,20]); ctx.stroke();
對比代碼看圖,如果有2個參數,則第一個參數表示虛線的線寬,第二個參數表示虛線的線與線的距離,后面一直循環
如果是3個參數呢?
ctx.beginPath(); ctx.moveTo(0,100); ctx.lineTo(400, 100); ctx.setLineDash([10,20,30]); ctx.stroke();
此時會這樣,第一條線長為10,然后間距為20,第2條線長為30,然后間距為10,第3條線長20,然后間距為30,到處為一個循環,后面重復
那么4個參數就好理解了,
ctx.beginPath(); ctx.moveTo(0,100); ctx.lineTo(400, 100); ctx.setLineDash([10,20,30,40]); ctx.stroke();
規律和上面的一樣,只是循環的長度要長一些,更多參數的規則也是這樣的,那么一個參數是否有效呢
ctx.beginPath(); ctx.moveTo(0,100); ctx.lineTo(400, 100); ctx.setLineDash([10]); ctx.stroke();
顯然是有效的,此時線寬為10,間距為10,這就是華麗的分割線的做法
它還有一個兄弟用法,這個是設置虛線,那么就會有一個獲取虛線
getLineDash() 獲取當前虛線的樣式
它沒有參數,它得到的結果就是設置虛線的線寬數組arr,我們看一下怎么用:
ctx.beginPath(); ctx.moveTo(0,100); ctx.lineTo(400, 100); ctx.setLineDash([10]); var txt = ctx.getLineDash(); ctx.stroke(); ctx.fillStyle = 'red'; ctx.font = "30px Arial"; ctx.fillText(txt,180,140);
ctx.beginPath(); ctx.moveTo(0,100); ctx.lineTo(400, 100); ctx.setLineDash([10,20]); var txt = ctx.getLineDash(); ctx.stroke(); ctx.fillStyle = 'red'; ctx.font = "30px Arial"; ctx.fillText(txt,180,140);
從這兩組圖可以看出,當只有一個參數數,會默認為2個一樣的參數
4、isPointInPath
isPointInPath(x,y) 指定點是否在路徑區域中,如果在則返回true,不在則返回false
參數: x,y表示指定的坐標點
舉個栗子:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.fillStyle = 'red'; ctx.rect(50,50,100,100); ctx.fill(); canvas.onclick = function(ev){ var ev = ev || event; ctx.clearRect(200,0,200,200); var l = ev.clientX - canvas.offsetLeft; var t = ev.clientY - canvas.offsetTop; if(ctx.isPointInPath(l,t)){ ctx.font = "40px Arial"; ctx.fillText((l+','+t),200,120); } }
看看這個gif圖,當點擊紅色區域時,我將坐標打印出來,如果點擊的地方不在紅色區域,則不顯示坐標,具體效果看這里 —— canvas判斷是否在路徑區域
這里有一點需要注意,就是在繪制矩形時,不能用fillRect或strokeRect,為什么呢?因為這里判斷是是否在指定的路徑中,而fillRect或strokeRect此時已經不是路徑了,而是變成了填充過的圖形,所以這里必須先用Rect()定義一下路徑,再填充,這樣才能回去到指定圖形的路徑,此點須知!
還有一個方法:
isPointInStroke(x,y) 指定點是否在路徑中,如果在則返回true,不在則返回false
此方法跟上面的方法很相似,不同點在於,isPointInPath是在一個區域中,不管是用fill還是stroke,但是isPointInStroke只能用stroke填充,且指定的區域是在線框上,看下面的例子:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.strokeStyle = 'red'; ctx.lineWidth = 5; ctx.rect(50,50,100,100); ctx.stroke(); canvas.onclick = function(ev){ var ev = ev || event; ctx.clearRect(200,0,200,200); var l = ev.clientX - canvas.offsetLeft; var t = ev.clientY - canvas.offsetTop; if(ctx.isPointInStroke(l,t)){ ctx.font = "40px Arial"; ctx.fillText((l+','+t),200,120); } }
從這個gif中可以看出端倪來,只有點到線框才會觸發,具體效果看這里 —— canvas 判斷是否在線框中
這2個方法的基本用法就是這樣,但是會有一個問題,就是目前只有一個圖形在上面,如果有2個圖形在上面,而且分別的方法不一樣,比如說,一個是區域路徑,一個是線框路徑,分別點擊他們,彈出不同的值,我們看行不行:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.strokeStyle = 'red'; ctx.lineWidth = 5; ctx.rect(50,50,100,100); ctx.stroke(); ctx.closePath(); ctx.beginPath(); ctx.fillStyle = 'green'; ctx.rect(200,50,100,100); ctx.fill(); ctx.closePath(); canvas.onclick = function(ev){ var ev = ev || event; var l = ev.clientX - canvas.offsetLeft; var t = ev.clientY - canvas.offsetTop; if(ctx.isPointInStroke(l,t)){ console.log('線框路徑'); } } canvas.onclick = function(ev){ var ev = ev || event; var l = ev.clientX - canvas.offsetLeft; var t = ev.clientY - canvas.offsetTop; if(ctx.isPointInPath(l,t)){ console.log('區域路徑'); } }
看看console里面的提示,當點擊區域路徑的時候,觸發了操作,但是點擊線框路徑時,無論我怎么點擊,都無濟於事,這是為什么呢?把2圖形的執行順序顛倒一下,發現效果也相反了,說明誰最后繪制就執行誰,其實這也是可以理解的,因為此時的ctx指的是當前的路徑,它不能分當前路徑一,路徑二什么的,如果要實現多個圖形執行不同的事件,又改如何做呢?由於實現方法有點復雜,就在這里留一個思考題?你們先思考一下,該怎么弄?我會到后期單獨寫一篇文章,專門來說這個的解決方案,供大家參考!
恩,到處所有該講的canvas API就全部講完了,看了這一系列的文章,不知道你是否對canvas有了那么一點點的感覺,是否canvas已經不那么神秘了,如果你嘴上不說,心里覺得,恩,好像有點感覺了,那我的目的就達到了,要是你還能寫一些效果,那恭喜你,距離大神你有近了一步,如果有時間,有能力,我希望能多寫一下有點深度的canvas實例給大家參考,但願能對大家有幫助!
就這樣吧,感謝大家的關注,謝謝!