首頁  >  文章  >  web前端  >  canvas API ,通俗的canvas基礎知識(六)

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

黄舟
黄舟原創
2017-02-25 11:55:281818瀏覽

這篇是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);
}


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

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

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

canvas API ,通俗的canvas基礎知識(六)
##恩,跟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);


canvas API ,通俗的canvas基礎知識(六)
當然這個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("<p id=&#39;p_" + i + "&#39; style=&#39;float:left;&#39;>" + arr[i] + ":<br>");
            var canvas = document.createElement("canvas");
            canvas.width = 120;
            canvas.height = 100;
            canvas.style.border = "1px solid #000";
            canvas.style.marginRight = &#39;10px&#39;;
            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("</p>");
                
        }

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

红与蓝

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

具体效果你也可以看这里 —— 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();



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

如果配合前面的扇形方法,很容易做一个圆形进度条什么的,当然,还有很多属性可以有大的作用,比如说裁切一个图形,发挥的发达的大脑吧,这里我就不演示了

3、setLineDash

setLineDash(arr)  在画布上画一条虚线

参数:arr 表示的是一个数组集合,里面的参数可以有多个,这里面的参数很有意思,举个栗子说明:

ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(400, 100);
ctx.setLineDash([10,20]);
ctx.stroke();


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

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

对比代码看图,如果有2个参数,则第一个参数表示虚线的线宽,第二个参数表示虚线的线与线的距离,后面一直循环

如果是3个参数呢?

ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(400, 100);
ctx.setLineDash([10,20,30]);
ctx.stroke();


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

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

此时会这样,第一条线长为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();

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

规律和上面的一样,只是循环的长度要长一些,更多参数的规则也是这样的,那么一个参数是否有效呢

ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(400, 100);
ctx.setLineDash([10]);
ctx.stroke();


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

显然是有效的,此时线宽为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 = &#39;red&#39;;
ctx.font = "30px Arial";
ctx.fillText(txt,180,140);


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

ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(400, 100);
ctx.setLineDash([10,20]);
var txt = ctx.getLineDash();
ctx.stroke();
ctx.fillStyle = &#39;red&#39;;
ctx.font = "30px Arial";
ctx.fillText(txt,180,140);


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

从这两组图可以看出,当只有一个参数数,会默认为2个一样的参数

4、isPointInPath
isPointInPath(x,y)  指定点是否在路径区域中,如果在则返回true,不在则返回false
参数: x,y表示指定的坐标点

举个栗子:

var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        
        ctx.beginPath();
        ctx.fillStyle = &#39;red&#39;;
        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+&#39;,&#39;+t),200,120);
            }
        }


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

看看这个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 = &#39;red&#39;;
        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+&#39;,&#39;+t),200,120);
            }
        }


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

从这个gif中可以看出端倪来,只有点到线框才会触发,具体效果看这里 —— canvas 判断是否在线框中

这2个方法的基本用法就是这样,但是会有一个问题,就是目前只有一个图形在上面,如果有2个图形在上面,而且分别的方法不一样,比如说,一个是区域路径,一个是线框路径,分别点击他们,弹出不同的值,我们看行不行:

var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        
        ctx.beginPath();
        ctx.strokeStyle = &#39;red&#39;;
        ctx.lineWidth = 5;
        ctx.rect(50,50,100,100);
        ctx.stroke();
        ctx.closePath();
        ctx.beginPath();
        ctx.fillStyle = &#39;green&#39;;
        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(&#39;线框路径&#39;);
            }
        }
        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(&#39;区域路径&#39;);
            }
        }


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

看看console里面的提示,当点击区域路径的时候,触发了操作,但是点击线框路径时,无论我怎么点击,都无济于事,这是为什么呢?把2图形的执行顺序颠倒一下,发现效果也相反了,说明谁最后绘制就执行谁,其实这也是可以理解的,因为此时的ctx指的是当前的路径,它不能分当前路径一,路径二什么的,如果要实现多个图形执行不同的事件,又改如何做呢?由于实现方法有点复杂,就在这里留一个思考题?你们先思考一下,该怎么弄?我会到后期单独写一篇文章,专门来说这个的解决方案,供大家参考!

恩,到处所有该讲的canvas API就全部讲完了,看了这一系列的文章,不知道你是否对canvas有了那么一点点的感觉,是否canvas已经不那么神秘了,如果你嘴上不说,心里觉得,恩,好像有点感觉了,那我的目的就达到了,要是你还能写一些效果,那恭喜你,距离大神你有近了一步,如果有时间,有能力,我希望能多写一下有点深度的canvas实例给大家参考,但愿能对大家有帮助!

 以上就是canvas API ,通俗的canvas基础知识(六) 的内容,更多相关内容请关注PHP中文网(www.php.cn)!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn