Revision 453525 of canvas に図形を描く

  • リビジョンの URL スラグ: Web/Guide/HTML/Canvas_tutorial/Drawing_shapes
  • リビジョンのタイトル: canvas に図形を描く
  • リビジョンの ID: 453525
  • 作成日:
  • 作成者: ethertank
  • 現行リビジョン はい
  • コメント

このリビジョンの内容

グリッド

描き始める前に、 canvas のグリッドもしくは 座標空間 について話す必要があります。前のページの HTML テンプレートは幅 150 ピクセル、高さ 150 ピクセルの canvas 要素を持っていました。私はこの画像をデフォルトのグリッドに上書きして描きました。普通 グリッド上の 1 単位は canvas 上の 1 ピクセルに相当します。このグリッドの原点は左上の角 ( 座標 (0,0) ) に位置します。全ての要素がこの原点から相対的に配置されます。よって青い正方形の左上の場所は左から x ピクセル、上から y ピクセル (座標 (x,y) ) に来ます。 このチュートリアルの後半で原点を他の位置へずらす方法、グリッドを回転したり、伸縮したりさえする方法を見ることになります。今はデフォルトで我慢しましょう。

矩形を描く

SVG とは異なり、canvas は 1 つの原始図形「矩形」のみをサポートしています。 他の全ての図形は 1 つ以上のパスを組み合わせて作らなくてはなりません。幸いなことに、とても複雑な図形を作ることが可能なパスを描く関数のコレクションがあります。

最初に矩形を見ていきましょう。canvas に矩形を描く 3 つの関数があります:

fillRect(x,y,width,height)   // 塗られた矩形を描く
strokeRect(x,y,width,height) // 矩形の輪郭を描く
clearRect(x,y,width,height)  // 指定された領域を消去し、完全な透明にする

3 つの関数は同じパラメータをとります。xy は 矩形の左上の角の canvas 上での位置 (原点から相対的) を指定します。 widthheight は非常に明解です。 動作中のこれらの関数を見てみましょう。

下は、前のページの draw() 関数ですが、私は 3 つの関数を追加しました。

矩形の例

function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    ctx.fillRect(25, 25, 100, 100);
    ctx.clearRect(45, 45, 60, 60);
    ctx.strokeRect(50, 50, 50, 50);
  }
}

結果は以下のように見えるはずです。

{{EmbedLiveSample("Rectangular_shape_example", 160, 160, "https://mdn.mozillademos.org/files/245/Canvas_rect.png")}}

fillRect 関数は 100x100 ピクセルの大きな黒色正方形を描きます。clearRect 関数は中心から 60x60 ピクセルの正方形を取り除き、最後に strokeRect が消去された正方形の中に 50x50 ピクセルの矩形の輪郭を描きます。 後のページで clearRect の代わりのメソッドを見て、描く図形の色と輪郭のスタイルを変更する方法を見ます。

次の節でみるパス関数とことなり、全ての 3 つの矩形関数は直ちに canvas に描きます。

パスを描く

パスを使って図形を描くには、 2 つの余分な作業が必要です。

beginPath()

closePath()

stroke()

fill()

パスを作る最初の作業は beginPath メソッドを呼び出すことです。内部では、パスは図形を一緒に作るサブパス(線、円弧など)のリストとして保存されます。 このメソッドが呼び出される毎に、リストは再初期化され新しい図形を始めることができます。

2 番目の作業は描かれる実際のパスを定義するメソッドを呼び出すことです。それらを簡単にみていくことにしましょう

3 番目は任意の作業ですが、closePath メソッドを呼び出すことです。このメソッドは現在の点から始点に向けて直線を描くことで図形を閉じようとします。もし図形がすでに閉じられているかリストに点がひとつしかない場合はこの関数は何もしません。

最後の作業は stroke と/または fill メソッドを呼ぶことでしょう。これらのうちの一つを呼ぶことは実際に canvas に図形を描きます。 stroke は輪郭の描かれた図形を描き、一方で fill は単色の図形を描きます。

注意: fill メソッドがと呼ばれるときはどんな開いている図形は自動的に閉じられ、 closePath メソッドを使う必要はありません。

三角形の描画

単純な図形(三角形)を描くコードはこのようになります。

function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.moveTo(75,50);
    ctx.lineTo(100,75);
    ctx.lineTo(100,25);
    ctx.fill();
  }
}

表示結果は以下の様になります。

{{EmbedLiveSample("Drawing_a_triangle", 160, 160)}}

ペンの移動

moveTo 関数自体は何も描画しませんが、上述のパスリストの一部です。あなたはこれを 1 枚の紙の上の 1 つの場所からペンか鉛筆を持ち上げてそれを次に置くと考えることができるでしょう。

  moveTo(x, y)

moveTo 関数は 2 つの引数 xy をとります。それらは新しい始点の座標です。

canvas が初期化されるか beginPath メソッドが呼ばれると始点は座標 (0,0) に設定されます。ほとんどの場合 moveTo メソッドを始点を他の場所に置くために使います。moveTo メソッドを繋がっていないパスを描くために使うこともできます。右のスマイリーを見てください。私は moveTo メソッドを使った場所をマークしました(赤い線)

