takuti.me ABOUT

2013-08-03

HTML5 Canvasの回転と角丸についてメモ

HTML5 CanvasでメルトPVに出てくるメル時計をつくったで、ビギナーの僕には少し厄介だった回転と角丸化についてメモメモ。

回転 rotate() の扱い方

メル時計の文字盤代わりの六角形は、12時の位置に全ての時刻分を(色を変えながら)作りつつ、それらを30°ずつ回転させていくことで描画しました。

hexagon
1:てっぺんをスタートして右に8px、下に10pxの移動
2:下に18pxの移動
3:2の移動した先から、更に下に3px移動したところが、もう1つの六角形のてっぺん

この3つさえ分かればあとは対称だったりするので、とりあえず12時の位置に色を変えながら量産することは問題なくできます。あとは30°ずつ回転をさせるだけです。

しかし、rotate()はcanvasそのものの左上を中心とみて回転させるので、ふつうにrotate(Math.PI/6)とかやっても思うように回ってくれません。円(時計)の中心を回転の中心にしてほしい!

そんなときは、「現時点でのcanvasそのものの左上を円の中心にズラしてから回転させる。回転が終わったらズラした分を元に戻す。」という方法をとるみたいです。

【参考】今更聞けないcanvasの基礎の基礎 | tech.kayac.com - KAYAC engineers' blog

つまり、canvas全体を回転の中心にしたい座標(今回は400x400のcanvasに描画した半径200の円の中心なので(200,200))の分だけ移動して、本来回転させたかった角度で回転させたら、移動させた分を元に戻す、と。

ctx.translate(200,200);
ctx.rotate(30*Math.PI/180);
ctx.translate(-200,-200);

デキター!

ちなみに、rotate()の状態を解除する方法も分からなくて悲しみました。

rotate(θ)をした後に何もしないと、以後の描画処理が全て角度θだけ回転した状態で行われてしまうんですね。だから、もう回転の必要がなくなったらそれを解除して、全く回転していない状態に戻してあげる必要があるというわけなんだとか。

そこでよく使われるのがsave()restore()で、これらを使うと描画状態(回転情報も含んでいる変換行列など)を保存して、復元することができる。

全く回転していない状態をsave()して、回転の必要がなくなったところですぐrestore()してあげれば、その後もイメージどおりに描画できるんですね!

ctx.save(); // 変換行列の初期状態(全く回転していない状態)を保存

rotateSomething(); // 回転を含む処理

// 回転を含む処理の後には必ず変換行列を初期状態に戻し、再度保存しておく
ctx.restore();
ctx.save();

save()restore()はスタックのPushとPopに対応するので、一度restore()をしてしまうとせっかく保存していた初期状態の情報が消えてしまいます。そのため、restore()の直後にもう一度save()をして、次の回転を含む処理に備えます。

というわけで、移動させてから回転させてまた戻すことと、回転した状態を解除することによって、イメージ通りの回転を含む描画処理いろいろができました。

角丸な長方形

長方形を角丸にしたい場面はたくさんあるのに、Canvasではササッと角丸な長方形を作ってくれる機能などありません。

そこで、角丸長方形は1/4の円弧を4つ描いてそれらを結ぶことによって実現します。

Screen Shot 2013-08-04 at 12.19.25 PM
これは円弧ひとつひとつに対してbeginPath(),stroke()をしたもの。

これを、beginPath()を最初に一度だけ行い、円弧すべてのarc()を実行した後にclosePath()をしてあげるようにすれば、あとはstroke()なりfill()なりでお好みの角丸な長方形ができあがる。

長方形の位置や幅、高さは4つの円弧の中心点に依存するわけですね。

これについては、以下を参考にさせていただき解釈しました。
[javascript]canvasで円や角丸の矩形を描画する

以上、回転と角丸についてのメモでした。