Canvasで図形を描く

もくじ > Web開発ノート > リッチサイト+JavaScript

売り上げ変動や、何かの目的達成をするための経緯などが確認できるサイトでは、円グラフ折れ線グラフのようなものを活用すると効果的です。会員制のサイトなどで自分自身の何かの成績をグラフで把握しておきたい事もよくあります。

プロモーションサイト等で、派手派手しく画像が動くような演出を作る時は、大抵、あらかじめ用意しておいた静止画像を使ったり、思い切って編集された動画ファイルを使えば良いので、意外と数学な頭を使うものではなく、プログラム的にはそれほど大変なものではないです。

しかし、HTML5がまだ標準と言われるほど普及していない時代は、軽く「データベースと連携したグラフとかを表示したい」とか言われると、少し頭を悩ませていました。

グラフ描画が大変でした

グラフを描画する時は、線を繋いだり、点を打ったり、円や四角などの図形を描くわけですが、テキストや画像を並べる事しかできないようなHTMLでそれを表現するのは至難の業で、画像ファイルを使って、線や図形っぽく見えるように工夫する必要がありました。

Flash全盛期の時代にも、実は見えない部分に苦労がありました。

Flashは、そもそも線や点や図形の描画を簡単にできるような機能を持っておらず、基本的にはシェイプや画像を配置して使います。なので、線や図形のシェイプを用意して、それを三角関数やら小難しい方程式やらを長く書いて、なんとかそれっぽく見せていただけだったりしました。

HTML5では、Canvasという技術が標準で使えるようになり、やっととても簡単に図形を描く事ができるようになりました。

ここでは、具体的にどの程度の手順で図形を描く事ができるのかを、目安程度にまとめます。実際にスクリプトを書く場合は、参考リンク先などをご覧ください。

HTML5Canvas具体例

基本的な書き方

まず、HTMLで以下のようなタグを用意します。

<canvas id="sample"></canvas>

canvasタグには特定のidを決めておいてください。
ここではidをsampleとします。

次にJavaScriptで以下のように記述します。

var canvas = document.getElementById('sample');
var context = canvas.getContext('2d');

id=sampleのcanvasを呼び出して、それをcontextという変数(以降、コンテキストと呼びます)に割り当てています。

この2行を実行した後は、ここで割り当てたコンテキストに対して描画処理を書いていきます。

context.fillStyle = '#ff0000';
context.fillRect(10, 20, 150, 100);

例えば、こう書くと、赤色で指定して、左上からX座標10、Y座標20の位置に、横幅150、縦幅100の塗りつぶした四角を描画します。

描画エリアのサイズ

canvasの初期サイズは幅300、高さ150です。

以下のようにCSSでwidthとheightを指定してしまうと、2倍の大きさに拡大されたように表示され、期待したような大きさにできません。

canvas {
 width:600px;
 height:300px;
 position:absolute;
 left:0px;
 top:0px;
}

描画エリアを変更したい時は、

<canvas id="sample" width="600" height="300"></canvas>

このようにタグに直接指定するか、
もしくは、

$('canvas').attr('width', 600);
$('canvas').attr('height', 300);

このようにして、JavaScriptから指定します。

描画タイミングについて

実際にグラフを描く時は、四角や線などを沢山並べたり組み合わせる事になります。1本描いては描画、1本描いては描画では、完成までとてつもなく時間がかかってしまいます。

Canvasは、context.beginPath();と書いた後に、複雑な図形の描画処理をまとめて書き、最後にcontext.closePath();と書いて締めて、context.stroke();の1行で実際の描画処理を実行します。

//横w、縦hの幅の範囲を消して白紙にします。
//こうして消さないと上書きされていきます。
context.clearRect(0, 0, w, h);

//描画開始
context.beginPath();

//透明度を50%にする
context.globalAlpha = 0.5;
//線の太さを1にする
context.lineWidth = 1;
//色を緑にする
context.strokeStyle = '#00ff00';
//四角で塗りつぶす
context.fillRect(10, 20, 150, 100);