これをあなた自身で試すには、以下のコードを使うことができます。さきほど見た draw 関数に貼り付けるだけです。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.arc(75, 75, 50, 0, Math.PI*2, true); // 外の円
    ctx.moveTo(110,75);
    ctx.arc(75,75,35,0,Math.PI,false);   // 口 (時計回り)
    ctx.moveTo(65,65);
    ctx.arc(60,65,5,0,Math.PI*2,true);  // 左目
    ctx.moveTo(95,65);
    ctx.arc(90,65,5,0,Math.PI*2,true);  // 右目
    ctx.stroke();
  }
}

表示結果は以下の様になります。

{{EmbedLiveSample("Moving_the_pen", 160, 160, "https://mdn.mozillademos.org/files/252/Canvas_smiley.png")}}

繋がっている線を見るには moveTo メソッドを取り除いてください。

注記: arc() 関数とそのパラメータの解説は {{anch("Arcs","円弧")}} の章をご覧下さい。

直線を描くには lineTo メソッドを使います。

lineTo(x, y)

このメソッドは 2 つの引数 xy を取ります。それらは線の終点の座標です。始点は前回のパスに依存します。前回のパスの終点が始点になる、など。始点は moveTo メソッドを使って変更することもできます。

次の例では 2 つの三角形が描かれています。 1 つは塗られてもう 1 つは輪郭線が描かれています。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    // Filled triangle
    ctx.beginPath();
    ctx.moveTo(25,25);
    ctx.lineTo(105,25);
    ctx.lineTo(25,105);
    ctx.fill();

    // Stroked triangle
    ctx.beginPath();
    ctx.moveTo(125,125);
    ctx.lineTo(125,45);
    ctx.lineTo(45,125);
    ctx.closePath();
    ctx.stroke();
  }
}

最初に新しい図形のパスを始めるために beginPath メソッドが呼ばれています。次に 始点を任意の位置に移動するために moveTo メソッドが呼ばれています。三角形の 2 つの側面を作る 2 つの線が描かれています。

{{EmbedLiveSample("Lines", 160, 160, "https://mdn.mozillademos.org/files/238/Canvas_lineTo.png")}}

あなたは塗られた三角形と輪郭線の描かれたものとの違いに気がつくでしょう。上で述べたように、これはパスが塗られると図形は自動的に閉じられるからです。もしこれを輪郭の描かれた三角形に行うと 2 つの線しか描かれず、三角形は完成しません。

// 塗られた三角形
ctx.beginPath();
ctx.moveTo(25,25);
ctx.lineTo(105,25);
ctx.lineTo(25,105);
ctx.fill();

// 輪郭の描かれた三角形
ctx.beginPath();
ctx.moveTo(125,125);
ctx.lineTo(125,45);
ctx.lineTo(45,125);
ctx.closePath();
ctx.stroke();

円弧

円弧や円を描くために arc メソッドを使います。仕様書は arcTo メソッドも述べています。これは Safari はサポートしていますが、現在の Gecko ブラウザは実装していません。

arc(x, y, radius, startAngle, endAngle, anticlockwise)

このメソッドは 5 つのパラメタをとります。xy は円の中心です。Radius は自明です。startAngleendAngle パラメタは円弧の始まりと終点をラジアンで定義します。始まりと終わりの角度は x 軸から計算します。anticlockwise パラメタは true の時には円弧を反時計回りに、それ以外は時計回りの方向に描くブーリアン値です。

注意: arc 関数の角度は度ではなく、ラジアンで計算されます。度からラジアンに変換するにはあなたは以下の JavaScript 式を使うことができます : var radians = (Math.PI/180)*degrees.

以下の例は上で見てきた例よりすこし複雑です。私は全て異なる角度と塗りを持った 12 の異なる円弧を描きます。もし私が上のスマイリーのようにこの例を書いたなら、非常に長い文のリストになったでしょう、第二に円弧を描くとき私は全ての出発点を知る必要があるでしょう。ここで使ったような 90、180、270 度の円弧にはこれは問題にならないでしょう、しかしより複雑なものにはこの方法は難しいすぎるでしょう。

2 つの for ループは円の行と列のループです。全ての円弧毎に私は beginPath を使って新しいパスを始めました。次に何が行われているか読みやすくするために全てのパラメタを変数として書きました。普通これは一文になったでしょう。 xy 座標は充分明確です。 radiusstartAngle は固定です。 endAngle は 180 度(最初の列)から始まって 90 度ずつ完全な円(最後の行)を作るように増加します。 clockwise パラメタの文は最初と 3 番目の列では時計回りの円弧として 2 番目と 4 番目の列では反時計回りの円弧という結果になります。最後に、if 文は上半分は輪郭を描画された円弧に下半分は塗られた円弧を作ります。

function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    for(var i = 0; i < 4; i++) {
      for(var j = 0; j < 3; j++) {
        ctx.beginPath();
        var x              = 25 + j * 50;             // x 座標
        var y              = 25 + i * 50;             // y 座標
        var radius         = 20;                      // 円弧の半径
        var startAngle     = 0;                       // 円孤の始点
        var endAngle       = Math.PI + (Math.PI*j)/2; // 円孤の終点
        var anticlockwise  = i%2==0 ? false : true;   // 時計回りまたは半時計回り

        ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

        if (i>1){
          ctx.fill();
        } else {
          ctx.stroke();
        }
      }
    }
  }
}
{{EmbedLiveSample("Arcs", 160, 210, "https://mdn.mozillademos.org/files/204/Canvas_arc.png")}}

ベジェと二次曲線

パスの次の種類はベジェ曲線で入手可能です。三次および二次の種類で利用可能です。通常複雑な自然の図形を描くのに使われます。

