CanvasRenderingContext2D 中的透明组

Transparency groups in CanvasRenderingContext2D

有没有一种方法可以将多个绘制操作组合到 2d canvas 渲染上下文中,使它们的 组合 结果组合到之前的内容上canvas,而不是每个绘图操作都由自己组成?

一个应用程序:我想画一条带箭头的半透明线,我想避免增加线和箭头重叠区域的不透明度。

许多其他渲染模型支持此类功能。 SVG 在第 7.3 节中有一个 group opacity setting, described in section 14.5. The PDF reference 描述的“透明组”。在许多图形应用程序中,用户可以构建层,然后将它们组合成一个整体。

我想我可以设置第二个不可见的 canvas 用作屏幕外图像,将我的内容呈现给它,然后使用 globalAlpha 将结果合成到主 canvas 具有所需的半透明度。但我希望有一些更优雅的解决方案,即使到目前为止我在文档中找不到它。

apparently has a similar goal in mind. But the focus there appears to be how to perform boolean operations on paths, probably the way clipper 做到了。所以对于这里的post,我对预先操作路径不感兴趣;我希望能够像往常一样画出每一笔画。

不,如果不使用中间体 canvas 目前无法做到这一点。

除非 所有有问题的绘制操作都可以合并到一个路径中,从而使用对 stroke()fill() 的单个调用。我假设这里不是这种情况,但稍后搜索的人可能正在寻找该信息。

// two rectangles composed into a single draw operation:
ctx.rect(0, 0, 10, 10);
ctx.rect(5, 5, 10, 10);
ctx.fill();

// With transparency, the above produces a different result from:
ctx.rect(0, 0, 10, 10);
ctx.fill();
ctx.rect(5, 5, 10, 10);
ctx.fill();

也许因为我习惯了分层的想法,我相信离屏 canvas 仍然是最优雅的方式。

但请注意,在空 canvas 的 exceptional* 情况下,您也可以在单个 canvas 元素上实现它,这要归功于globalCompositeOperation 属性.

想法是先将重叠路径组绘制成不透明的,然后使用 gCO "destination-in" 并绘制一个矩形,用所需的颜色覆盖组的整个区域(请参阅 post 的评论和下方编辑以获得更好的方法,仍然使用 gCO) :

var ctx = c.getContext('2d');

// first draw your overlapping paths opaque
ctx.lineWidth = 10;
ctx.beginPath();
ctx.arc(40, 40, 35, 0, Math.PI * 2);
ctx.stroke();
ctx.beginPath();
ctx.arc(60, 60, 35, 0, Math.PI * 2);
ctx.stroke();
// then set the fill color to the one you want
ctx.fillStyle = 'rgba(0,255,0,.5)';
// set the gCo so we only draw on the existing pixels
ctx.globalCompositeOperation = 'source-in';
// draw a large rect
ctx.fillRect(0, 0, c.width, c.height);
p{position: absolute;z-index:-1}
body{background-color: ivory;}
<p>Is this transparent ?</p>
<canvas id="c"></canvas>

* 实际上,我能想到的唯一一种情况是屏幕外 canvas ;-)

编辑

@K3N, it can even be simplified and improved 所述,使用 "copy" 复合操作。