//三角形を描く
context.moveTo(100,50);
context.lineTo(150,130);
context.lineTo(50,130);

//円を描く
context.arc(100,100,50, 0, Math.PI * 2, false);

//描画完了
context.closePath();
//描いたものを表示する
context.stroke();

数百個の図形を描いたとしても、実際に描画を行うのは最後に実行するcontext.stroke();の瞬間だけですので、描画は一瞬で完了します。少しずつ変化をつけて連続再生すればパーティクル効果のような演出や、動く図形や手描き風アニメーションなどが作れます。

図形描画の種類

描画できる図形をいくつか紹介します。

直線を描く

context.moveTo(100,50);
context.lineTo(150,130);
context.lineTo(50,130);

最初にmoveToで描きはじめを指定し、そこからlineToで指定した座標まで直線を描きます。

円や円弧を描く

cx = 200;
cy = 150;
ra = 100;
stAngle = 0;
edAngle = Math.PI * 2;
lineWay = false;
context.arc(cx,cy,ra, stAngle, edAngle, lineWay);

cxとcyで指定した座標を中心に、半径raで、stAngleからedAngleまでの角度分の弧を描きます。
lineWayは反時計回りでtrue、時計回りでfalseを指定します。

四角形を描く

//枠のみ
context.rect(20,20,50,50);
//塗りつぶし
context.fillRect(20,20,50,50);

この手の図形描画の特徴として、「線の描画」と「塗りつぶし」は別の命令文が用意されています。

ベジェ曲線を描く

context.beginPath();

//描きはじめの地点をセット
context.moveTo(50,100);
//2次ベジェ曲線を引く
context.quadraticCurveTo(150,20,250,100);
//3次ベジェ曲線を引く
context.bezierCurveTo(100,40,200,40,250,120);

context.closePath();
context.stroke();

ベジェ曲線を使って複雑な図形を描画する事もできます。
パラメーターを変化させれば、ウニョニョと自由に変形する物体を描く事もできます。

ただ、それはとても難しいので、adobe Animateなどで作ったものをgifアニメなどにしたほうが簡単かもしれません。

イメージを描画する

var img = new Image();
img.src = "images/ichigo.png";
context.drawImage(img, 0, 0, 400, 400, 100, 150, 400, 400);

指定した位置に画像を配置する事もできます。

テキスト描画

//テキスト塗りつぶし
context.fillText('こんにちは', 100, 150 ,200);
//テキストの輪郭線
context.strokeText('こんにちは', 100, 150 ,200);

指定したスタイルでテキストを描画する事もできます。

イベントを取得する

マウス操作や、スマートフォンでのタップ操作などを取得する事ができます。
以下の例ではcanvasエリア内のクリックされた座標を取得しています。

var canvas = document.getElementById('sample');
canvas.addEventListener('click', onClick, false);
function onClick(event) {
  var x = event.clientX - canvas.offsetLeft;
  var y = event.clientY - canvas.offsetTop;
}

イベントの種類は

click・・クリックした
mouseover・・マウスカーソルが上に乗った
mousemove・・マウスカーソルが動いた
mouseout・・マウスカーソルが外に出た
mouseup・・マウスを離した
mousedown・・マウスを押した
mousewheel・・マウスホイールを回した
keydown・・キーを押した
keyup・・キーを離した

などが指定できます。

ここまで、基本的な事だけを紹介しましたが、これだけでも円グラフや棒グラフ、折れ線グラフや、株価表示くらいなら簡単に作る事ができそうです。

更に応用して工夫すれば、ブラウザ上で、激しく動く幾何学演算的な映像や、なんらかの計算で動く学術的なシミュレーション、複雑なアクションゲーム等を作る事もできます。

参考リンク

Canvasリファレンス(HTMLクイックリファレンス)
Canvas API(MDN web docs)