quadraticCurveTo(cp1x, cp1y, x, y);

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);

これらの違いは右の画像を使うことで説明することができます。二次ベジェ曲線は始点と終点(青い点)を持ち、三次ベジェ曲線が 2 つの制御点を持つのに対して 制御点 (赤い点)を 1 つだけ持ちます。

それらのメソッドの両方の xy パラメータは終点の座標です。cp1xcp1y は最初の制御点、 cp2xcp2y は 2 番目の制御点の座標です。

Adobe Illustrator のようなベクタードローイングソフトとは違い、何をやっているのかの直接の視覚的フィードバックが得られないので、二次および三次ベジェ曲線を使うことはとても挑戦的です。このことは複雑な図形を描くことをとても難しくします。以下の例で、いくつかの単純な有機的な図形を描きます、しかしもしあなたに時間と特に忍耐があればはるかに複雑な図形を作ることができます。

これらの例で非常に難しいものは何もありません。 どちらの場合も最終的に完全な図形をもたらす描かれたカーブの連続を見ます。

二次ベジェ曲線

この例では、吹き出しをレンダリングするために複数の二次ベジェ曲線を使用しています。

function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    // 二次曲線の例
    ctx.beginPath();
    ctx.moveTo(75, 25);
    ctx.quadraticCurveTo(25, 25,  25, 62.5);
    ctx.quadraticCurveTo(25, 100, 50, 100);
    ctx.quadraticCurveTo(50, 120, 30, 125);
    ctx.quadraticCurveTo(60, 120, 65, 100);
    ctx.quadraticCurveTo(125, 100, 125, 62.5);
    ctx.quadraticCurveTo(125, 25, 75, 25);
    ctx.stroke();
  }
}
{{EmbedLiveSample("Quadratic_Bezier_curves", 160, 160, "https://mdn.mozillademos.org/files/243/Canvas_quadratic.png")}}

三次ベジェ曲線

この例では、三次ベジェ曲線を使ってハートを描画します。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){

    var ctx = canvas.getContext('2d');

    // Quadratric curves example
    ctx.beginPath();
    ctx.moveTo(75,40);
    ctx.bezierCurveTo(75,37,70,25,50,25);
    ctx.bezierCurveTo(20,25,20,62.5,20,62.5);
    ctx.bezierCurveTo(20,80,40,102,75,120);
    ctx.bezierCurveTo(110,102,130,80,130,62.5);
    ctx.bezierCurveTo(130,62.5,130,25,100,25);
    ctx.bezierCurveTo(85,25,75,37,75,40);
    ctx.fill();
  }
}
{{EmbedLiveSample("Cubic_Bezier_curves", 160, 160, "https://mdn.mozillademos.org/files/207/Canvas_bezier.png")}}

矩形

canvas に直接矩形を描く例 ({{anch("Drawing rectangles","矩形を描く")}}) で見た 3 つのメソッドのほかに、パスリストに矩形を追加する rect メソッドがあります。

rect(x, y, width, height)

このメソッドは 4 つの引数をとります。xy パラメタは新しい矩形パスの左上の角の座標を定義します。widthheight は矩形の幅と高さを定義します。

このメソッドが実行されると、パラメタに (0,0) を持った moveTo メソッドが自動的に呼ばれます。(すなわち、始点が標準の位置に置かれます。)

組み合わせ

このページの全ての例で私は図形につき一種類のパス関数のみを使ってきました。しかし、量や図形を作るのにパスの種類の制限は一切ありません。そこで、この最後の例で私は非常に有名なゲームのキャラクタを作るために全てのパス関数を組み合わせることに挑戦しました。

// 角丸の四角形を描画するためのユーティリティ関数
function roundedRect(ctx, x, y, width, height, radius) {
  ctx.beginPath();
  ctx.moveTo(x, y+radius);
  ctx.lineTo(x, y+height-radius);
  ctx.quadraticCurveTo(x, y+height, x+radius, y+height);
  ctx.lineTo(x+width-radius, y+height);
  ctx.quadraticCurveTo(x+width, y+height, x+width, y+height-radius);
  ctx.lineTo(x+width, y+radius);
  ctx.quadraticCurveTo(x+width, y, x+width-radius, y);
  ctx.lineTo(x+radius, y);
  ctx.quadraticCurveTo(x, y, x, y+radius);
  ctx.stroke();
}


