つれづれなる備忘録

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

ブログデザイン備忘録~canvasによる曲線描画

 前回はcanvasjavascriptを用いて直線を描画を行う方法について紹介したが、今回は円などの曲線の描画方法について紹介する。

atatat.hatenablog.com

1.円の描画

 まずcanvas要素とjavascript関数を用いて円を描画する方法について説明する。円だけを描画する関数はなく、実際には円弧を描画するarc()を利用して円を描くことになる。

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

<script>
var canvas = document.getElementById('canv_curv1');
if (canvas.getContext) {
    var context = canvas.getContext('2d');
    context.beginPath();
    context.arc(150,75,50,0,2*Math.PI);//円を描画
    context.stroke(); 
}
</script>

関数arc(x0,y0,r,ph_sartt,ph_end,counterclock)は円弧の中心座標x0,y0、円弧の半径r, 円弧の開始角、円弧の終了角、円弧の描画方向を半時計周りであればtrue, 時計回りであればfalseを指定する。 上の例ではキャンバス(300x150)の中心(150,75)から半径50の円を描くようにしている。開始角は0度、終了角を360度とするが角度はそれぞれラジアン単位で指定するため、πを利用するためMath.PIを用いている。 円の描画実行結果を下に示す。

2. 円弧の描画

arc関数の引数を変えることで円弧を描画することができる。以下は開始角を45度、終了角を360度にしてcounterclockを左はfalse(デフォルト)、右はtrueにした場合の円弧の描画を行う。

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

<script>
var canvas = document.getElementById('canv_curv2');
if (canvas.getContext) {
    var context = canvas.getContext('2d');
    context.beginPath();
    context.arc(100,75,50,45/180*Math.PI,2*Math.PI);//時計回りの円弧
    context.stroke(); //描画を指示する
    context.beginPath();
    context.arc(200,75,40,45/180*Math.PI,2*Math.PI,true);//反時計回りの円弧
    context.stroke(); //描画を指示する
}
</script>

以下の実行結果で0度(360度)は円弧右にあること、counterclockがfalseの場合時計回り、trueの場合は反時計回りに円弧が描画されていることが確認できる。

円弧を描く方法としてはarcの他に直線と組み合わせた円弧を描くarcTo関数がある。arcTo(x1, y1, x2, y2, radius)は直前にmoveTo(x0,y0)と座標を指定した状態で点F(x0,y0)と点C(x1,y1)を結ぶ直線および点C(x1,y1)と点G(x2,y2)を結ぶ直線を描き、半径radiusの円と2本の直線の交点をD,EとしたときにFDEまでが描画される。(下図参照)

"arcToの座標"
arcToの座標

以下がコード例だが、(x0,y0)=(40,20)と(x1,y1)=(140,120)を結ぶの直線と半径20の円との交点までの直線と(x1,y1)=(140,120)と(x2,y2)=(240,20)を結ぶ直線の半径20の円との交点までの円弧を描画する。

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

<script>
var canvas = document.getElementById('canv_curv3');
if (canvas.getContext) {
    var context = canvas.getContext('2d');
    context.beginPath();
    context.moveTo(40,20); //直線の開始点
    context.arcTo(140,120,240,20,20); //直線+円弧描画
    context.stroke(); 
}
</script>

3. ベジエ曲線の描画

 曲線としては円弧の他にベジエ曲線をを描画することができる。2次のベジエ曲線を描画するにはquadraticCurveTo(cpx, cpy, x, y)を用いる。下図の曲線の開始点B:(x0,y0)はあらかじめmoveTo(x0,y0)で移動した状態で曲線の終了点C:(x,y)を指定する。曲線の曲がり方はコントロール点(cpx,cpy)を指定する。2次のベジエ曲線の場合、開始点と終了点の接戦の交点が(cpx,cpy)となるように曲線が曲げられる。

"2次ベジエ曲線"
2次ベジエ曲線

以下のコードは、上下に2本の2次ベジエ曲線を描画するが、開始点/終了点はy方向にシフト(x座標は同一で、y座標だけオフセットさせた)させて、コントロール点は同一にしている。コントロール点が離れている下のベジエ曲線の方が曲線のカーブが急峻になっていることがわかる。

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

<script>
var canvas = document.getElementById('canv_curv4');
if (canvas.getContext) {
 var context = canvas.getContext('2d');
    context.beginPath();
    context.moveTo(50,100);
    context.quadraticCurveTo(150,20,250,100);//2次ベジエ曲線
    context.stroke(); //上のベジエ曲線
    context.beginPath();
    context.moveTo(50,200);
    context.quadraticCurveTo(150,20,250,200);
    context.stroke(); //下のベジエ曲線
}
</script>

 3次のベジエ曲線bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)を用いる。コントロール点の役割は2次のときと同じだが、開始点と終了点のコントロール点を別々に設定できる。 下図の関係で示すと開始点D(x0,y0)のコントロール点は点F(cp1x,cp2y)で、終了点E(x,y)に対するコントロール点は点G(cp2x,cp2y)となる。

"3次ベジエ曲線"
3次ベジエ曲線

以下に3字のベジエ曲線を描画するコードを示す。

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

<script>
var canvas = document.getElementById('canv_curv5');
if (canvas.getContext) {
 var context = canvas.getContext('2d');
    context.beginPath();
    context.moveTo(50,100);
    context.bezierCurveTo(100,20,200,20,250,100);//3次ベジエ曲線
    context.stroke();
}
</script>

ベジエ曲線は曲線をコントロール点の座標で指定する必要があるが、直観ではわかりにくく別のソフトウェア等で座標がわかっていないと使いにくいと思う。

4. まとめ

 今回はcanvasjavascriptを用いた曲線の描画として、円、円弧、ベジエ曲線の描画方法を紹介した。基本的に直観的に扱いやすいのは円、円弧が中心になると思う。