HTML5 canvasの変換マトリックスによるオブジェクトの変形

HTML5 canvas APIには、変換マトリックスを操作するメソッドが用意されています。変換マトリックスを簡易的に操作するtranslate(), rotate(), scale()や変換マトリックスを直接操作するtransform(), setTransform()を通して、描画オブジェクトを変形させることができます。

座標を移動させる translate()

translate()は、描画オブジェクトの基準点を第1, 2引数で指定した座標(x, y)に移動します。下記の例では、まず変更していないコンテキストの状態をsave()で保存し、translate()で描画の基準点をcanvasの中央に変更しています。

次に基準点を中心に縦横100pxの正方形を描画した後、restore()でコンテキストを変更前の状態に戻しています。例のように、コンテキストに対する変形は、描画の前に記述する必要があります。

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.fillStyle = 'rgb(127, 127, 127)';
  context.fillRect(-50, -50, 100, 100);
  context.restore();
};

回転させる rotate()

rotate()は、引数で指定した角度に描画オブジェクトを回転させます。回転は基準点を中心に行われ、角度は時計回りのラジアン値で指定します。下記の例では、translate()で基準点をcanvasの中央に移動し、rotate()で時計回りに45度回転させてから、縦横100pxの正方形を描画しています。結果として、100pxの正方形が45度回転して、canvasの中央に描画されます。

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.rotate(45 * Math.PI / 180);
  context.fillStyle = 'rgb(127, 127, 127)';
  context.fillRect(-50, -50, 100, 100);
  context.restore();
};

伸縮させる scale()

scale()は、描画オブジェクトを伸縮させます。第1引数で水平方向の伸縮率、第2引数で垂直方向の伸縮率を指定します。下記の例では、translate()でcanvasの中央に移動、rotate()で時計回りに45度回転、scale()で水平方向に2倍、垂直方向に0.5倍の順番で処理させています。結果として、縦横100pxの矩形を描画すると横200px, 縦50pxの矩形が45度回転し、canvasの中央に描画されます。

translate(), rotate(), scale()による変形は処理の順序によって結果が異なります。コンテキストはrestore()されるまで、変換マトリックスの状態を維持するからです。例えば、translate()よりも先にscale(2, 2)と記述した場合、translate()による座標の移動量も指定した値の2倍になります。

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.rotate(45 * Math.PI / 180);
  context.scale(2, 0.5);
  context.fillStyle = 'rgb(127, 127, 127)';
  context.fillRect(-50, -50, 100, 100);
  context.restore();
};

変換マトリックスを変更する transform()

translate(), rotate(), scale()といったメソッドは、変換マトリックスを簡易的に変更するためのメソッドです。これらの変更は、変換マトリックスを直接操作することで行うこともできます。

transform()は、現在のコンテキストの変換マトリックスに引数で渡す行列を掛け合わせます。引数の行列は、ActionScript3.0のMatrixクラスと同じく3×3の正方行列で、指定できる値は(a, b, c, d, tx, ty)です。下記の例は、translate(), rotate(), scale()の処理をそれぞれtransform()で書き直したものです。

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.transform(1, 0, 0, 1, canvas.width * 0.5, canvas.height * 0.5);
  // context.rotate(45 * Math.PI / 180)と同じ処理
  var degree = 45;
  var degreeToRadian = Math.PI / 180;
  var cos = Math.cos(degree * degreeToRadian);
  var sin = Math.sin(degree * degreeToRadian);
  context.transform(cos, sin, -sin, cos, 0, 0);
  // context.scale(2, 0.5)と同じ処理
  context.transform(2, 0, 0, 0.5, 0, 0);
  // 図形を描画
  context.fillStyle = 'rgb(127, 127, 127)';
  context.fillRect(-50, -50, 100, 100);
  context.restore();
};

新規の変換マトリックスを作成する setTransform()

setTransform()は、変換マトリックスを引数で渡した行列で差し替えます。引数の行列は、transform()と同じく3×3の正方行列で、指定できる値は(a, b, c, d, tx, ty)です。

変換マトリックスを操作することにより、矩形を平行四辺形に変形させることができます。下記の例では、引数の行列で水平方向の傾斜率として-1を指定することにより、正方形を水平方向に傾いた平行四辺形に変形させています。

JavaScript

window.onload = function() {
  var canvas = document.getElementById('my-canvas');
  var context = canvas.getContext('2d');
  /*
   * a c tx
   * b d ty
   * 0 0 1
   */
  var a = 1;
  var b = 0;
  var c = -1;
  var d = 1;
  var tx = canvas.width * 0.5;
  var ty = canvas.height * 0.5;
  context.setTransform(a, b, c, d, tx, ty);
  context.fillStyle = 'rgb(127, 127, 127)';
  context.fillRect(-50, -50, 100, 100);
  context.restore();
};

変換マトリックスによる変形のサンプル

変換マトリックスによる簡単な変形のサンプルを作ってみました。canvas上でマウスを動かすとマウスのX座標に応じて、配置した画像が水平方向に傾いた平行四辺形に変形します。