// 描画関数。先に定義したユーティリティ関数を内部で使用している。
function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    roundedRect(ctx, 12, 12, 150, 150, 15);
    roundedRect(ctx, 19, 19, 150, 150, 9);
    roundedRect(ctx, 53, 53, 49, 33, 10);
    roundedRect(ctx, 53, 119, 49, 16, 6);
    roundedRect(ctx, 135, 53, 49, 33, 10);
    roundedRect(ctx, 135, 119, 25, 49, 10);

    ctx.beginPath();
    ctx.arc(37, 37, 13, Math.PI/7, -Math.PI/7, false);
    ctx.lineTo(31, 37);
    ctx.fill();

    for(var i = 0; i < 8; i++) {
      ctx.fillRect(51+i*16, 35, 4, 4);
    }

    for(i = 0; i < 6; i++) {
      ctx.fillRect(115, 51+i*16, 4, 4);
    }

    for(i = 0; i < 8; i++) {
      ctx.fillRect(51+i*16, 99, 4, 4);
    }

    ctx.beginPath();
    ctx.moveTo(83, 116);
    ctx.lineTo(83, 102);
    ctx.bezierCurveTo(83, 94, 89, 88, 97, 88);
    ctx.bezierCurveTo(105, 88, 111, 94, 111, 102);
    ctx.lineTo(111, 116);
    ctx.lineTo(106.333, 111.333);
    ctx.lineTo(101.666, 116);
    ctx.lineTo(97, 111.333);
    ctx.lineTo(92.333, 116);
    ctx.lineTo(87.666, 111.333);
    ctx.lineTo(83, 116);
    ctx.fill();

    ctx.fillStyle = "white";
    ctx.beginPath();
    ctx.moveTo(91, 96);
    ctx.bezierCurveTo(88, 96, 87, 99, 87, 101);
    ctx.bezierCurveTo(87, 103, 88, 106, 91, 106);
    ctx.bezierCurveTo(94, 106, 95, 103, 95, 101);
    ctx.bezierCurveTo(95, 99, 94, 96, 91, 96);
    ctx.moveTo(103, 96);
    ctx.bezierCurveTo(100, 96, 99, 99, 99, 101);
    ctx.bezierCurveTo(99, 103, 100, 106, 103, 106);
    ctx.bezierCurveTo(106, 106, 107, 103, 107, 101);
    ctx.bezierCurveTo(107, 99, 106, 96, 103, 96);
    ctx.fill();

    ctx.fillStyle = "black";
    ctx.beginPath();
    ctx.arc(101, 102, 2, 0, Math.PI*2, true);
    ctx.fill();

    ctx.beginPath();
    ctx.arc(89, 102, 2, 0, Math.PI*2, true);
    ctx.fill();
  }
}

以下の様な表示結果となります。

{{EmbedLiveSample("Making_combinations", 160, 160)}}

これらは非常に簡単な例ですので、詳細は割愛します。ポイントは fillStyle を使用している点と、独自関数 roundedRect() を定義している点です。この様に繰り返し利用する可能性のある処理を関数化しておくと、コード量を低減する事ができます。

fillStyle プロパティで、塗りの色を初期値の黒から白に、そしてもう一度黒に変更しています。このプロパティの詳細についてはこのチュートリアルの後半で説明します。

{{PreviousNext("Web/Guide/HTML/Canvas/Tutorial/Basic_usage", "Web/Guide/HTML/Canvas/Tutorial/Using_images")}}

このリビジョンのソースコード

<h2 id="The_grid" name="The_grid">グリッド</h2>


<p><img align="right" src="https://mdn.mozillademos.org/files/224/Canvas_default_grid.png" width="220" height="220"></p>


<p>描き始める前に、 canvas のグリッドもしくは <i>座標空間</i> について話す必要があります。前のページの HTML テンプレートは幅 150 ピクセル、高さ 150 ピクセルの canvas 要素を持っていました。私はこの画像をデフォルトのグリッドに上書きして描きました。普通 グリッド上の 1 単位は canvas 上の 1 ピクセルに相当します。このグリッドの原点は左上の角 ( 座標 (0,0) ) に位置します。全ての要素がこの原点から相対的に配置されます。よって青い正方形の左上の場所は左から x ピクセル、上から y ピクセル (座標 (x,y) ) に来ます。 このチュートリアルの後半で原点を他の位置へずらす方法、グリッドを回転したり、伸縮したりさえする方法を見ることになります。今はデフォルトで我慢しましょう。</p>





<h2 id="Drawing_rectangles" name="Drawing_rectangles">矩形を描く</h2>
<p><a href="/ja/docs/SVG">SVG</a> とは異なり、canvas は 1 つの原始図形「矩形」のみをサポートしています。 他の全ての図形は 1 つ以上のパスを組み合わせて作らなくてはなりません。幸いなことに、とても複雑な図形を作ることが可能なパスを描く関数のコレクションがあります。</p>


<p>最初に矩形を見ていきましょう。canvas に矩形を描く 3 つの関数があります:</p>


<pre class="syntaxbox">
<b>fillRect</b>(x,y,width,height)   // 塗られた矩形を描く
<b>strokeRect</b>(x,y,width,height) // 矩形の輪郭を描く
<b>clearRect</b>(x,y,width,height)  // 指定された領域を消去し、完全な透明にする
</pre>


<p>3 つの関数は同じパラメータをとります。<code>x</code> と <code>y</code> は 矩形の左上の角の canvas 上での位置 (原点から相対的) を指定します。 <code>width</code> と <code>height</code> は非常に明解です。 動作中のこれらの関数を見てみましょう。</p>

<p>下は、前のページの <code>draw()</code> 関数ですが、私は 3 つの関数を追加しました。</p>





<h3 id="Rectangular_shape_example" name="Rectangular_shape_example">矩形の例</h3>


<div class="hidden">
<pre class="brush: html" name="code">
&lt;html&gt;
&nbsp;&lt;body onload="draw();"&gt;
&nbsp;&nbsp; &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
&nbsp;&lt;/body&gt;
&lt;/html&gt;
</pre>
</div>



<pre class="brush: js">
function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    ctx.fillRect(25, 25, 100, 100);
    ctx.clearRect(45, 45, 60, 60);
    ctx.strokeRect(50, 50, 50, 50);
  }
}</pre>

<p>結果は以下のように見えるはずです。</p>

<div>{{EmbedLiveSample("Rectangular_shape_example", 160, 160, "https://mdn.mozillademos.org/files/245/Canvas_rect.png")}}</div>


