前端時間做的一個項目需要支持多終端,網頁版需要使用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 9
、Firefox
、Opera
、Chrome
、Safari
支持globalCompositeOperation 屬性
通過Context的globalCompositeOperation
我們可以靈活的掌握繪制圖形之間層疊顯示關系,做出很多漂亮的顯示效果。接下來我們就使用globalCompositeOperation=destination-out
來實現一個刮刮卡的效果。
globalCompositeOperation屬性應用
刮刮卡實現效果
實現原理
- 在頁面上放一個
div
容器,設置這個div的寬高、把機器貓
的圖片設為背景, - 在div中放一個
canvas
標簽,設置canvas的寬高和父容器div的一樣。 - 獲取canvas的context對象繪制一個以灰色為背景寬高和canvas寬高相同的矩形,這樣機器貓背景圖就被遮住了,只能看見一個灰色的背景。
- canvas綁定鼠標mousedown,mousemove和mouseup事件(移動端綁定事件分別是:touchstart,touchmove,touchend),設置鼠標按下標志,鼠標按下或者鼠標按下并且移動時記錄鼠標坐標值。
- 鼠標點擊或者按住鼠標移動的時候開始繪圖,繪圖的時候設置
context.globalCompositeOperation='destination-out'
根據上面屬性的解釋,原有圖形(灰色矩形)與新圖形(畫的線條)不重疊的部分會被保留,所以畫過線條的部分不會被保留就可以看見下面機器貓圖片背景了。 - 鼠標抬起設置鼠標按下標志為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();
}
}
文章如有誤,請不吝賜教~