【この教材について】
2019.2.10現在の作動確認
◎ PC版 Google Chrome 72.0.3626.96
◎ Android版 Google Chrome
◎ Microsoft Edge 42.17134.1.0
◎ Firefox Quantum 65.0
◎ Internet Explorer 11
◎ windows版 Safari

 この教材は,HTML5+javascriptで可能となったcanvasによるグラフィックスについて,プログラマー向けに無駄なく正確な解説を行うことを目的としたものではありません.中高生レベルの読者向けに,多少とも厳密さを犠牲にしてでも,例と図を中心として,平易で分かり易い解説となることを目指しています.
 また,技術革新の著しい分野ですので,最新の正確な情報を確かめたい場合には,次のサイトを参考にしてください.
[日本語]
MDN Web docs mozilla canvas チュートリアル
とほほのWWW入門 Canvas 2Dリファレンス
[英語]…日本語訳がまだない箇所を確かめたいときなど
W3C HTML Canvas 2D Context
MDN Web docs mozilla Canvas tutorial

1. canvasを使って円弧を描く方法

円弧(円の一部)または円を描くには,
コンテキスト.arc(中心のx座標, 中心のy座標, 半径, 開始角, 終了角, 回転方向);
の書式で書きます.

-図1-
 図1にように,描画領域の左上端が(0,0)で,右に行くほどx座標(ピクセル単位)が増加します.他方で,初期設定では,y座標は下に行くほど増えることに注意してください.(数学の座標とは上下が逆です).
 したがって,例えば x=50, y=60という点は,キャンバスの左上端から右に50ピクセル,下に60ピクセルだけ進んだところになります.
角と回転方向
(1) 単位はラジアンです.角度の単位:ラジアンは高校数学Ⅱで習いますが,分かりにくい場合に度の単位に直して使うには,次の関数を定義しておくと,度の単位で使える.
function d2r(degree1) //degree_to_radianを短縮したもの
{return degree1 * Math.PI / 180; //円周率πは,Math.PIにより求められる
}
 よく使う角度について,ラジアンと度は次の図のように対応している.

-図2-
(2) 初期設定で,y座標が下に行くほど増えることと対応して,図2に示されるように,始線(0°[0ラジアン])を右向きにとって,円周上で始線から「時計回りに」進んだ角によって,開始角, 終了角の向き(場所)を決めます.次に,回転方向の引数は,反時計方向なら true[1でもよい],時計回りなら false[0でもよいが,-1などはダメ.0以外はすべて真=1と見なされる]で指定します.

- 図3 -    - 図4 -    - 図5 -
 図3~図5は,ラジアンの単位で書いたもので,
図3は
コンテキスト.arc(50,50,40, 0, Math.PI, true);
と書いた場合で,x=50, y=50 を中心とする半径 r=40 の円周のうちで,開始角 0ラジアン,から,終了角πラジアンまで反時計回りに回ったときの半円になります.(線の色,幅は初期設定の黒,1ピクセルです)
図4は
コンテキスト.arc(150,50,40, 0, Math.PI, false);
と書いた場合で,x=150, y=50 を中心とする半径 r=40 の円周のうちで,開始角 0ラジアン,から,終了角πラジアンまで時計回りに回ったときの半円になります.(線の色,幅は初期設定)
図5は
コンテキスト.arc(250,50,40, 5*Math.PI/3, Math.PI/3, true);
と書いた場合で,x=250, y=50 を中心とする半径 r=40 の円周のうちで,開始角 5π/3ラジアン,から,終了角π/3ラジアンまで反時計回りに回ったときの円弧になります.(線の色,幅は初期設定)
この例のように,開始角 a,終了角 b で a>b のときは,開始角と終了角を入れ換えて,回転方向を逆向きにしたものと一致します.すなわち,図5は
コンテキスト.arc(250,50,40, Math.PI/3, 5*Math.PI/3, false);
と同じになります.
度の単位で書く 図6~図8は,度の単位で書くために,度からラジアンに変換する関数d2r(degree1)を定義して,開始角,終了角にそれを使っています.

- 図6 -    - 図7 -    - 図8 -
図6は
コンテキスト.arc(50,50,40, d2r(30), d2r(120), 1);
と書いた場合で,x=50, y=50 を中心とする半径 r=40 の円周のうちで,開始角 30°から,終了角120°まで反時計回り(1はtrue)に回ったときの円弧になります.2バイト文字の°のマークは書かない.(線の色は,コンテキスト.strokeStyle = "red";により赤,線の幅はコンテキスト.lineWidth = 10;により10ピクセル)
図7は
コンテキスト.arc(150,50,40,d2r(30), d2r(120), 0);
と書いた場合で,x=150, y=50 を中心とする半径 r=40 の円周のうちで,開始角 30°から,終了角120°まで時計回り(0はfalse)に回ったときの円弧になります.2バイト文字の°のマークは書かない.(線の色は,コンテキスト.strokeStyle = "blue";により青,線の幅はコンテキスト.lineWidth = 20;により20ピクセル)
図8は
コンテキスト.arc(250,50,20,d2r(30), d2r(120), -1);
と書いた場合で,x=250, y=50 を中心とする半径 r=20 の円周のうちで,開始角 30°から,終了角120°まで時計回り(-1はtrueなので,1の逆ではないことに注意)に回ったときの円弧になります.2バイト文字の°のマークは書かない.(線の色は,コンテキスト.strokeStyle = "green";により緑,線の幅はコンテキスト.lineWidth = 20;により20ピクセル).半径20ピクセルの円弧[参考としてやや白い色で示した線]に,幅20ピクセルの円周を描いても内部は埋まらないことに注意…幅20ピクセルの線は,半径20ピクセルの線を真ん中にして,その両側10ピクセルずつの線が引かれる