<p><code>fillRect</code> 関数は 100x100 ピクセルの大きな黒色正方形を描きます。<code>clearRect</code> 関数は中心から 60x60 ピクセルの正方形を取り除き、最後に <code>strokeRect</code> が消去された正方形の中に 50x50 ピクセルの矩形の輪郭を描きます。 後のページで <code>clearRect</code> の代わりのメソッドを見て、描く図形の色と輪郭のスタイルを変更する方法を見ます。</p>


<p>次の節でみるパス関数とことなり、全ての 3 つの矩形関数は直ちに canvas に描きます。</p>





<h2 id="Drawing_paths" name="Drawing_paths">パスを描く</h2>
<p>パスを使って図形を描くには、 2 つの余分な作業が必要です。</p>

<pre class="syntaxbox">
<b>beginPath</b>()

<b>closePath</b>()

<b>stroke</b>()

<b>fill</b>()</pre>


<p>パスを作る最初の作業は <code>beginPath</code> メソッドを呼び出すことです。内部では、パスは図形を一緒に作るサブパス(線、円弧など)のリストとして保存されます。 このメソッドが呼び出される毎に、リストは再初期化され新しい図形を始めることができます。</p>

<p>2 番目の作業は描かれる実際のパスを定義するメソッドを呼び出すことです。それらを簡単にみていくことにしましょう</p>

<p>3 番目は任意の作業ですが、<code>closePath</code> メソッドを呼び出すことです。このメソッドは現在の点から始点に向けて直線を描くことで図形を閉じようとします。もし図形がすでに閉じられているかリストに点がひとつしかない場合はこの関数は何もしません。</p>

<p>最後の作業は <code>stroke</code> と/または <code>fill</code> メソッドを呼ぶことでしょう。これらのうちの一つを呼ぶことは実際に canvas に図形を描きます。 <code>stroke</code> は輪郭の描かれた図形を描き、一方で <code>fill</code> は単色の図形を描きます。</p>

<p><b>注意</b>: <code>fill</code> メソッドがと呼ばれるときはどんな開いている図形は自動的に閉じられ、 <code>closePath</code> メソッドを使う必要はありません。</p>




<h3 id="Drawing_a_triangle" name="Drawing_a_triangle">三角形の描画</h3>

<p>単純な図形(三角形)を描くコードはこのようになります。</p>

<div class="hidden">
<pre class="brush:html" name="code">
&lt;html&gt;
&nbsp;&lt;body onload="draw();"&gt;
&nbsp;&nbsp; &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
&nbsp;&lt;/body&gt;
&lt;/html&gt;
</pre>
</div>

<pre class="brush:js" name="code">
function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.moveTo(75,50);
    ctx.lineTo(100,75);
    ctx.lineTo(100,25);
    ctx.fill();
  }
}</pre>

<p>表示結果は以下の様になります。</p>
<div>{{EmbedLiveSample("Drawing_a_triangle", 160, 160)}}</div>





























<h3 id="Moving_the_pen" name="Moving_the_pen">ペンの移動</h3>

<p><code>moveTo</code> 関数自体は何も描画しませんが、上述のパスリストの一部です。あなたはこれを 1 枚の紙の上の 1 つの場所からペンか鉛筆を持ち上げてそれを次に置くと考えることができるでしょう。</p>

<pre class="syntaxbox">
  <code><b>moveTo</b>(x, y)</code>
</pre>

<p><code>moveTo</code> 関数は 2 つの引数 <code>x</code> と <code>y</code> をとります。それらは新しい始点の座標です。</p>

<p>canvas が初期化されるか <code>beginPath</code> メソッドが呼ばれると始点は座標 (0,0) に設定されます。ほとんどの場合 <code>moveTo</code> メソッドを始点を他の場所に置くために使います。<code>moveTo</code> メソッドを繋がっていないパスを描くために使うこともできます。右のスマイリーを見てください。私は <code>moveTo</code> メソッドを使った場所をマークしました(赤い線)</p>

<p>これをあなた自身で試すには、以下のコードを使うことができます。さきほど見た <code>draw</code> 関数に貼り付けるだけです。</p>

<div class="hidden">
<pre class="brush: html" name="code">
&lt;html&gt;
&nbsp;&lt;body onload="draw();"&gt;
&nbsp;&nbsp; &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
&nbsp;&lt;/body&gt;
&lt;/html&gt;
</pre>
</div>


<pre class="brush: js" name="code">
function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.arc(75, 75, 50, 0, Math.PI*2, true); // 外の円
    ctx.moveTo(110,75);
    ctx.arc(75,75,35,0,Math.PI,false);   // 口 (時計回り)
    ctx.moveTo(65,65);
    ctx.arc(60,65,5,0,Math.PI*2,true);  // 左目
    ctx.moveTo(95,65);
    ctx.arc(90,65,5,0,Math.PI*2,true);  // 右目
    ctx.stroke();
  }
}</pre>


<p>表示結果は以下の様になります。</p>
<div>{{EmbedLiveSample("Moving_the_pen", 160, 160, "https://mdn.mozillademos.org/files/252/Canvas_smiley.png")}}</div>


<p>繋がっている線を見るには <code>moveTo</code> メソッドを取り除いてください。<br />

<div class="note">
<b>注記</b>: <code>arc()</code> 関数とそのパラメータの解説は {{anch("Arcs","円弧")}} の章をご覧下さい。</p>
</div>

















