0

HTML5 画布:我正在寻找一种在组合路径周围绘制单个笔划的方法。

例如,如果我有两个重叠的圆圈,我不想有两个重叠的圆圈笔画,而是在两个圆圈的组合区域周围有一个笔画..

有机会吗?

4

2 回答 2

2

它可以通过使用来完成globalCompositeOperation。有多种方法可以自己绘制形状,但这是一种方法(对于演示中的两个矩形圆圈):

在此处输入图像描述

  • 第 1 步:设置普通画布
  • 第 2 步:设置屏幕外画布

更新不知道我怎么会错过明显的,但你当然可以先划圈,然后用复合模式和填充打一个整体——快得多(我想当我想出偏移量时我脑子里已经有了图像重绘)。

屏幕外画布的原因是如果您在主画布上已经有一些背景内容。这将被删除,否则我们打孔的地方。如果什么都没有,则将其绘制到单个画布上没有问题-更新的代码:

/// 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);

使用此优化版本的(动画)在线演示

我将保留旧代码,因为它可用于无法抚摸的图像 -

现在将填充的形状绘制到离屏画布上。用你想要的轮廓颜色绘制。

/// 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

要使边框更厚,只需在将形状绘制到主画布时增加偏移量。

于 2013-07-31T19:08:52.860 回答
0

这是我目前的解决方案。不需要第二个画布,更容易实现。它仍然使用Ken的想法来使用globalCompositeOperation

context.lineWidth = 2;
context.stroke();
var prev = context.globalCompositeOperation;
context.globalCompositeOperation = "destination-out";
context.fill();
context.globalCompositeOperation = prev;
于 2013-08-01T12:09:53.367 回答