サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

<canvas>要素で定めた領域に図形を描く

ID: FN1202002 Technique: HTML5 and JavaScript

HTML5の<canvas>要素は、描画できる透明な領域を定めます。本稿では、JavaScriptにより簡単な図形を描いてみます。


01 <canvas>要素を定める
<canvas>要素を<body>要素の中に書くと、透明な領域が定められ、JavaScriptで図形を描くことができます。widthとheight属性で幅と高さが決まります。また、id属性を加えると、JavaScriptで<canvas>要素が取出せます。

<canvas id=canvas要素名 width=幅 height=高さ>

新たなHTMLドキュメントの<body>要素の中に、<canvas>要素を書き加えます(図001)。幅と高さをそれぞれwidthとheight属性で決め、id属性も定めます(コード001)。

図001■新たなHTMLドキュメントに<canvas>要素を記述する
図001

コード001■<canvas>要素を定める
  1. <canvas id="myCanvas" width="240" height="180"></canvas>

<canvas>要素は透明な領域ですので、このままブラウザで見ても空白のページになります。


02 <canvas>の領域にJavaScriptで矩形を描く
<canvas>要素で定めた領域に、JavaScriptで矩形を描いてみましょう。描画は<canvas>要素から得られるコンテクストというオブジェクトに対して行います。まず、<canvas>要素をdocument.getElementById()メソッドで取得します。

element = document.getElementById(エレメントID)

つぎに、コンテクストの参照を得るにはgetContext()メソッドを呼出します。このとき、2次元の描画をする2Dコンテクストが必要なので、メソッドの引数には"2d"を渡します。

context2D = canvasElement.getContext("2d")

この2Dコンテクストに対して描画のためのメソッドを呼出します。塗りの矩形を描くのが、fillRect()メソッドです。xy座標、および幅と高さの4つの引数を渡します。

2Dコンテクスト.fillRect(x座標, y座標, 幅, 高さ)

塗りの矩形を描く関数(xDraw())は、つぎのコード002のように定められます。xy座標は(10, 10)、幅100×高さ100ピクセルの正方形を描きます。なお、塗り色のデフォルトは黒です。

コード002■塗りの矩形を描く関数
  1. function xDraw() {
  2.   var canvasElement = document.getElementById("myCanvas");
  3.   var context2D = canvasElement.getContext("2d");
  4.   context2D.fillRect(10, 10, 100, 100);
  5. }

この関数をページが読込み終わったときに呼出すには、<body>要素のイベント属性(イベントハンドラ)onLoadに設定します(コード003)。これで、<canvas>要素で定めた領域に矩形を描くコードができ上がりました(図002)。

コード003■関数をonLoadイベント属性に定める
  1. <body onload="xDraw()">

図002■<canvas>要素で定めた領域に矩形を描く
図002

ブラウザで確かめると、左上角座標(10, 10)の位置に幅100×高さ100ピクセルの黒い正方形が描かれます(図003)。

図003■左上角座標(10, 10)に100ピクセル四方の黒い正方形が描かれた
図003


03 塗り色を定める
前掲コード002で描いた矩形に、塗り色を定めましょう。fillStyleプロパティに、HTMLと同じく#記号で始まる6桁のカラー値を文字列で指定します(CSSの色指定もできます)。

2Dコンテクスト.fillStyle = カラー値

この後もう少し込入ったかたちも書きますので、この機会に関数も整理します。2Dコンテクストを得る関数(xGetContext())と描画の関数(xDraw())は分け、これらを呼出すための最初の関数(xInitialize())を定めました(コード004)。

コード004■描画のための関数を整理
  1. function xInitialize() {
  2.   var context2D = xGetContext();
  3.   xDraw(context2D);
  4. }
  5. function xGetContext() {
  6.   var canvasObject = document.getElementById('myCanvas');
  7.   var context2D = canvasObject.getContext('2d');
  8.   return context2D;
  9. }
  10. function xDraw(context2D) {
  11.   context2D.fillStyle = "#0000FF";
  12.   context2D.fillRect(10, 10, 100, 100);
  13. }