<h3 id="Lines" name="Lines">線</h3>

<p>直線を描くには <code>lineTo</code> メソッドを使います。</p>

<pre class="syntaxbox">
<b>lineTo</b>(x, y)
</pre>

<p>このメソッドは 2 つの引数 <code>x</code> と <code>y</code> を取ります。それらは線の終点の座標です。始点は前回のパスに依存します。前回のパスの終点が始点になる、など。始点は <code>moveTo</code> メソッドを使って変更することもできます。</p>


<p>次の例では 2 つの三角形が描かれています。 1 つは塗られてもう 1 つは輪郭線が描かれています。</p>

<div class="hidden">
<pre class="brush: html" name="code">
&lt;html&gt;
 &lt;body onload="draw();"&gt;
   &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
 &lt;/body&gt;
&lt;/html&gt;
</pre>
</div>
<pre class="brush: js" name="code">
function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    // Filled triangle
    ctx.beginPath();
    ctx.moveTo(25,25);
    ctx.lineTo(105,25);
    ctx.lineTo(25,105);
    ctx.fill();

    // Stroked triangle
    ctx.beginPath();
    ctx.moveTo(125,125);
    ctx.lineTo(125,45);
    ctx.lineTo(45,125);
    ctx.closePath();
    ctx.stroke();
  }
}
</pre>


<p>最初に新しい図形のパスを始めるために <code>beginPath</code> メソッドが呼ばれています。次に 始点を任意の位置に移動するために <code>moveTo</code> メソッドが呼ばれています。三角形の 2 つの側面を作る 2 つの線が描かれています。</p>

<div>{{EmbedLiveSample("Lines", 160, 160, "https://mdn.mozillademos.org/files/238/Canvas_lineTo.png")}}</div>


<p>あなたは塗られた三角形と輪郭線の描かれたものとの違いに気がつくでしょう。上で述べたように、これはパスが塗られると図形は自動的に閉じられるからです。もしこれを輪郭の描かれた三角形に行うと 2 つの線しか描かれず、三角形は完成しません。</p>






<pre class="brush:js">// 塗られた三角形
ctx.beginPath();
ctx.moveTo(25,25);
ctx.lineTo(105,25);
ctx.lineTo(25,105);
ctx.fill();

// 輪郭の描かれた三角形
ctx.beginPath();
ctx.moveTo(125,125);
ctx.lineTo(125,45);
ctx.lineTo(45,125);
ctx.closePath();
ctx.stroke();</pre>










<h3 id="Arcs" name="Arcs">円弧</h3>
<p>円弧や円を描くために <code>arc</code> メソッドを使います。仕様書は <code>arcTo</code> メソッドも述べています。これは Safari はサポートしていますが、現在の Gecko ブラウザは実装していません。</p>

<pre class="syntaxbox">
<code>arc(x, y, radius, startAngle, endAngle, anticlockwise)</code>
</pre>


<p>このメソッドは 5 つのパラメタをとります。<code>x</code> と <code>y</code> は円の中心です。Radius は自明です。<code>startAngle</code> と <code>endAngle</code> パラメタは円弧の始まりと終点をラジアンで定義します。始まりと終わりの角度は x 軸から計算します。<code>anticlockwise</code> パラメタは <code>true</code> の時には円弧を反時計回りに、それ以外は時計回りの方向に描くブーリアン値です。</p>

<p><b>注意</b>: <code>arc</code> 関数の角度は度ではなく、ラジアンで計算されます。度からラジアンに変換するにはあなたは以下の JavaScript 式を使うことができます : <code>var radians = (Math.PI/180)*degrees</code>.</p>


<p>以下の例は上で見てきた例よりすこし複雑です。私は全て異なる角度と塗りを持った 12 の異なる円弧を描きます。もし私が上のスマイリーのようにこの例を書いたなら、非常に長い文のリストになったでしょう、第二に円弧を描くとき私は全ての出発点を知る必要があるでしょう。ここで使ったような 90、180、270 度の円弧にはこれは問題にならないでしょう、しかしより複雑なものにはこの方法は難しいすぎるでしょう。</p>

<p>2 つの <code>for</code> ループは円の行と列のループです。全ての円弧毎に私は <code>beginPath</code> を使って新しいパスを始めました。次に何が行われているか読みやすくするために全てのパラメタを変数として書きました。普通これは一文になったでしょう。 <code>x</code> と <code>y</code> 座標は充分明確です。 <code>radius</code> と <code>startAngle</code> は固定です。 <code>endAngle</code> は 180 度(最初の列)から始まって 90 度ずつ完全な円(最後の行)を作るように増加します。 <code>clockwise</code> パラメタの文は最初と 3 番目の列では時計回りの円弧として 2 番目と 4 番目の列では反時計回りの円弧という結果になります。最後に、<code>if</code> 文は上半分は輪郭を描画された円弧に下半分は塗られた円弧を作ります。</p>

<div class="hidden">
<pre class="brush: html" name="code">
&lt;html&gt;
  &lt;body onload="draw();"&gt;
    &lt;canvas id="canvas" width="150" height="200"&gt;&lt;/canvas&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
</div>


