図形を変形させて描画するには?
解説
Canvasには、図形を変形させて描画するメソッドが用意されています。
変形には大きく分けて、拡大/縮小、回転、平行移動の3種類があります。
ここで注意すべき点は、「図形そのものを変形させる」のではなく、
「変形のきまりにしたがって図形が描かれる」というしくみになっていることです。
たとえば、「2倍に拡大する」という変形のきまり(変換またはマッピングともいいます)を決めると、
それ以降に描かれる図形は、何も指定せずに描いたときの2倍の大きさで描かれます。
さらに、その上で「2倍に拡大する」というルールを適用すると、4倍の大きさの図形が描かれることになります。
以下に個々の変形についての詳細を紹介します。
【拡大/縮小】
scale()メソッドを使うと、図形を拡大/縮小して描くことができます。
次の例では、正円を描いたあと、同じ図形を横方向に1.4倍、縦方向に0.6倍して描いています。
結果として、前者は正円ですが、後者は楕円になっています。
拡大/縮小の中心は、(0,0)です。
context.beginPath();
context.arc(60,70,30,0,Math.PI*2,false);
context.stroke();
context.beginPath();
context.scale(1.4, 0.6);
context.arc(60,70,30,0,Math.PI*2,false);
context.stroke();

【回転】
rotate()メソッドを使うと、図形を回転させて描くことができます。
次の例では、横長の長方形を描いたあと、同じ図形を時計回りに60°(Math.PI/6はラジアンで60°を表す)回転させて描いています。
回転の中心は、(0,0)です。
context.beginPath();
context.rect(60,20,40,20);
context.stroke();
context.beginPath();
context.rotate(Math.PI/6);
context.rect(60,20,40,20);
context.stroke();

【平行移動】
translate()メソッドを使うと、図形を平行移動させて描くことができます。
次の例では、横長の長方形を、横方向に40、縦方向に50だけ移動させて描いています。
context.beginPath();
context.rect(60,20,40,20);
context.stroke();
context.beginPath();
context.translate(40, 50);
context.rect(60,20,40,20);
context.stroke();

【拡大/縮小、回転、平行移動の組み合わせ】
次の例では、rotate()とtranslate()を使って、時計の文字盤のような模様を描いています。
context.beginPath();
context.translate(100,70);
for(var i=0; i<12; i++) {
context.rotate(Math.PI/6);
if(i == 0) {
context.fillRect(-2,40,4,12);
} else {
context.strokeRect(-2,40,4,12);
}
}

元になっている(-2,40)を左上の座標とし、幅が4、高さが12の四角形は、
変形を指定しなければ、左端の画面の境目にあたる部分に描かれるはずです。
この図形を30°ずつ回転させて12個描いたものを、Canvasの中央付近に平行移動することで、
文字盤のような図形を描いています。
ここで、注意してもらいたいのは、コード上は「回転→平行移動」ではなく、
「平行移動→回転」の順になっているということです。
図形を変形させるのでしたら「回転→平行移動」になりますが、変形して描画される
ように、座標系を動かしている形になっているので、「平行移動→回転」の順になっているのです。
【変形マトリクス】
上で見てきたような変形を一般化したものに、変形マトリクスというものがあります。
これは、次のような3×3の行列です。

この行列を使って次のように演算することで、元の座標(x,y)を変換した(x',y')という座標を得ることができます。

これを展開すると、次のような意味になります。
x' = m11 * x + m21 * y + dx
y' = m12 * x + m22 * y + dy
この変換を利用すると、拡大/縮小や回転だけでなく、平行四辺形や台形のように図形を歪ませるといった複雑な変形ができるようになります。
Canvasには、変形マトリクスの変換を行うためのメソッドが2つ用意されています。
context.transform(m11, m12, m21, m22, dx, dy)
context.setTransform(m11, m12, m21, m22, dx, dy)
transform()メソッドは、過去の変形を生かした上で変換を行います。
一方、setTransform()は、過去の変形は破棄するところが異なります。
引数の数と意味は、どちらも同じです。
次の例では、元になる長方形と、それを変形させた平行四辺形を描画しています。
context.beginPath();
context.rect(40,40,40,30);
context.stroke();
context.beginPath();
context.transform(2,1,1,2,-100,-100);
context.rect(40,40,40,30);
context.stroke();

【変形を元に戻す】
変形の状態を元に戻す方法としては、save()メソッドでコンテキストの状態を保存しておき、restore()メソッドで元に戻すというのがよいでしょう。また、以下のようにして単位変換行列を設定することで元に戻すこともできます。
context.setTransform(1,0,0,1,0,0);
関連項目
Canvasとは