如何使globalCompositeOperationSection仅影响save()和restore()上下文?

时间:2019-07-20 11:41:58

标签: javascript html5-canvas

如何使globalCompositeOperation仅影响save / restore()上下文中的内容?

例如,红色矩形波纹管正受到“目的地在上”运算符的影响。预期要做的是用红色矩形填充画布,并在其上看到黑色圆圈。而且发生的是红色矩形也被遮盖了。

let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let size1 = 350;
let size2 = 150;
let size3 = 154;

canvas.width  = size1;
canvas.height = size1; 
canvas.style.width  = size1+'px';
canvas.style.height = size1+'px';

//red rectangle
ctx.fillStyle = "red";
ctx.beginPath();
ctx.rect(0, 0, size1, size1);
ctx.fill();

// save the context state
ctx.save();

//black circle
ctx.fillStyle = "black";
ctx.beginPath();
ctx.ellipse(size2, size2, size2, size2, 0, 0, 6.28);
ctx.fill();

//mask
//shouldnt it mask only the shape before?
//why is it masking the red rectangle outside save/restore() context?
ctx.globalCompositeOperation="destination-atop";
ctx.beginPath();
ctx.ellipse(size3, size3, size3, size3, 0, 0, 6.28);
ctx.fill();

ctx.restore();
<canvas id="canvas" />

我知道有一种方法可以创建多个画布以将它们组合起来,或者可以使用其他技术进行遮罩,但是我的主要问题是globalCompositeOperation不尊重save / restore()上下文...

1 个答案:

答案 0 :(得分:0)

save()方法将2DContext的所有当前属性保存在已保存状态的堆栈中。 ({fillStylestrokeStylefontlineWidth等)
restore()将应用堆栈中最后保存的状态,同时将其从堆栈中删除。

这些方法都与画布上绘制的内容无关,它们只保存JS对象的某些属性(以及一些不可访问的属性,例如剪切区域)。


globalCompositeOperation仅影响设置后的绘图操作。他们将与您在画布上绘制的内容有关。

saverestore根本无法帮助您实现目标。 您想要的是在单独的画布内容上进行合成,为此,最简单的方法是使用第二个画布元素:

let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let size1 = 350;
let size2 = 150;
let size3 = 154;

canvas.width  = size1;
canvas.height = size1; 
canvas.style.width  = size1+'px';
canvas.style.height = size1+'px';

const copycanvas = canvas.cloneNode();
const copyctx = copycanvas.getContext('2d');

//red rectangle
ctx.fillStyle = "red";
ctx.beginPath();
ctx.rect(0, 0, size1, size1);
ctx.fill();

//draw the mask on the off-screen canvas
//black circle
copyctx.fillStyle = "black";
copyctx.beginPath();
copyctx.ellipse(size2, size2, size2, size2, 0, 0, 6.28);
copyctx.fill();

// I guess you didn't really want a source-atop gCO here
copyctx.globalCompositeOperation="source-out";
copyctx.beginPath();
copyctx.ellipse(size3, size3, size3, size3, 0, 0, 6.28);
copyctx.fill();

ctx.drawImage(copycanvas, 0, 0);
<canvas id="canvas" />

但是您也可以通过以其他顺序绘制完全在同一画布上进行精确绘制:

let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let size1 = 350;
let size2 = 150;
let size3 = 154;

canvas.width  = size1;
canvas.height = size1; 
canvas.style.width  = size1+'px';
canvas.style.height = size1+'px';

//draw the mask first
//black circle
ctx.fillStyle = "black";
ctx.beginPath();
ctx.ellipse(size2, size2, size2, size2, 0, 0, 6.28);
ctx.fill();

// I guess you didn't really want a source-atop gCO here
ctx.globalCompositeOperation = "source-out";
ctx.beginPath();
ctx.ellipse(size3, size3, size3, size3, 0, 0, 6.28);
ctx.fill();

// finally, draw the background
ctx.globalCompositeOperation = "destination-over";
//red rectangle
ctx.fillStyle = "red";
ctx.beginPath();
ctx.rect(0, 0, size1, size1);
ctx.fill();
<canvas id="canvas" />