<pre class="brush: js" name="code">
function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    for(var i = 0; i &lt; 4; i++) {
      for(var j = 0; j &lt; 3; j++) {
        ctx.beginPath();
        var x              = 25 + j * 50;             // x 座標
        var y              = 25 + i * 50;             // y 座標
        var radius         = 20;                      // 円弧の半径
        var startAngle     = 0;                       // 円孤の始点
        var endAngle       = Math.PI + (Math.PI*j)/2; // 円孤の終点
        var anticlockwise  = i%2==0 ? false : true;   // 時計回りまたは半時計回り

        ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

        if (i&gt;1){
          ctx.fill();
        } else {
          ctx.stroke();
        }
      }
    }
  }
}</pre>

<div>{{EmbedLiveSample("Arcs", 160, 210, "https://mdn.mozillademos.org/files/204/Canvas_arc.png")}}</div>















<h3 id="Bezier_and_quadratic_curves" name="Bezier_and_quadratic_curves">ベジェと二次曲線</h3>

<p>パスの次の種類は<a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">ベジェ曲線</a>で入手可能です。三次および二次の種類で利用可能です。通常複雑な自然の図形を描くのに使われます。</p>


<pre class="syntaxbox">
<code><b>quadraticCurveTo</b>(cp1x, cp1y, x, y);

<b>bezierCurveTo</b>(cp1x, cp1y, cp2x, cp2y, x, y);</code>
</pre>


<p><img src="https://mdn.mozillademos.org/files/223/Canvas_curves.png" style="float:right" width="190" height="190" />これらの違いは右の画像を使うことで説明することができます。二次ベジェ曲線は始点と終点(青い点)を持ち、三次ベジェ曲線が 2 つの制御点を持つのに対して <i>制御点</i> (赤い点)を 1 つだけ持ちます。</p>

<p>それらのメソッドの両方の <code>x</code> と <code>y</code> パラメータは終点の座標です。<code>cp1x</code> と <code>cp1y</code> は最初の制御点、 <code>cp2x</code> と <code>cp2y</code> は 2 番目の制御点の座標です。</p>

<p>Adobe Illustrator のようなベクタードローイングソフトとは違い、何をやっているのかの直接の視覚的フィードバックが得られないので、二次および三次ベジェ曲線を使うことはとても挑戦的です。このことは複雑な図形を描くことをとても難しくします。以下の例で、いくつかの単純な有機的な図形を描きます、しかしもしあなたに時間と特に忍耐があればはるかに複雑な図形を作ることができます。</p>

<p>これらの例で非常に難しいものは何もありません。 どちらの場合も最終的に完全な図形をもたらす描かれたカーブの連続を見ます。</p>







<h4 id="Quadratic_Bezier_curves" name="Quadratic_Bezier_curves">二次ベジェ曲線</h4>
<p>この例では、吹き出しをレンダリングするために複数の二次ベジェ曲線を使用しています。</p>

<div class="hidden">
<pre class="brush: html" name="code">
&lt;html&gt;
&nbsp;&lt;body onload="draw();"&gt;
&nbsp;&nbsp; &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
&nbsp;&lt;/body&gt;
&lt;/html&gt;
</pre>
</div>

<pre class="brush: js" name="code">
function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    // 二次曲線の例
    ctx.beginPath();
    ctx.moveTo(75, 25);
    ctx.quadraticCurveTo(25, 25,  25, 62.5);
    ctx.quadraticCurveTo(25, 100, 50, 100);
    ctx.quadraticCurveTo(50, 120, 30, 125);
    ctx.quadraticCurveTo(60, 120, 65, 100);
    ctx.quadraticCurveTo(125, 100, 125, 62.5);
    ctx.quadraticCurveTo(125, 25, 75, 25);
    ctx.stroke();
  }
}
</pre>

<div>{{EmbedLiveSample("Quadratic_Bezier_curves", 160, 160, "https://mdn.mozillademos.org/files/243/Canvas_quadratic.png")}}</div>










<h4 id="Cubic_Bezier_curves" name="Cubic_Bezier_curves">三次ベジェ曲線</h4>

<p>この例では、三次ベジェ曲線を使ってハートを描画します。</p>

<div class="hidden">
<pre class="brush: html" name="code">
&lt;html&gt;
 &lt;body onload="draw();"&gt;
   &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
 &lt;/body&gt;
&lt;/html&gt;
</pre>
</div>

<pre class="brush: js" name="code">
function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){

    var ctx = canvas.getContext('2d');

    // Quadratric curves example
    ctx.beginPath();
    ctx.moveTo(75,40);
    ctx.bezierCurveTo(75,37,70,25,50,25);
    ctx.bezierCurveTo(20,25,20,62.5,20,62.5);
    ctx.bezierCurveTo(20,80,40,102,75,120);
    ctx.bezierCurveTo(110,102,130,80,130,62.5);
    ctx.bezierCurveTo(130,62.5,130,25,100,25);
    ctx.bezierCurveTo(85,25,75,37,75,40);
    ctx.fill();
  }
}
</pre>

<div>{{EmbedLiveSample("Cubic_Bezier_curves", 160, 160, "https://mdn.mozillademos.org/files/207/Canvas_bezier.png")}}</div>














<h3 id="Rectangles" name="Rectangles">矩形</h3>

<p>canvas に直接矩形を描く例 ({{anch("Drawing rectangles","矩形を描く")}}) で見た 3 つのメソッドのほかに、パスリストに矩形を追加する <code>rect</code> メソッドがあります。</p>

<pre class="syntaxbox">
<code><b>rect</b>(x, y, width, height)</code>
</pre>

