首頁  >  文章  >  web前端  >  帶你了解canvas中的globalCompositeOperation屬性

帶你了解canvas中的globalCompositeOperation屬性

青灯夜游
青灯夜游轉載
2021-04-25 11:57:524815瀏覽

這篇文章帶大家詳細了解canvas中的globalCompositeOperation屬性,透過程式碼實例看看該屬性所做的神奇效果。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

帶你了解canvas中的globalCompositeOperation屬性

說明

#最早知道canvas 的globalCompositeOperation 屬性,是需要實現一個刮刮卡效果的時候,當時也就是網路上找到刮刮卡的效果趕緊完成任務就完了,這次又學習一次,希望能加深理解吧。

先來看下 canvas 的 globalCompositeOperation屬性,具體是做什麼的。

定義

globalCompositeOperation 屬性設定或傳回如何將一個來源(新的)影像繪製到目標(已有)的圖像上。
來源圖像 = 您打算放置到畫布上的繪圖。
目標圖像 = 您已經放置在畫布上的繪圖。

這個屬性用來設定要在繪製新形狀時應用的合成操作的類型,例如在一個藍色的矩形上畫一個紅色的圓形,是紅色在上顯示,還是藍色在上顯示,重疊的部分顯示還是不顯示,不重疊的部分又怎麼顯示,等一些情況,在面對這些情況的時候,就是globalCompositeOperation 屬性起作用的時候了。
在取預設值的情況下,都是顯示的,新畫的圖形會覆蓋原來的圖形。

用法

預設值: source-over
語法: context.globalCompositeOperation=" source-in";

表格中的藍色矩形為目標影像,紅色圓形為來源影像。

屬性值 描述 效果
source-over 預設.在目標影像上顯示來源影像。
source-atop 在目標影像頂部顯示來源影像。來源影像位於目標影像之外的部分是不可見的。
source-in 在目標影像中顯示來源影像。只有目標影像內的來源影像部分會顯示,目標影像是透明的。
source-out 在目標影像之外顯示來源影像。只會顯示目標影像之外來源影像部分,目標影像是透明的。
destination-over #在來源影像上方顯示目標影像。
destination-atop #在來源影像頂部顯示目標影像。來源影像之外的目標影像部分不會被顯示。
destination-in #在來源影像中顯示目標影像。只有來源影像內的目標影像部分會被顯示,來源影像是透明的。
destination-out #在來源影像外顯示目標影像。只有來源影像外的目標影像部分會被顯示,來源影像是透明的。
lighter 顯示來源影像 目標影像。
copy 顯示來源影像。忽略目標影像。
xor 使用異或運算對來源影像與目標影像進行組合。

好的,下來實現一個水滴擴散的效果:

https://codepen.io/FEWY/pen/oPxbmj

效果圖

實現想法

#在一個canvas 上先畫出黑白色的圖片,然後設定背景是一張彩色的圖片,滑鼠點擊時,設定canvas 的globalCompositeOperation 屬性值為destination-out,根據滑鼠在canvas 中的座標,用一個不規則的圖形逐漸增大,來擦除掉黑白色的圖片,就可以慢慢顯示彩色的背景了。

也就是說我們需要三張圖片

黑白的圖片

帶你了解canvas中的globalCompositeOperation屬性

彩色的圖片

帶你了解canvas中的globalCompositeOperation屬性

不規則形狀的圖片

帶你了解canvas中的globalCompositeOperation屬性

程式碼

<!doctype html>
<html>

