HTML5 キャンバス: 結合されたパスの周りに単一のストロークを描画する方法を探しています。
たとえば、2 つの重なり合う円がある場合、2 つの重なり合う円ストロークは必要ありませんが、両方の円の結合領域の周りに 1 つのストロークが必要です..
そのチャンスは?
HTML5 キャンバス: 結合されたパスの周りに単一のストロークを描画する方法を探しています。
たとえば、2 つの重なり合う円がある場合、2 つの重なり合う円ストロークは必要ありませんが、両方の円の結合領域の周りに 1 つのストロークが必要です..
そのチャンスは?
を使用して行うことができます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);
境界線を太くするには、図形をメイン キャンバスに戻すときにオフセットを増やすだけです。