<p>このメソッドは 4 つの引数をとります。<code>x</code> と <code>y</code> パラメタは新しい矩形パスの左上の角の座標を定義します。<code>width</code> と <code>height</code> は矩形の幅と高さを定義します。</p>

<p>このメソッドが実行されると、パラメタに (0,0) を持った <code>moveTo</code> メソッドが自動的に呼ばれます。(すなわち、始点が標準の位置に置かれます。)</p>









<h3 id="Making_combinations" name="Making_combinations">組み合わせ</h3>

<p>このページの全ての例で私は図形につき一種類のパス関数のみを使ってきました。しかし、量や図形を作るのにパスの種類の制限は一切ありません。そこで、この最後の例で私は非常に有名なゲームのキャラクタを作るために全てのパス関数を組み合わせることに挑戦しました。</p>

<div class="hidden">
<pre class="brush: html" name="code">
&lt;html&gt;
 &lt;body onload="draw();"&gt;
   &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
 &lt;/body&gt;
&lt;/html&gt;
</pre>
</div>


<pre class="brush:js" name="code">
// 角丸の四角形を描画するためのユーティリティ関数
function roundedRect(ctx, x, y, width, height, radius) {
  ctx.beginPath();
  ctx.moveTo(x, y+radius);
  ctx.lineTo(x, y+height-radius);
  ctx.quadraticCurveTo(x, y+height, x+radius, y+height);
  ctx.lineTo(x+width-radius, y+height);
  ctx.quadraticCurveTo(x+width, y+height, x+width, y+height-radius);
  ctx.lineTo(x+width, y+radius);
  ctx.quadraticCurveTo(x+width, y, x+width-radius, y);
  ctx.lineTo(x+radius, y);
  ctx.quadraticCurveTo(x, y, x, y+radius);
  ctx.stroke();
}


// 描画関数。先に定義したユーティリティ関数を内部で使用している。
function draw() {
  var canvas = document.getElementById('canvas');

  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    roundedRect(ctx, 12, 12, 150, 150, 15);
    roundedRect(ctx, 19, 19, 150, 150, 9);
    roundedRect(ctx, 53, 53, 49, 33, 10);
    roundedRect(ctx, 53, 119, 49, 16, 6);
    roundedRect(ctx, 135, 53, 49, 33, 10);
    roundedRect(ctx, 135, 119, 25, 49, 10);

    ctx.beginPath();
    ctx.arc(37, 37, 13, Math.PI/7, -Math.PI/7, false);
    ctx.lineTo(31, 37);
    ctx.fill();

    for(var i = 0; i &lt; 8; i++) {
      ctx.fillRect(51+i*16, 35, 4, 4);
    }

    for(i = 0; i &lt; 6; i++) {
      ctx.fillRect(115, 51+i*16, 4, 4);
    }

    for(i = 0; i &lt; 8; i++) {
      ctx.fillRect(51+i*16, 99, 4, 4);
    }

    ctx.beginPath();
    ctx.moveTo(83, 116);
    ctx.lineTo(83, 102);
    ctx.bezierCurveTo(83, 94, 89, 88, 97, 88);
    ctx.bezierCurveTo(105, 88, 111, 94, 111, 102);
    ctx.lineTo(111, 116);
    ctx.lineTo(106.333, 111.333);
    ctx.lineTo(101.666, 116);
    ctx.lineTo(97, 111.333);
    ctx.lineTo(92.333, 116);
    ctx.lineTo(87.666, 111.333);
    ctx.lineTo(83, 116);
    ctx.fill();

    ctx.fillStyle = "white";
    ctx.beginPath();
    ctx.moveTo(91, 96);
    ctx.bezierCurveTo(88, 96, 87, 99, 87, 101);
    ctx.bezierCurveTo(87, 103, 88, 106, 91, 106);
    ctx.bezierCurveTo(94, 106, 95, 103, 95, 101);
    ctx.bezierCurveTo(95, 99, 94, 96, 91, 96);
    ctx.moveTo(103, 96);
    ctx.bezierCurveTo(100, 96, 99, 99, 99, 101);
    ctx.bezierCurveTo(99, 103, 100, 106, 103, 106);
    ctx.bezierCurveTo(106, 106, 107, 103, 107, 101);
    ctx.bezierCurveTo(107, 99, 106, 96, 103, 96);
    ctx.fill();

    ctx.fillStyle = "black";
    ctx.beginPath();
    ctx.arc(101, 102, 2, 0, Math.PI*2, true);
    ctx.fill();

    ctx.beginPath();
    ctx.arc(89, 102, 2, 0, Math.PI*2, true);
    ctx.fill();
  }
}</pre>

<p>以下の様な表示結果となります。</p>
<div>{{EmbedLiveSample("Making_combinations", 160, 160)}}</div>


<p>これらは非常に簡単な例ですので、詳細は割愛します。ポイントは <code>fillStyle</code> を使用している点と、独自関数 <code>roundedRect()</code> を定義している点です。この様に繰り返し利用する可能性のある処理を関数化しておくと、コード量を低減する事ができます。</p>


<p><code>fillStyle</code> プロパティで、塗りの色を初期値の黒から白に、そしてもう一度黒に変更しています。このプロパティの詳細についてはこのチュートリアルの後半で説明します。</p>






<div>{{PreviousNext("Web/Guide/HTML/Canvas/Tutorial/Basic_usage", "Web/Guide/HTML/Canvas/Tutorial/Using_images")}}</div>
このリビジョンへ戻す