HTML5のcanvasに直線や曲線でパスを描画する

HTML5のcanvas APIには、直線や曲線、円弧を描画するためのメソッドが予め用意されています。これらのメソッドを利用することで、これまではプラグインなしでは実現が難しかった自由な形状のパスをHTMLだけで描画することができます。

直線の描画と線端の形状指定

まず、簡単な直線から描いてみます。下記の例では、beginPath()をコールした後、moveTo()で開始点を右上にして、lineTo()で左下へパスを描いています。パスを閉じない場合は、lineCapで線端の形状を指定することができます。lineCapで指定できる値は、"butt", "round", "square"となります。

JavaScript

window.onload = function() {
  var canvas = document.getElementById('my-canvas');
  var context = canvas.getContext('2d');
  context.save();
  context.translate(canvas.width * 0.5, canvas.height * 0.5);
  context.beginPath();
  context.moveTo(100, -100);
  context.lineTo(-100, 100);
  // 線の色
  context.strokeStyle = 'rgba(255, 0, 0, 0.5)';
  // 線の幅
  context.lineWidth = 10;
  // 線端の形状
  context.lineCap = 'round';
  context.stroke();
  context.restore();
};

二次ベジェ曲線を描画する quadraticCurveTo()

quadraticCurveTo()は、第1, 2引数を(x, y)の制御点として、第3, 4引数の(x, y)座標に対して二次ベジェ曲線を描画します。quadraticCurveTo()における制御点は、始点と終点を結ぶ線に対する引力と考えるとわかりやすいでしょう。

下記の例では、quadraticCurveTo()で角丸矩形を描画するdrawRoundRect関数を定義しています。drawRoundRect関数は、第1引数でcanvasのコンテキスト、第2引数で角丸矩形の幅、第3引数で角丸矩形の高さ、第4引数で角丸の大きさを指定するようにしています。

JavaScript

function drawRoundRect(context, width, height, roundSize) {
  var halfW = width * 0.5;
  var straightW = halfW - roundSize;
  var halfH = height * 0.5;
  var straightH = halfH - roundSize;
  context.beginPath();
  context.moveTo(-straightW, -halfH);
  context.lineTo(straightW, -halfH);
  context.quadraticCurveTo(halfW, -halfH, halfW, -straightH);
  context.lineTo(halfW, straightH);
  context.quadraticCurveTo(halfW, halfH, straightW, halfH);
  context.lineTo(-straightW, halfH);
  context.quadraticCurveTo(-halfW, halfH, -halfW, straightH);
  context.lineTo(-halfW, -straightH);
  context.quadraticCurveTo(-halfW, -halfH, -straightW, -halfH);  
}

window.onload = function() {
  var canvas = document.getElementById('my-canvas');
  var context = canvas.getContext('2d');
  context.save();
  context.translate(canvas.width * 0.5, canvas.height * 0.5);
  drawRoundRect(context, 360, 270, 20);
  context.fillStyle = 'rgba(255, 0, 0, 0.5)';
  context.fill();
  context.restore();
};

三次ベジェ曲線を描画する bezierCurveTo()

bezierCurveTo()は、第1, 2引数の(x, y)を始点からの制御点、第3, 4引数の(x, y)を終点への制御点、第5, 6引数の(x, y)を終点として三次ベジェ曲線を描画します。bezierCurveTo()における制御点は、Illustratorでベジェ曲線を描くときのアンカーポイントのハンドルのようなものと考えるとわかりやすいでしょう。

下記の例では、bezierCurveTo()を使ってサイン波のような波線を描画しています。

JavaScript

window.onload = function() {
  var canvas = document.getElementById('my-canvas');
  var context = canvas.getContext('2d');
  context.save();
  context.translate(canvas.width * 0.5, canvas.height * 0.5);
  context.beginPath();
  context.moveTo(-200, 0);
  context.bezierCurveTo(0, -400, 0, 400, 200, 0);
  context.lineWidth = 2;
  context.strokeStyle = 'rgba(255, 0, 0, 0.5)';
  context.stroke();
  context.restore();
};

円弧を描画する arc()

arc()は、第1, 2引数の(x, y)を中心座標として、第3引数を半径とした円弧を描きます。第4引数は開始角度、第5引数は終了角度となり、角度はx軸から見て時計回りの角度をラジアン値で指定します。第6引数は描画する円弧の向きをBool値で指定します。trueを指定すると反時計回りに、falseを指定すると時計回りに円弧が描かれます。

下記の例では、半径100の円弧を0度から270度まで時計回りに描画しています。

JavaScript

window.onload = function() {
  var canvas = document.getElementById('my-canvas');
  var context = canvas.getContext('2d');
  context.save();
  context.translate(canvas.width * 0.5, canvas.height * 0.5);
  context.beginPath();
  var x = 0;
  var y = 0;
  var radius = 100;
  var startAngle = 0;
  var endAngle = 270 * Math.PI / 180;
  var anticlockwise = false;
  context.arc(x, y, radius, startAngle, endAngle, anticlockwise);
  context.lineWidth = 2;
  context.strokeStyle = 'rgba(255, 0, 0, 0.5)';
  context.stroke();
  context.restore();
};

角を円弧で接続する arcTo()

arcTo()は、描画の開始座標から第1, 2引数で指定した座標(x, y)、第3, 4引数で指定した終了座標(x, y)と直線で結びつつ、3つの座標が成す角を第5引数を半径とする円の最も短い円弧で接続します。直線と円弧が接点でつながると考えるとわかりやすいでしょう。

下記の例は、角丸矩形を描画するdrawRoundRect関数をarcTo()を使って書き直したものです。なお、私が確認した限り、arcTo()はIE9とOpera11.61(Windows, Mac)では対応していません。

JavaScript

function drawRoundRect(context, width, height, radius) {
  var halfW = width * 0.5;
  var straightW = halfW - radius;
  var halfH = height * 0.5;
  var straightH = halfH - radius;
  context.beginPath();
  context.moveTo(-straightW, -halfH);
  context.arcTo(halfW, -halfH, halfW, -straightH, radius);
  context.arcTo(halfW, halfH, straightW, halfH, radius);
  context.arcTo(-halfW, halfH, -halfW, straightH, radius);  
  context.arcTo(-halfW, -halfH, -straightW, -halfH, radius);
}

window.onload = function() {
  var canvas = document.getElementById('my-canvas');
  var context = canvas.getContext('2d');
  context.save();
  context.translate(canvas.width * 0.5, canvas.height * 0.5);
  drawRoundRect(context, 360, 270, 20);
  context.fillStyle = 'rgba(255, 0, 0, 0.5)';
  context.fill();
  context.restore();
};