描画のための関数(xDraw())は、引数に2Dコンテクストを受取りますので、そのオブジェクトにfillStyleプロパティで塗り色を定め、矩形を描いています(コード004第10〜13行目)。

初めに呼出す関数が変わりましたので、忘れずにonLoadイベント属性の設定を書替えます(コード005)。これで、描かれる正方形の塗り色が青(#0000FF)に変わります(図004)。

コード005■onLoadイベント属性に定める関数を変更する
  1. <body onload="xInitialize()">

図004■正方形の塗り色が青に変わる
図004


04 直線でかたちを描く
2Dコンテクストにパスでかたちを描くこともできます。パスはbeginPath()メソッドで始め、closePath()メソッドを使って閉じます。パスをつくっただけでは、2Dコンテクストに何も描かれません。パスを塗るにはfill()メソッド、線として描くならstroke()メソッドを呼出します。パスをつくるための各座標は、直線または曲線で結ばれます。

塗りと線のあるパスを描くには、これらのメソッドはつぎのように用いられます。なお、線の塗りはstrokeStyle、太さはlineWidthプロパティで定めます。

2Dコンテクスト.beginPath();
// 塗りと線の設定
// パスを描く
2Dコンテクスト.closePath();
2Dコンテクスト.fill();
2Dコンテクスト.stroke();

パスを直線で描くには、moveTo()lineTo()メソッドを使います。moveTo()メソッドで書き始めの座標を決め、lineTo()メソッドによりふたつの座標の間を直線で結びます。

これらのメソッドを使って前掲コード004と同じ正方形を描き、違う塗り色と線をつけましょう(図005)。つぎのコード006は、前掲コード004の描画の関数(xDraw())を書替え、パスを描く関数(xDrawRect)は別に定めました。

コード006■直線の描画メソッドで矩形を描く
  1. function xDraw(context2D) {
  2.   context2D.beginPath();
  3.   context2D.strokeStyle = "#0000FF";
  4.   context2D.fillStyle = "#00FFFF";
  5.   xDrawRect(10, 10, 100, 100, context2D);
  6.   context2D.closePath();
  7.   context2D.fill();
  8.   context2D.stroke();
  9. }
  10. function xDrawRect(nX, nY, nWidth, nHeight, context2D) {
  11.   context2D.moveTo(nX, nY);
  12.   context2D.lineTo(nX + nWidth, nY);
  13.   context2D.lineTo(nX + nWidth, nY + nHeight);
  14.   context2D.lineTo(nX, nY + nHeight);
  15.   context2D.lineTo(nX, nY);
  16. }

図005■シアンの塗りと青い線で正方形を描く
図005

なお、新たに加えたパスを描く関数(xDrawRect())は、引数にfillRect()メソッドと同じxy座標および幅と高さに加えて、2Dコンテクストを受取ります(コード006第10行目)。こうすると、この関数は任意の2Dコンテクストに矩形のパスが加えられることになります。


05 星形を描く
直線でパスを描く応用例として、星形をつくりましょう。星形は関数(xDrawStar())に定めて描くことにします。かたちを変えられるように、引数には中心のxy座標と頂点数(山の数)および山と谷の半径を数値で渡し(図006)、描画する2Dコンテクストも加えます。

xDrawStar(中心のx座標, 中心のy座標, 頂点数, 山の半径, 谷の半径, 2Dコンテクスト)

図006■頂点数および山と谷の半径で描く星形を定める
図006

星の描き方は、つぎのような流れです。頂点数は山の数としましたので、まず谷も含めて「頂点数×2」で360度(2πラジアン)を等分します。その角度を順に回しながら、山と谷の座標を交互にとって直線で1周結べばよいのです。moveTo()メソッドで書き初めの位置を定め、あとはlineTo()メソッドで各点を直線で結びます。そのように定めた関数(xDrawStar())が、つぎのコード007です。

コード007■直線のパスで星形を描く
  1. function xDrawStar(nX, nY, numVertex, longRadius, shortRadius, context2D) {
  2.   var nStart = Math.PI;
  3.   var nTheta = nStart / numVertex;
  4.   var nRadians = 0;
  5.   numVertex *= 2;
  6.   nStart /= 2;
  7.   context2D.moveTo(nX, -longRadius + nY);
  8.   for (var i = 1; i < numVertex; i++) {
  9.     nRadians = i * nTheta - nStart;
  10.     context2D.lineTo(shortRadius * Math.cos(nRadians) + nX, shortRadius * Math.sin(nRadians) + nY);
  11.     nRadians = (++i) * nTheta - nStart;
  12.     context2D.lineTo(longRadius * Math.cos(nRadians) + nX, longRadius * Math.sin(nRadians) + nY);
  13.   }
  14. }

コード007は、前述のとおり、関数(xDrawStar())に渡された頂点数(numVertex)を谷も含めて2倍にしています(第5行目)。その頂点数で1周2πラジアン(360度)を割れば、頂点間の角度(nTheta)が導けます。ただ、実際には半周のπラジアンを分子にしたので、2倍にする前の頂点数が分母になっています(第3行目)。

もうひとつ気をつけるのは、星形の描き始めを時計の12時の向き、つまり-π/2ラジアン(-90度)にしたことです(コード007第7行目)。角度0は時計の3時になりますので、頂点の角度から2/πラジアンを引かなければなりません。その値を予め変数(nStart)に納めています(第2および第6行目)。

書き初めを山にしましたので(コード007第7行目)、繰返し処理のforループ内では谷と山を順に直線で結びます(第8〜13行目)[*1]。頂点ごとの角度を求めるとき、π/2を引いていることも確かめておきましょう(第9および第11行目)。

なお、原点(0, 0)からの距離(半径)をr、正のx軸となす角度をθとするとき、そのxy座標は(r cosθ, r sinθ)になります。中心を原点から座標(x0, y0)に(平行)移動すると、xy座標はつぎの式で表されます。

x = r cosθ + x0
y = r sinθ + y0

前掲コード007の山と谷の座標は、この式にもとづいて計算しています(第10および第12行目)。

あとは前掲コード006の描画の関数(xDraw())から呼出すのを、コード007に定めた関数(xDrawStar())に書替えればよいでしょう(コード008)。さらに、lineWidthプロパティで線の太さも変えました(第4行目)。

コード008■星形のパスを描く関数の呼出しに書替え
  1. function xDraw(context2D) {
  2.   context2D.beginPath();
  3.   context2D.strokeStyle = "#0000FF";
  4.   context2D.lineWidth = 5;
  5.   context2D.fillStyle = "#00FFFF";
  6.   xDrawStar(100, 100, 5, 90, 40, context2D);
  7.   context2D.closePath();
  8.   context2D.fill();
  9.   context2D.stroke();
  10. }

これで、シアンの塗りと青い線で5頂点の星形が描かれます(図007)。コード007で定めた関数(xDrawStar())の引数値を変えれば、いろいろなかたちの星形が描けます。

図007■シアンの塗りと青い線で5頂点の星形が描かれる
図007

<canvas>要素の2Dコンテクストに用いることのできる描画のメソッドは、本稿でご紹介したほかにもあります。詳しくは、MOZILLA DEVELOPER NETWORK「図形を描く」を読まれるとよいでしょう。

[*1] for文による繰返し処理については、AjaxTower「for文」が参考になるでしょう。


作成者: 野中文雄
作成日: 2012年2月13日


Copyright © 2001-2012 Fumio Nonaka.  All rights reserved.