イナヅマTVログ

Canvas始めました – 矩形を回転させる

| 1件のコメント

矩形を回転させるの巻。

Canvasでのオブジェクトの移動や回転はめんどい。
FlashのDisplayObjectを回転させるのに慣れているとなんでこんなに面倒なのかとぼやきたくなる。

まず描画した矩形を回転させるのではなく、回転しているのは描画のもとCanvasそのものだと考えるようにしました。

HTML

<canvas id='canvas'></canvas>

JavaScript

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
 
context.save();
 
context.fillStyle = '#0000ff';
context.fillRect(100,100,50,50);
 
context.setTransform(1,0,0,1,0,0);
var radian = 45 * Math.PI / 180;
context.rotate(radian);
context.fillStyle = '#ff0000';
context.fillRect(100,100,50,50);
 
context.fillStyle = '#00ff00';
context.fillRect(200,200,50,50);
 
context.restore();

rotate後にfillRectした矩形は思いもよらないところに描かれてしまいます。

save, restore
saveは現在の状態を保存し、restoreで復元します。
データは配列状態で保存されるようでsaveでpushされrestoreでshiftされるみたいです。
なんかめんどくさい。

setTransformはActionScriptのMatrixに相当するものだと思います。
回転させる前にsetTransformで定義してrotateするのかな。

上記のコードでsave, restoreを使わないときはrestoreの所を次のようにすれば同じ結果になります。

context.setTransform(1,0,0,1,0,0);

context.rotate(0);
context.rotate(0); は必要ない。

後から描く赤い矩形を座標[100, 100]で回転させるには少々工夫が必要になります。

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
 
context.save();
 
context.fillStyle = '#0000ff';
context.fillRect(100,100,50,50);
 
context.setTransform(1,0,0,1,0,0);
var radian = 45 * Math.PI / 180;
var x=100,y=100,w=50,h=50;
context.translate(x+0.5*w,y+0.5*h);
context.rotate(radian);
context.fillStyle = '#ff0000';
context.fillRect(-0.5*w,-0.5*h,w,h);
 
context.restore();

translateを使い移動させて回転させる。

ActionScriptでMatrixを使い中心点に関係なく回転させるやり方と同じ。

【回転】
Canvas state 保存
tarnsformation Matrixを初期化(identity)する, context.setTransform(1,0,0,1,0,0);
translateで移動
rotateで回転
fillRect座標を矩形の幅と高さの半分をネガティブ側へオフセットさせて描く
Canvas state  復元

【Matrix】関連関数
translate: 移動, rotate: 回転以外にscale: 拡大・縮小が用意されている。

【参考資料】
W3C: http://www.w3.org/TR/2010/WD-2dcontext-20100624/#transformations

MatrixはAdobeのActionScrit 3.0 リファレンスガイドが詳しい。
Matrix

update 2012-04-27
複数の矩形を回転させてみた。

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
 
var x=20,y=20,w=50,h=50, r=15;
 
function circle (x, y) {
    var r = 10;
    context.beginPath();
    context.arc(x+r, y+r, r, (Math.PI/180)*0, (Math.PI/180)*360, false);
    context.fillStyle = 'yellow';
    context.fill();
 
    context.closePath();
    context.fillStyle = 'rgba(255,0,0,0.5)';
}
 
context.fillStyle = '#0000ff';
context.fillRect(x,y,w,h);
circle(x, y);
 
context.setTransform(1,0,0,1,0,0);
var radian = 45 * Math.PI / 180;
context.translate(x+0.5*w,y+0.5*h);
context.rotate(radian);
context.fillStyle = 'rgba(255,0,0,0.5)';
context.fillRect(-0.5*w,-0.5*h,w,h);
circle(-0.5*w,-0.5*h);
 
context.setTransform(1,0,0,1,0,0);
x += 100;
context.translate(x+0.5*w,y+0.5*h);
context.rotate(90 * Math.PI / 180);
context.fillRect(-0.5*w,-0.5*h,w,h);;
circle(-0.5*w,-0.5*h);
 
context.setTransform(1,0,0,1,0,0);
x += 100;
context.translate(x+0.5*w,y+0.5*h);
context.rotate(135 * Math.PI / 180);
context.fillRect(-0.5*w,-0.5*h,w,h);
circle(-0.5*w,-0.5*h);
 
context.setTransform(1,0,0,1,0,0);
x += 100;
context.translate(x+0.5*w,y+0.5*h);
context.rotate(180 * Math.PI / 180);
context.fillRect(-0.5*w,-0.5*h,w,h);
circle(-0.5*w,-0.5*h);
 
context.setTransform(1,0,0,1,0,0);

canvas rotates