在画布中使用 globalCompositeOperation 屏蔽多个形状

Posted

技术标签:

【中文标题】在画布中使用 globalCompositeOperation 屏蔽多个形状【英文标题】:Masking multiple shapes using globalCompositeOperation in canvas 【发布时间】:2013-10-31 11:56:20 【问题描述】:

我正在尝试绘制多个矩形,然后使用 globalCompositeOperation 'source-in' 遮盖这些矩形,效果很好,但问题是当我填充矩形时它们会消失...如果我只有一个 fill() 调用它们全部正确绘制,但仅尊重最后应用的填充样式。

有问题的代码 -

ctx.drawImage(self.glass.mask, 256, 375);
ctx.globalCompositeOperation = 'source-in';

ctx.rect(256, 635, 256, 75);
ctx.fillStyle = "#c65127";

ctx.rect(256, 605, 256, 25);
ctx.fillStyle = "#f5f4f0";

ctx.rect(256, 565, 256, 35);
ctx.fillStyle = "#c65127";

ctx.fill();

上面的代码可以正常工作。但如果我这样做,并取下面具 -

ctx.beginPath();
ctx.rect(0, 256, 256, 75);
ctx.fillStyle = "#c65127";
ctx.fill();

ctx.beginPath();
ctx.rect(0, 226, 256, 25);
ctx.fillStyle = "#f5f4f0";
ctx.fill();

ctx.beginPath();
ctx.rect(0, 186, 256, 35);
ctx.fillStyle = "#222";
ctx.fill();

我有每个矩形,他们尊重他们的填充样式。问题是当我启用掩码时,它们不再可见。

在 globalCompositeOperation 'source-in' 下可以拥有的元素数量是否有限制,或者我只是缺少一些简单的东西?

这里有一些小提琴 -

http://jsfiddle.net/ENtXs/ - 按预期工作,但不遵守填充样式。

http://jsfiddle.net/ENtXs/1/ - 移除掩码以显示所有元素

http://jsfiddle.net/ENtXs/2/ - 添加 beginPath() 和 fill() 元素尊重填充样式。 (无掩饰)

http://jsfiddle.net/ENtXs/3/ - 重新添加掩码(不再显示任何内容)

http://jsfiddle.net/ENtXs/4/ - 只有一个与#3 代码相同的矩形才能正常工作。

【问题讨论】:

篡改了一段时间,尝试在每个形状后使用ctx.closePath(),尝试使用多个蒙版和多个ctx.globalCompositeOperation以及不同的复合类型......没什么。 @inorganik 这正是我注意到的。似乎在绘制具有不同填充样式的多个形状时存在问题。除非我错过了一些超级简单的东西...... 【参考方案1】:

已解决

我认为问题在于 globalCompositeOperation 'source-in'。我最终要做的是创建一个缓冲区画布,在上面绘制我的形状,然后获取该图像数据并将其绘制到我的主画布中,并将 GCO 应用到该画布上。

这是一个有效的小提琴 - http://jsfiddle.net/ENtXs/5/

有问题的代码:

// Canvas and Buffers
var canvas = document.getElementById('canvas');
var buffer = document.getElementById('buffer');
var ctx = canvas.getContext('2d');
var buffer_ctx = buffer.getContext('2d');

// sizing
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;

buffer.height = window.innerHeight;
buffer.width = window.innerWidth;

// mask image
var mask = new Image();
mask.onload = function () 
    drawBuffer();


mask.src = 'http://drewdahlman.com/experiments/masking/highball_mask.png';

function drawBuffer() 
    buffer_ctx.beginPath();
    buffer_ctx.rect(0, 256, 256, 75);
    buffer_ctx.fillStyle = "#c65127";
    buffer_ctx.fill();

    buffer_ctx.beginPath();
    buffer_ctx.rect(0, 226, 256, 25);
    buffer_ctx.fillStyle = "#f5f4f0";
    buffer_ctx.fill();

    buffer_ctx.beginPath();
    buffer_ctx.rect(0, 186, 256, 35);
    buffer_ctx.fillStyle = "#222";
    buffer_ctx.fill();

    var image = buffer.toDataURL("image/png");
    var img = new Image();
    img.onload = function()
        buffer_ctx.clearRect(0,0,buffer.width,buffer.height);
        ctx.drawImage(mask,0,0);
        ctx.globalCompositeOperation = 'source-in';
        ctx.drawImage(img,0,0);
    
    img.src = image;

【讨论】:

以上是关于在画布中使用 globalCompositeOperation 屏蔽多个形状的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 html5 中使用画布制作动画?

Android,画布:如何清除(删除)画布(=位图),生活在surfaceView中?

HTML5怎样创建画布?

为啥我的位图图像使用 EaselJS 在画布中出现别名?

HTML5怎样创建画布?

如何让用户在 WPF 中使用画布绘制线条