2. 数学座標を使って円弧を描く方法


-図9-
数学座標では,コンピュータ上に初期設定で示される座標とは異なり,図9のようにy座標は上に行くほど大きくなります.このようにコンピュータ上の初期設定を変更して,x座標は変更せずにy座標だけ逆向きの座標系に変換するには,
コンテキスト.scale(1, -1);
とします.一般に,コンテキスト.scale(s, t);とすると,x方向にs倍,y方向にt倍して描画されます.
注意(1)この変換を行うと,円周上で角度を表す位置も上下が逆になり,次の図10のようになることに注意しましょう.

-図10-

注意(2)コンテキスト.scale(1, -1);によって,y座標の符号を逆にすると,次の図11,図12の元の座標のように画面上のy座標がすべて負になり,使いにくくなります.そこで,コンテキスト.translate(a, b);によって,原点を(a, b)に平行移動する変換を併用するとよい.
 ただし,[1] コンテキスト.scale(1, -1);コンテキスト.translate(a, b);もすでに描画されている図形には影響しない. [2] コンテキスト.scale(1, -1);コンテキスト.translate(a, b);の記述順序が重要です.順序を変えると,異なる結果になります.


数学の教科書に出てくる,図13のような座標系にするには,コンテキスト.translate(50, 50);の後にコンテキスト.scale(50, -50);とすればよい.

- 図13 -
ただし,このようにスケールを拡大すると,デフォルトの線幅1では太すぎるので,コンテキスト.lineWidth = 0.01;などと半径の100分の1程度の線幅に変更する.
 また,canvasのレファレンス・マニュアルに書かれている回転方向(anticlockwise)は,「反時計回り(true),時計回り(false)で分けるよりは」「x軸の正の向きからy軸の正の向きに(小さい方の角)90°で回る向きがfalse=0,(大きい方の角)270°で回る向きがtrue=1」と考えると,ブラウザでの実装と合う.
 さらに,注意すべきこととして,コンテキスト取得後は,beginPath()の呼び出しの有無にかかわらず,コンテキスト.translate(a, b);コンテキスト.scale(s, -t);を何度も使うと,座標系がさらに変換されることとなるので,複数の図形を同一キャンバス上に描く場合でも,コンテキスト.translate(a, b);コンテキスト.scale(s, -t);は,初めに「1回」だけ使用することにすると,同一座標系での描画にできる.

- 図14 -    - 図15 -    - 図16 -
<canvas id="my_canvas3" width="300" height="100"></canvas>
<script type="text/javascript">
function deg2rad(degree1)
{return degree1 * Math.PI / 180;
}//度の角度をラジアンに変換する関数の定義
cname3 = document.getElementById("my_canvas3");
ctx3 = cname3.getContext("2d");
ctx3.translate(50,50);
ctx3.scale(50,-50);
//translate()とscale()は初めに1回だけ使う
ctx3.beginPath();
ctx3.arc(0,0,1,deg2rad(0), deg2rad(150),false);
//0°から150°まで左回り
ctx3.lineWidth = 0.01;
ctx3.stroke();
図14は
コンテキスト.arc(0,0,1,deg2rad(0), deg2rad(150),false);
により,0°から150°まで,x正→y正の近回り(=false)で円弧を描いたもの
(※反時計回りがtrueと覚えていると合わない)
ctx3.beginPath();
ctx3.arc(2,0,1,deg2rad(60),deg2rad(270),true);
//60°から270°まで右回り
ctx3.strokeStyle = "red";
ctx3.lineWidth = 0.02;
ctx3.stroke();
図15は
コンテキスト.arc(2,0,1,deg2rad(60),deg2rad(270),true);
により,60°から270°まで,x正→y正の遠回り(=true)で円弧を描いたもの
ctx3.beginPath();
ctx3.arc(4,0,1,deg2rad(270), deg2rad(60),false);
//270°から60°まで左回り
ctx3.strokeStyle = "green";
ctx3.lineWidth = 0.03;
ctx3.stroke();
</script>
図16は
コンテキスト.deg2rad(270), deg2rad(60),false);
により,270°から60°まで,x正→y正の近回り(=false)で円弧を描いたもの
図15と同じ形になる

3. 円を描く方法

円(ちょうど1周しているもの)を描くには,開始角と終了角として360°(2πラジアン)だけ異なる角度を指定すればよい.回転方向はどちらでもよいが,0°から0°のような「同じ値」では何も描かれない.
- 図17 -  - 図18 -  - 図19 -  - 図20 -
図17は,コンテキスト.translate(50, 50);の後コンテキスト.scale(40, -40);を実行,その後,コンテキスト.arc(0,0,1,0, 2*Math.PI,false);により,中心(0,0),半径1の円を開始角0ラジアン,終了角2πラジアンで左回りに1周したものです.
図18は,コンテキスト.arc(2.1,0,1,2*Math.PI,0,false);により,中心(2.1,0),半径1の円を開始角2πラジアン,終了角0ラジアンで左回りに1周したものです.(同じく円になります)
図19は,コンテキスト.arc(4.2,0,1,2*Math.PI, 4*Math.PI,true);により,中心(4.2,0),半径1の円を開始角2πラジアン,終了角4πラジアンで右回り1周し,水色の中塗りでコンテキスト.fill();を青のラインでコンテキスト.stroke();を実行したものです.
図20は,コンテキスト.arc(6.3,0,1,Math.PI/6, 3*Math.PI/2,false);により,中心(6.3,0),半径1の円を開始角π/6ラジアン,終了角3*π/2ラジアンで左回りに取ってから,緑色の中塗りでコンテキスト.fill();を実行したものです.
○== メニューに戻る ==