【この教材について】
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(←図12〜16のsetLineDash()を認識しない)

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

1. canvasを使って直線を描く方法

次の例は,canvasを使って図1のような三角形を描く書き方です.
<canvas id="my_canvas1" width="200" height="100"></canvas>
<!-- (1) canvasの設置 //-->
<script type="text/javascript">
cname1 = document.getElementById("my_canvas1");
<!-- (2) canvasオブジェクトをid識別子から取得 //-->
ctx1 = cname1.getContext("2d");
<!-- (3) 描画コンテキストを取得する //-->
ctx1.beginPath();
<!-- (4) パス(折れ線や曲線の経路のリスト)の記録を開始 //-->
ctx1.moveTo(100,10);
<!-- (5) 始点を(100,10)に移動する //-->
ctx1.lineTo(10,90);
<!-- (6) (10,90)まで線で結ぶ //-->
ctx1.lineTo(190,90);
<!-- (7) さらに(190,90)まで線で結ぶ //-->
ctx1.closePath();
<!-- (8) 終点と始点を結んで折れ線を閉じる //-->
ctx1.stroke();
<!-- (9) 表示する //-->
</script>

- 図1 -
【解説】
この例 のように,(2)でcanvas要素オブジェクトをid識別子から取得する操作が行われる場合には,それよりも前に(1)の記述がなければなりません.
 これに対して,上記の一連の描画作業(2)〜(9)が次のように関数の中で定義されていて,HTMLファイルの読み込み動作が完了してから,何らかのタイミングで(この例では,ボタン2がクリックされたらこの関数が実行される.この他,HTMLのbodyタグにonLoad="draw_triangle2()"と記述して,HTMLファイルの読み込み動作完了直後にこの関数を実行されるようにしてもよい.)この関数が実行されるようになっていれば,(1)(2)はどちらが先に書かれていてもよい.
関数は定義のとき(funtion draw_triangle2()...)には,まだ実行されず,scriptの中で関数の名前が直接書かれたとき(draw_triangle2();)に実行されるので,実行されるときまでにcanvas要素オブジェクトが読み込まれていればよい.
<a href="javascript:draw_triangle2()">⇒ボタン2</a><br>
<script type="text/javascript">
function draw_triangle2()
{cname2 = document.getElementById("my_canvas2");
ctx2 = cname2.getContext("2d");
ctx2.beginPath();
ctx2.moveTo(100,10);
ctx2.lineTo(10,90);
ctx2.lineTo(190,90);
ctx2.closePath();
ctx2.stroke();
}
</script>
<canvas id="my_canvas2" width="200" height="100"></canvas>

⇒ボタン2
- 図2 -

(6)(7) のように,コンテキスト識別子.lineTo()でつないでいくと,各々の直線の終点が次の直線の始点となって,折れ線が描かれます.
これに対して,(5)のコンテキスト識別子.moveTo()は,いったんペンを持ち上げて(線を描かずに)新たな始点に移動することを表します.
次の例では,2本の直線が描かれます.
<canvas id="my_canvas3" width="200" height="100"></canvas>
<script type="text/javascript">
cname3 = document.getElementById("my_canvas3");
ctx3 = cname3.getContext("2d");
ctx3.beginPath();
ctx3.moveTo(100,10);
ctx3.lineTo(10,90);

ctx3.moveTo(10,10);
ctx3.lineTo(190,90);

ctx3.stroke();
</script>

- 図3 -

2. 線の色,幅,終端の形を指定するには

線の色は,デフォルト(既定値)では黒になります.
 この色を変更するには,
コンテキスト.strokeStyle = "";
の書式で色を指定します.
色は
(1) "red","green","blue"などの名前で書く方法
(2) "#ff0000","#00ff00","#0000ff"のように#を付けて2桁ずつ16進数で書く方法
"f00","0f0","00f"のように1桁ずつの16進数で書いてもよい.
(3) "rgb(255,0,0)","rgb(0,255,0","rgb(0,0,255)"のようにrgb()関数に赤緑青の濃さを10進数で0〜255までの範囲で書く方法
"rgb(100%,0%,0%)","rgb(0%,100%,0%","rgb(0%,0%,100%)"のように百分率で書いてもよい.
などがあり,いずれでも指定できます.…上記の(1)(2)(3)は互いに同じ色を表します.
線の幅は,デフォルト(既定値)では1になります.
 線の幅を指定するには,
コンテキスト.lineWidth = n;
の書式でnのところに1,2,3,...の整数を指定します.
終端の形(始点と終点の形)は,デフォルト(既定値)では"butt"になります."square"は"butt"とよく似た形ですが,線の太さの半分だけ余白のキャップが付きます."round"は線の太さの半分を半径とする半円のキャップがつきます.

butt square round
<canvas id="my_canvas4" width="100" height="100"></canvas>
<script type="text/javascript">
cname4 = document.getElementById("my_canvas4");
ctx4 = cname4.getContext("2d");

