つれづれなる備忘録

日々の発見をあるがままに綴る

ブログデザイン備忘録~canvasによる図形の合成

 今回はcanvasjavascriptを用いて複数の図形を合成して表示する方法について紹介する。

atatat.hatenablog.com

1.図形の重ね合わせ

 複数の図形の重ね方を指定することで単純な和の他、差やANDなど様々な図形を合成することができる。globalCompositeOperationに様々なプロパティを指定することで図形同士の合成方法を指定できる。 デフォルトはsource-overで後から描画される図形が上に重なる。ここでdestination-overとすると重なり順が逆になり、先に描画される図形が上に重なる。 以下のコードは先に描画される四角形は青、後で描画される四角形は赤で示し、左側がデフォルト(指定なし)のsource-in,右側がdesitionation-overにしたときの合成された図形の描画を示す。 なお重ね合わせを指定するglobalCompositeOperationは重ね合わせる図形描画の手前に入れるとよい。

<canvas width="300" height="150" id="canv_comp1" style="background-color:yellow;"></canvas>

<script>
var canvas = document.getElementById('canv_comp1');
if (canvas.getContext) {
    var context = canvas.getContext('2d');
    context.fillStyle = "blue";
    context.fillRect(20,20,80,80);
    context.fillStyle = "red";
    context.fillRect(60,60,80,80);   
    context.fillStyle = "blue";
    context.fillRect(170,20,80,80);
    context.globalCompositeOperation = "destination-over";
    context.fillStyle = "red";
    context.fillRect(210,60,80,80);
    context.stroke();
}
</script>

source-atopは2つの図形が重なったときに、先に描画された図形と重なった部分は後から描画された図形で、それ以外(後から描画された図形で重なっていない部分)は削除する。

<canvas width="300" height="150" id="canv_comp2" style="background-color:yellow;"></canvas>

<script>
var canvas = document.getElementById('canv_comp2');
if (canvas.getContext) {
    var context = canvas.getContext('2d');
    context.fillStyle = "blue";
    context.fillRect(120,40,80,80);
   context.globalCompositeOperation = "source-atop";
    context.fillStyle = "red";
    context.fillRect(160,80,80,80);
}
</script>

destination-atopsource-atopの逆で2つの図形が重なったときに、先に描画された図形と重なった部分は先に描画された図形で、先に描画された図形で重なっていない部分は削除する。

<canvas width="300" height="150" id="canv_comp3" style="background-color:yellow;"></canvas>

<script>
var canvas = document.getElementById('canv_comp3');
if (canvas.getContext) {
    var context = canvas.getContext('2d');
    context.fillStyle = "blue";
    context.fillRect(120,20,80,80);
   context.globalCompositeOperation = "destination-atop";
    context.fillStyle = "red";
    context.fillRect(160,60,80,80);
}
</script>

lighterは2つの図形の重なった部分は混色で表示する。

<canvas width="300" height="150" id="canv_comp4" style="background-color:yellow;"></canvas>

<script>
var canvas = document.getElementById('canv_comp4');
if (canvas.getContext) {
    var context = canvas.getContext('2d');  
    context.fillStyle = "blue";
    context.fillRect(20,20,80,80);
   context.globalCompositeOperation = "lighter";
    context.fillStyle = "red";
    context.fillRect(60,60,80,80);
    context.stroke();
}
</script>

2. 図形の切り出し

 source-inは図形同士が重なった部分だけを残すが、後で描画した図形の部分を残す。

<canvas width="300" height="150" id="canv_comp5" style="background-color:yellow;"></canvas>

<script>
var canvas = document.getElementById('canv_comp5');
if (canvas.getContext) {
    var context = canvas.getContext('2d');
    
    context.fillStyle = "blue";
    context.fillRect(120,20,80,80);
   context.globalCompositeOperation = "source-in";
    context.fillStyle = "red";
    context.fillRect(160,60,80,80);
    context.stroke();
}
</script>

 destination-inは図形同士が重なった部分だけを残すが、先に描画した図形の部分を残す。

<canvas width="300" height="150" id="canv_comp6" style="background-color:yellow;"></canvas>

<script>
var canvas = document.getElementById('canv_comp6');
if (canvas.getContext) {
    var context = canvas.getContext('2d');    
    context.fillStyle = "blue";
    context.fillRect(120,20,80,80);
   context.globalCompositeOperation = "destination-in";
    context.fillStyle = "red";
    context.fillRect(160,60,80,80);
    context.stroke();
}
</script>

source-outは後から描画した図形から先に描画した図形を差し引く。

<canvas width="300" height="150" id="canv_comp7" style="background-color:yellow;"></canvas>

<script>
var canvas = document.getElementById('canv_comp7');
if (canvas.getContext) {
    var context = canvas.getContext('2d');    
    context.fillStyle = "blue";
    context.fillRect(120,20,80,80);
   context.globalCompositeOperation = "source-out";
    context.fillStyle = "red";
    context.fillRect(160,60,80,80);
    context.stroke();
}
</script>

destination-outは先に描画した図形から後に描画した図形を差し引く。

<canvas width="300" height="150" id="canv_comp8" style="background-color:yellow;"></canvas>

<script>
var canvas = document.getElementById('canv_comp8');
if (canvas.getContext) {
    var context = canvas.getContext('2d');    
    context.fillStyle = "blue";
    context.fillRect(120,20,80,80);
   context.globalCompositeOperation = "destination-out";
    context.fillStyle = "red";
    context.fillRect(160,60,80,80);
    context.stroke();
}
</script>

<canvas width="300" height="150" id="canv_comp9" style="background-color:yellow;"></canvas>

`xor`は2つの図形の排他的論理和XORを表示する。
<script>
var canvas = document.getElementById('canv_comp9');
if (canvas.getContext) {
    var context = canvas.getContext('2d');    
    context.fillStyle = "blue";
    context.fillRect(120,20,80,80);
   context.globalCompositeOperation = "xor";
    context.fillStyle = "red";
    context.fillRect(160,60,80,80);
    context.stroke();
}
</script>

3. 他の図形での例

 上記の例は四角形で示したが、他の図形で例えば円でも実行できる。下のコードは四角形と円のXORを実行したものになる。ただし、描画線を処理するために、描画線の色をキャンバスの黄色と同じにしている。

<canvas width="300" height="150" id="canv_comp10" style="background-color:yellow;"></canvas>

<script>
var canvas = document.getElementById('canv_comp10');
if (canvas.getContext) {
    var context = canvas.getContext('2d');    
    context.fillStyle = "blue";
    context.fillRect(60,20,80,80);
    context.globalCompositeOperation = "xor";
    context.fillStyle = "red";
    context.strokeStyle = "yellow"; //キャンバスと同じ色
    context.arc(140,100,40,0,2*Math.PI);//円を描画
    context.fill();
    context.stroke();
}
</script>

4. まとめ

 今回はcanvasjavascriptを用いて複数の図形を合成して表示する方法としてglobalCompositeOperationの指定とその効果について紹介した。