canvas繪制刮刮卡

前端時間做的一個項目需要支持多終端,網頁版需要使用html5中canvas畫布對象對一組數據進行渲染還原,但是在實際實現過程中遇到了一個問題,canvas中沒有mask(遮罩)層的概念,所以一些效果實現不了,最后翻看文檔的時候發現可以通過Context對象的globalCompositeOperation屬性或者Context的clip()裁剪路徑方法實現遮罩的效果。

globalCompositeOperation屬性介紹

接下來先詳細了解下Context的globalCompositeOperation的各種值描述,由于項目不便演示最后我們通過它來實現一個刮刮卡的效果來學習使用它。

屬性值 描述 顯示效果
source-over (default) 新圖形會覆蓋在原有內容之上
destination-over 會在原有內容之下繪制新圖形
source-in 新圖形會僅僅出現與原有內容重疊的部分。其它區域都變成透明的
destination-in 原有內容中與新圖形重疊的部分會被保留,其它區域都變成透明的
source-out 結果是只有新圖形中與原有內容不重疊的部分會被繪制出來
destination-out 原有內容中與新圖形不重疊的部分會被保留
source-atop 新圖形中與原有內容重疊的部分會被繪制,并覆蓋于原有內容之上
destination-atop 原有內容中與新內容重疊的部分會被保留,并會在原有內容之下繪制新圖形
lighter 兩圖形中重疊部分作加色處理
darker 兩圖形中重疊的部分作減色處理
xor 重疊的部分會變成透明
copy 只有新圖形會被保留,其它都被清除掉

藍色 表示先繪制的圖形、紅色 表示后繪制的圖形

瀏覽器支持: Internet Explorer 9FirefoxOperaChromeSafari 支持globalCompositeOperation 屬性

通過Context的globalCompositeOperation我們可以靈活的掌握繪制圖形之間層疊顯示關系,做出很多漂亮的顯示效果。接下來我們就使用globalCompositeOperation=destination-out來實現一個刮刮卡的效果。

globalCompositeOperation屬性應用

刮刮卡實現效果

實現原理

  1. 在頁面上放一個div容器,設置這個div的寬高、把機器貓的圖片設為背景,
  2. 在div中放一個canvas標簽,設置canvas的寬高和父容器div的一樣。
  3. 獲取canvas的context對象繪制一個以灰色為背景寬高和canvas寬高相同的矩形,這樣機器貓背景圖就被遮住了,只能看見一個灰色的背景。
  4. canvas綁定鼠標mousedown,mousemove和mouseup事件(移動端綁定事件分別是:touchstart,touchmove,touchend),設置鼠標按下標志,鼠標按下或者鼠標按下并且移動時記錄鼠標坐標值。
  5. 鼠標點擊或者按住鼠標移動的時候開始繪圖,繪圖的時候設置context.globalCompositeOperation='destination-out'根據上面屬性的解釋,原有圖形(灰色矩形)與新圖形(畫的線條)不重疊的部分會被保留,所以畫過線條的部分不會被保留就可以看見下面機器貓圖片背景了。
  6. 鼠標抬起設置鼠標按下標志為false,清空坐標數組。

代碼實現

html代碼(canvas動態創建的)

<div id='div' style='width:540px;min-height:360px;background:url("../images/test.jpg") no-repeat'>
</div>

javascript代碼

function init() {
    if (!document.getElementById("myCanvas")) {
        var width = "";
        var height = "";
        var canvas = document.createElement("canvas");
        width = document.getElementById("div").offsetWidth;
        height = document.getElementById("div").offsetHeight;
        canvas.setAttribute("width", width + "px");
        canvas.setAttribute("height", height + "px");
        canvas.setAttribute("style", "border:1px solid green");
        canvas.id = "myCanvas";
        document.getElementById("div").appendChild(canvas);
    }

    var myCanvasObject = document.getElementById("myCanvas");
    var ctx = myCanvasObject.getContext("2d");

    //繪制黑色矩形    
    ctx.beginPath();
    ctx.fillStyle = "#939393";
    ctx.rect(0, 0, width, height);
    ctx.closePath();
    ctx.fill();

    var isDown = false; //鼠標是否按下標志
    var pointerArr = []; //鼠標移動坐標數組
    var xPointer = 0;//鼠標當前x坐標
    var yPointer = 0;//鼠標當前y坐標


    //pc,移動事件兼容寫法
    var hastouch = "ontouchstart" in window ? true : false,
    tapstart = hastouch ? "touchstart" : "mousedown",
    tapmove = hastouch ? "touchmove" : "mousemove",
    tapend = hastouch ? "touchend" : "mouseup";


    //鼠標按下
    myCanvasObject.addEventListener(tapstart, function(event) {
        var e=window.event||event;//2017-12-06
        this.style.cursor = "move";
        isDown = true;
        xPointer = hastouch ? e.targetTouches[0].pageX : e.clientX - this.offsetLeft;
        yPointer = hastouch ? e.targetTouches[0].pageY : e.clientY - this.offsetTop;;
        pointerArr.push([xPointer, yPointer]);
        circleReset(ctx);
    });


    //鼠標按下后拖動
    myCanvasObject.addEventListener(tapmove, function(event) {
        var e=window.event||event;//2017-12-06
        if (isDown) {
        xPointer = hastouch ? e.targetTouches[0].pageX : e.clientX - this.offsetLeft;;
        yPointer = hastouch ? e.targetTouches[0].pageY : e.clientY - this.offsetTop;;
        pointerArr.push([xPointer, yPointer]);
        circleReset(ctx);
        }
    });


    //鼠標抬起取消事件
    myCanvasObject.addEventListener(tapend, function(event) {
        isDown = false;
        pointerArr = [];
    });


    //圓形橡皮檫
    function circleReset(ctx) {
        ctx.save();
        ctx.beginPath();
        ctx.moveTo(pointerArr[0][0], pointerArr[0][1]);
        ctx.lineCap = "round";   //設置線條兩端為圓弧
        ctx.lineJoin = "round";   //設置線條轉折為圓弧
        ctx.lineWidth = 60;
        ctx.globalCompositeOperation = "destination-out";
        if (pointerArr.length == 1) {
            ctx.lineTo(pointerArr[0][0] + 1, pointerArr[0][1] + 1);
        } else {
            for (var i=1;i<pointerArr.length;i++) {
                ctx.lineTo(pointerArr[i][0], pointerArr[i][1]);
                ctx.moveTo(pointerArr[i][0], pointerArr[i][1]);
            }
        }
        ctx.closePath();
        ctx.stroke();
        ctx.restore();
    }
}

文章如有誤,請不吝賜教~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容