2011/07/31

[js][canvas]中抜けのパスを描画する

このエントリーをはてなブックマークに追加
canvasのパス描画の話です。

重ねたところを中抜きさせる方法です。
逆周りのパス書くと相殺されるようです。

●逆順のパスを描く



基準となるパスと、逆周りのパスを重ねると、重複したところが抜けます。arcメソッドの最後の引数はtrueとfalseでパスの向きが変わるような仕様でした。こうやって使うためのものなのか、というのが解った。

// 中空きのパスなら問題なく描画できる
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(100, 100, 100, 0, Math.PI * 2, true);
ctx.arc(100, 100, 80, 0, Math.PI * 2, false);
ctx.fill();
ctx.fillStyle = "blue";
ctx.beginPath();
ctx.arc(200, 100, 100, 0, Math.PI * 2, true);
ctx.arc(200, 100, 80, 0, Math.PI * 2, false);
ctx.fill();





円と、逆回転のパスで描いた円を僅かにスライドさせて重ねると、排他的論理和のベン図のような図形ができる。なるほど、ここまではいい。
だけどこうなると三種類の円での排他的論理和のベン図は無理そうです。
当然、上記の円を三つ重ねても望みどおりの図形はできない。

うーむ。
やっぱりまだ納得がいっていない。
完全に、すっぽり中空の図形だったら問題はないのです。だけど中が抜ける図形であることが描画前にわかってない場合は、内包判定しないといけなくて、これは限りなく面倒でしょう。


●globalCompositeOperationを使う方法


globalCompositeOperationを使うことでも、似たようなことはできます。

globalCompositeOperation="source-out"とかやれば、すでに描画されてるところを背景色で塗りつぶすように指定ができるわけです。

Canvasリファレンス - globalCompositeOperation = "合成方法"
http://www.htmq.com/canvas/globalCompositeOperation.shtml

感じとしては、前者の方法(逆順のパスを描く方法)のほうが、塗りつぶしの描画が一回で住む分、きっと高速でしょう。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// source-overで上書き(初期値)
// source-out(xor)で排他描画
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(100, 100, 100, 0, Math.PI * 2, true);
ctx.fill();
ctx.globalCompositeOperation = "source-out";
ctx.beginPath();
ctx.arc(100, 100, 80, 0, Math.PI * 2, true);
ctx.fill();
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "blue";
ctx.beginPath();
ctx.arc(200, 100, 100, 0, Math.PI * 2, true);
ctx.fill();
ctx.globalCompositeOperation = "source-out";
ctx.beginPath();
ctx.arc(200, 100, 80, 0, Math.PI * 2, true);
ctx.fill();




もちろん、描画されているかどうかで判断されるので背景が描画されてたら使えないのです。
これも条件が厳しすぎて、まあ使い勝手がいいとは言えない。


●fill("everodd")を使う方法

追記:20161017

久しぶりにcanvasをいじってたら、どうやら塗りつぶしのタイミングで奇遇規則を指定できるようなので補足しておきます。
この記事の公開当時からこの設定があったかどうかは不明です。
ctx.fill("everodd");
fillを呼ぶタイミングで、evenoddを指定すると偶数奇数ルール(奇偶規則)が設定されます。
なおnonzeroを指定すると、省略時と同じ非ゼロ回転数ルールとなります。

うーん、こんなに簡単に…。

http://stackoverflow.com/questions/12446790/using-even-odd-fill-on-html-canvas

0 件のコメント :

コメントを投稿