canvas API ,通俗的canvas基礎知識(六)


這篇是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實例給大家參考,但願能對大家有幫助!

就這樣吧,感謝大家的關注,謝謝!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM