HTML5画布:我正在寻找一种在组合路径上绘制单个笔划的方法。
例如,如果我有两个重叠的圆圈,我不希望有两个重叠的圆形笔划,但是在两个圆圈的组合区域周围只有一个笔划。
有机会吗?
答案 0 :(得分:2)
可以使用globalCompositeOperation
来完成。有各种方法可以自己绘制形状,但这里有一种方法可以实现这一点(对于演示中的两个矩形圆圈):
更新不确定我怎么会错过显而易见的,但你当然可以首先抚摸圈子,然后用复合模式和填充打一整个 - 多更快(我猜想当我想出偏移重绘时,我的脑海中有了图像)。
离屏画布的原因是如果你在主画布上已经有了背景。除非我们打洞,否则这将被删除。如果没有什么,那么将它绘制到单个画布上没有问题 - 更新的代码:
/// some regions
var rect = [ [20, 20, 200, 200], [100, 100, 200,200] ],
/// ox = off-screen context
ox.strokeStyle = '#fff';
ox.lineWidth = 3 * 2; /// x2 as half will be gone when we punch hole
/// stroke outlines
for(; r = rect[i]; i++) {
o = r[2] * 0.5;
ox.beginPath();
ox.arc(r[0] + o, r[1] + o, o, 0, 2 * Math.PI);
ox.stroke();
}
/// punch hole with composite mode and fill
ox.globalCompositeOperation = 'destination-out';
for(i = 0; r = rect[i]; i++) {
o = r[2] * 0.5;
ox.beginPath();
ox.arc(r[0] + o, r[1] + o, o, 0, 2 * Math.PI);
ox.fill();
}
/// draw result to main canvas
/// ctx = main context, ocanvas = off-screen canvas
ctx.drawImage(ocanvas, 0, 0);
<强> (Animated) online demo using this optimized version 强>
我将保留旧代码,因为它可以用于无法描边的图像 -
现在将填充形状绘制到离屏画布上。绘制您希望轮廓所在的颜色。
/// some regions
var rect = [ [20, 20, 200, 200], [100, 100, 200,200] ],
/// ox = off-screen canvas
ox.fillStyle = '#fff';
/// draw the array with circes
for(; r = rect[i]; i++) {
var o = r[2] * 0.5;
ox.beginPath(); //use this here - arcs are currently buggy
ox.arc(r[0] + o, r[1] + o, o, 0, 2 * Math.PI);
ox.fill(); //.. and here
}
现在将形状的缓存图像绘制回主画布。必须在每个方向上稍微偏移绘制形状 - 此步骤将创建轮廓:
/// ctx = main context, ocanvas = off-screen canvas
ctx.drawImage(ocanvas, -1, -1);
ctx.drawImage(ocanvas, 1, -1);
ctx.drawImage(ocanvas, 1, -1);
ctx.drawImage(ocanvas, 1, 1);
ctx.drawImage(ocanvas, -1, 1);
ctx.drawImage(ocanvas, 1, 1);
ctx.drawImage(ocanvas, -1, -1);
ctx.drawImage(ocanvas, -1, 1);
最后,我们在填充的形状中打出一个“洞”,使其使用globalCompositeOperation
+在0偏移位置的最终绘制时使用轮廓透明:
ctx.globalCompositeOperation = 'destination-out';
ctx.drawImage(ocanvas, 0, 0);
的 ONLINE DEMO 强>
要使边框更粗,只需在将形状绘制到主画布时增加偏移量。
答案 1 :(得分:0)
这是我目前的解决方案。不需要第二个画布,更容易实现。它仍然使用Ken的想法来使用globalCompositeOperation
:
context.lineWidth = 2;
context.stroke();
var prev = context.globalCompositeOperation;
context.globalCompositeOperation = "destination-out";
context.fill();
context.globalCompositeOperation = prev;