ctx4.beginPath();
ctx4.moveTo(10,10);
ctx4.lineTo(90,10);
ctx4.stroke();
<!-- (1) 幅1の黒線を描く //-->
ctx4.beginPath();
ctx4.strokeStyle = "red";
ctx4.moveTo(10,30);
ctx4.lineTo(90,30);
ctx4.stroke();
<!-- (2) 幅1の赤線を描く //-->
ctx4.beginPath();
ctx4.moveTo(10,50);
ctx4.lineTo(90,50);
ctx4.strokeStyle = "blue";
ctx4.lineWidth = 5;
ctx4.stroke();
<!-- (3) 幅5の青線を描く //-->
ctx4.beginPath();
ctx4.moveTo(10,70);
ctx4.lineTo(90,70);
ctx4.strokeStyle = "green";
ctx4.lineWidth = 10;
ctx4.lineCap = "round";
ctx4.stroke();
</script>
<!-- (4) 幅10の緑線を丸いキャップで描く //-->


- 図4 -
【解説】
この例では,各々の線を描く操作を
コンテキスト.beginPath();
から始めて
コンテキスト.stroke();
で描画しています.beginPath()を英語的に考えれば,「経路を記録し始める」となりますが,実際にはbeginPath()と書かなくても記録はできます.beginPath()の働きは,「それ以前の経路情報を初期化(リセット)して,デフォルトに戻す」という所にあるようです.
 したがって,moveTo(), lineTo(), ... などと記録していって,stroke()で描画するまでにbeginPath()が入ると,それまでの経路情報が消えてしまいます.stroke()で描画されたものは消えません.
 beginPath()によって初期化されるのは,経路情報(パス)だけで,コンテキストを構成している線の色や太さなどの描画状態には影響しませんが,線の幅,終端形状はどちらに入るのかなど個別に覚えるのは大変ですから,一連の記述をbeginPath()からstroke()までのブロックとして記述するとよいでしょう.

3. 塗りつぶし,透明度,多角形の頂点の形状の設定

多角形を描くとき,境界線の色と内部の塗りつぶしの色は別に指定できます.
 次の図5では,fillStyle = "pink"で五角形の中を塗りつぶし
コンテキスト.fill();
た後に,strokeStyle = "red",lineWidth = 2で境界線を描いています.
コンテキスト.stroke();
図6では,境界線を描いてから中を塗りつぶしています.(境界線は芯の部分と縁の部分があって,塗りつぶしは芯から内部に対して行われるので,不透明に塗りつぶすと境界線の太さは半分になります.)
図7では,コンテキスト.fillStyle = "rgb(100%,80%,80%,0.8)"により,中塗りの透明度を0.8にしています.(透明度は,0が完全な透明,デフォルトの1は完全な不透明)

- 図5 -    - 図6 -    - 図7 -
多角形の頂点の形状は,図8のような鋭く尖った形(デフォルトではmiter)
コンテキスト.lineJoin = "miter"
図9のような丸い形
コンテキスト.lineJoin = "round"
図10のような面取りした形
コンテキスト.lineJoin = "bevel"
が指定できます.

- 図8 -    - 図9 -    - 図10 -

4. 破線,1点鎖線,2点鎖線

単純に直線を描けば,実線が描かれますが,破線,1点鎖線,2点鎖線など「線と空白」から成るものを描くには,
コンテキスト.setLineDash(配列);
によって,線の長さ,空白の長さを配列によって指定します.

-図11-
配列はカギ括弧[ ]で囲んで,カンマ区切りで示します.図11上の直線の場合,
塗る(2ピクセル),空白(1ピクセル)
の繰り返しになるので,
コンテキスト.setLineDash([2, 1]);
と書きます.図11下の直線の場合,
塗る(1ピクセル),空白(1ピクセル)塗る(3ピクセル),空白(1ピクセル)
の繰り返しになるので,
コンテキスト.setLineDash([1, 1, 3, 1]);
と書きます.
 カギ括弧[ ]で囲んで書く配列は,一度書いたら後から書き換えることはできませんが,配列に変数名を付けて定義すれば,後から書き換えることもできます.
配列名 = new Array(3,1);
この場合の,配列の書き換え方については,配列の項目を読んでください.
 配列の奇数番目は塗る長さ,偶数番目は空白の長さなので,1点鎖線や2点鎖線のように規則的に繰り返される直線の形を配列で表すためには,偶数個の要素から成る配列を指定しなければなりません.(もし奇数個から成る配列を書くと,途中で塗る長さと空白の長さが入れ替わって,見た目が奇妙なものになります.)

-図12- -図13- -図14- -図15- -図16-
図12は,コンテキスト.setLineDash([2, 2]) としたもので,塗る長さも空白の長さも2ピクセルという短い鎖線(破線)になります.
図13は,コンテキスト.setLineDash([6, 3]) として,線の色を青に,線の幅を3にしたもので,図12よりも長い鎖線(破線)になります.
図14は,コンテキスト.setLineDash([2, 2, 10, 2])として,線の色を緑に,線の幅を4にしたもので,一点鎖線になります.
図15は,コンテキスト.setLineDash([2, 2, 2, 2, 10, 2])として,線の色を黒に,線の幅を2にしたもので,二点鎖線になります.
図16は,コンテキスト.setLineDash([3, 9, 6, 1, 2])として,線の色を赤に,線の幅を2にしたもので,破線パターンが奇数個となっているため,塗りと空白が途中で逆転します.
○== メニューに戻る ==