<head>
    <meta charset="UTF-8">
    <style>
        canvas {
            /* 设置鼠标的光标是一张图片, 16和22 分别表示热点的X坐标和Y坐标 */
            /* https://developer.mozilla.org/zh-CN/docs/Web/CSS/cursor/url */
            cursor: url(&#39;https://www.kkkk1000.com/images/globalCompositeOperation/mouse.png&#39;) 16 22, auto;
        }
    </style>
</head>

<body>
    <canvas id="canvas" width="400px" height="250px"></canvas>

    <script type="text/javascript"> 
        var canvas = document.getElementById("canvas");
        var context = canvas.getContext("2d");

        // 保存图片路径的数组
        var urlArr = ["https://www.kkkk1000.com/images/globalCompositeOperation/bg2.png", "https://www.kkkk1000.com/images/globalCompositeOperation/clear.png"];
        // imgArr 保存加载后的图片的数组,imgArr中保存的是真实的图片
        // loadImg 函数用来加载 urlArr 中所有的图片
        // 并返回一个保存所有图片的数组
        var imgArr = loadImg(urlArr);
        // flag 用来限制 点击事件,一张图片只会产生一次效果
        var flag = false;
 

        function loadImg(urlArr) {
            var index = 0;
            var res = [];
            // 每次给 load 函数传入一个图片路径,来加载图片
            load(urlArr[index]);
            function load(url) {
                // 如果 index 等于 urlArr.length,
                // 表示加载完 全部图片了,就结束 load函数
                if (index == urlArr.length) {
                    // 加载完全部图片,调用 init 函数
                    init();
                    return;
                }

                var img = new Image();
                img.src = url;
                // 不管当前图片是否加载成功,都要加载下一张图片
                img.onload = next;
                img.onerror = function () {
                    console.log(res[index] + "加载失败");
                    next();
                }
                // next 用来加载下一张图片
                function next() {
                    // 把加载后的图片,保存到 res 中
                    res[index] = img;
                    load(urlArr[++index])
                }
            }
            // 最后返回保存所有真实图片的数组
            return res;
        }

        function init() {
            // 先在canvas上画黑白的图片,然后再设置背景是彩色的图片
            // 避免先显示出彩色图片,再显示出黑白的图片
            context.globalCompositeOperation = "source-over";
            context.drawImage(imgArr[0], 0, 0, 400, 250);
            canvas.style.background = &#39;url(https://www.kkkk1000.com/images/globalCompositeOperation/bg.jpg)&#39;;
            canvas.style.backgroundSize = "100% 100%";

            // flag 是 true 时,鼠标点击才有水滴扩散的效果
            flag = true;
            // canvas 绑定点击事件,点击时产生水滴扩散效果
            canvas.onclick =  diffusion;
        }

        // width 表示 不规则形状的图片的尺寸
        var width = 0;
        // speed 表示扩散效果的速度
        var speed = 8;
        // diffusion 函数根据鼠标坐标,产生效果
        function  diffusion (e) {
            if (flag) {
                flag = false;
                context.globalCompositeOperation = "destination-out";
                window.requestAnimationFrame(draw);
                // 根据鼠标坐标,画扩散效果
                function draw() {
                    // 这里不一定需要是 1800 ,但必须是一个足够大的数,可以扩散出整张背景图
                    if (width > 1800) {
                        flag = true;
                        return;
                    }
                    width += speed;
                    // 获取鼠标相对于 canvas 的坐标
                    var x = e.layerX;
                    var y = e.layerY;

                    // 画不规则形状的图片,逐渐增大图片尺寸
                    context.drawImage(imgArr[1], x - (width / 2), y - (width / 2), width, width);
                    window.requestAnimationFrame(draw);
                }
            }
        }
    </script>
</body>

</html>

我們繼續實現一個刮刮卡的效果

效果圖

帶你了解canvas中的globalCompositeOperation屬性

刮刮卡效果實現的想法:

一個canvas 上先畫一層灰色,然後設定canvas的背景圖,設定canvas 的globalCompositeOperation屬性值為destination -out,點擊並移動時,根據移動點的座標,擦除掉灰色,當擦掉一部分時,再自動擦除掉全部灰色,顯示出背景來。

刮刮卡的效果和水滴擴散的效果,在開始的時候幾乎是一樣的,不過水滴擴散效果,用的是一張不規則形狀的圖片來清除黑白圖片,而刮刮卡效果,是透過畫線的方式,線比較粗而已,來清除上面的灰色。
主要的不同是,刮刮卡效果最後需要自動擦除掉全部灰色,這裡有兩種方式。

第一種

使用canvas 的getImageData 方法,來取得canvas 上的像素信息,這個方法傳回的物件的data 屬性是一個一維數組,包含以RGBA 順序的數據,數據使用0 至255(包含)的整數表示,詳細的可以看看canvas 的像素操作
用這個方法來判斷有多少已經擦除掉了,也就是透過一個變數來記錄有多少像素的RGBA的值是0,當變數的值超過某一個值時,就清除全部灰色。

程式碼在這裡:

##https://codepen.io/FEWY/pen/BOjmyg

第二種

就直接看移動了多少,滑鼠移動時,會有一個變數進行自增運算,當這個變量,超過一定值時,就擦除全部灰色。

程式碼在這裡

https://codepen.io/FEWY/pen/eLJeNv

注意: 第一種方式使用
getImageData 存在跨域問題,不過因為這個效果中,沒有在canvas上畫圖片,而是設定canvas的background 為一張圖片,所以這個還沒有影響,但如果canvas畫了其他圖片,就可能需要處理跨域的問題了。 使用 getImageData 能獲取到 canvas 上的像素信息,就可以根據刮刮卡上灰色的面積,決定擦除全部灰色的時機,更加靈活。

第二種方式,雖然不存在跨域的問題,但是,不能很好的根據刮刮卡上灰色的面積,控制最後擦除全部灰色的時機。

總結

文章中的效果主要是使用

globalCompositeOperation屬性取值為destination-out ,而取值為其他值的時候,同樣也是可以製作出各種效果的,大家也可以發揮自己的想像力,去試試其它值,也許有新發現呢。

更多程式相關知識,請造訪:

程式設計入門! !

以上是帶你了解canvas中的globalCompositeOperation屬性的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除
上一篇:html5是啥下一篇:html5是啥