2007年08月30日
AS3 で RSS アイコンを描画
ActionScript 3 で Photoshop チュートリアル実践シリーズ 第2弾。
今回は RSS アイコンを作ってみました。
参考にしたサイトは Photohop: RSS-Icon Standard in Variationen。ドイツ語で読めないけど、PSD ファイルが公開されているのでそれに沿って作成しました。
表面の描画は 前回 とほとんど同じなので省略。
いろいろ思いついて面白いのが「1/4 ドーナッツ」をどう描くか。円をマスクしてもできるんですが、それでは面白くないので、別の方法を3通り考えてみました。
1. 素直に外枠をなぞるパスを作る
1つ目は一番最初に思いついた単純だけどめんどくさい方法。
内側のドーナッツ作成コードがこれです。
private function drawPattern1(g:Graphics):void { g.beginFill(0xffffff); g.moveTo(24, 52); arcTo(g, 24, 108, 56, -Math.PI / 2, 0); arcTo(g, 24, 108, 40, 0, -Math.PI / 2); g.endFill(); // ...
座標がいっぱい出てくるので、イメージがつかみやすいように図を描いてみました。
Graphics クラスには弧を描画する関数がないので、arcTo というメソッドを定義しています。FN0506002 - 描画メソッドで円を描く - Flash : テクニカルノート を参考にしてベジェ曲線で描いています。
2. 線として弧を描く
2つ目は太い線として描く方法。
先ほどと同じく、arcTo 関数を使って描画します。
private function drawPattern2(g:Graphics):void { g.moveTo(24, 60); g.lineStyle(16, 0xffffff, 1, false, "normal", CapsStyle.NONE); arcTo(g, 24, 108, 48, -Math.PI / 2, 0); g.lineStyle(0, 0, 0); // ...
だいぶシンプルになりました。
3. 扇から扇を引く
最後はちょっとアクロバットに描画。
private function drawPattern2(g:Graphics):void { g.beginFill(0xffffff); drawPie(g, 24, 106, 56, -Math.PI / 2, 0); drawPie(g, 24, 106, 40, -Math.PI / 2, 0); g.endFill(); // ...
1/4円を2つ描いて XOR にしてます。このテクニックについては beginFill と endFill のケーススタディ で説明済みです。
drawPie は独自に定義したメソッドなのですが、内部で arcTo を使っているので行数は短くなってます。
ソース全体
まとめ代わりにソースを掲載。長いよ。
package { import flash.display.*; import flash.filters.*; import flash.geom.*; [SWF(width="128", height="128")] public class RssIcon extends Sprite { private const SIZE:int = 128; private const ROUND:int = 48; public function RssIcon():void { var matrix:Matrix = new Matrix(); matrix.createGradientBox(SIZE, SIZE, Math.PI * 1 / 4); var glowFilter:GlowFilter = new GlowFilter(0xffffbe, 0.75); glowFilter.inner = true; // 外側の角円四角 var base:Shape = new Shape(); base.graphics.beginFill(0xcc6611); base.graphics.drawRoundRect(0, 0, SIZE, SIZE, ROUND, ROUND); base.graphics.endFill(); addChild(base); // 内側の角円四角 var base2:Shape = new Shape(); base2.graphics.beginFill(0xee7722); base2.graphics.drawRoundRect(1, 1, SIZE - 2, SIZE - 2, ROUND - 1, ROUND - 1); base2.graphics.endFill(); base2.filters = [glowFilter]; addChild(base2); // グラデーション var gross:Shape = new Shape(); gross.graphics.beginGradientFill("linear", [0xffffff, 0x000000], [0.2, 0.2], [0, 255], matrix); gross.graphics.drawRoundRect(0, 0, SIZE, SIZE, ROUND, ROUND); gross.graphics.endFill(); gross.graphics.beginGradientFill("linear", [0xffffff, 0xffffff, 0xffffff], [0, 0.2, 0], [0, 112, 255], matrix); gross.graphics.drawRoundRect(0, 0, SIZE, SIZE, ROUND, ROUND); gross.graphics.endFill(); gross.blendMode = BlendMode.OVERLAY; addChild(gross); // ● var white:Shape = new Shape(); white.graphics.beginFill(0xffffff); white.graphics.drawCircle(36, 96, 12); white.graphics.endFill(); // )) drawPattern1(white.graphics); //drawPattern2(white.graphics); //drawPattern3(white.graphics); addChild(white); } // その1: 素直に外枠をなぞるパスを作る private function drawPattern1(g:Graphics):void { g.beginFill(0xffffff); g.moveTo(24, 52); arcTo(g, 24, 108, 56, -Math.PI / 2, 0); arcTo(g, 24, 108, 40, 0, -Math.PI / 2); g.endFill(); g.beginFill(0xffffff); g.moveTo(24, 22); arcTo(g, 24, 108, 86, -Math.PI / 2, 0); arcTo(g, 24, 108, 70, 0, -Math.PI / 2); g.endFill(); } // その2: 線として弧を描く private function drawPattern2(g:Graphics):void { g.moveTo(24, 60); g.lineStyle(16, 0xffffff, 1, false, "normal", CapsStyle.NONE); arcTo(g, 24, 108, 48, -Math.PI / 2, 0); g.lineStyle(0, 0, 0); g.moveTo(24, 30); g.lineStyle(16, 0xffffff, 1, false, "normal", CapsStyle.NONE); arcTo(g, 24, 108, 78, -Math.PI / 2, 0); g.lineStyle(0, 0, 0); } // その3: 扇から扇を引く private function drawPattern3(g:Graphics):void { g.beginFill(0xffffff); drawPie(g, 24, 106, 56, -Math.PI / 2, 0); drawPie(g, 24, 106, 40, -Math.PI / 2, 0); g.endFill(); g.beginFill(0xffffff); drawPie(g, 24, 106, 86, -Math.PI / 2, 0); drawPie(g, 24, 106, 70, -Math.PI / 2, 0); g.endFill(); } // 弧を描くメソッド // (参考) http://www.fumiononaka.com/TechNotes/Flash/FN0506002.html private function arcTo(g:Graphics, x:Number, y:Number, radius:Number, startAngle:Number, endAngle:Number):void { var clockwise:Boolean = startAngle < endAngle; g.lineTo(x + radius * Math.cos(startAngle), y + radius * Math.sin(startAngle)); while(clockwise && startAngle < endAngle || !clockwise && startAngle > endAngle) { var nextAngle:Number = clockwise ? Math.min(endAngle, startAngle + Math.PI / 4) : Math.max(endAngle, startAngle - Math.PI / 4); var nextPos:Point = new Point( Math.cos(nextAngle) * radius, Math.sin(nextAngle) * radius); var controlPos:Point = new Point( radius * Math.tan((nextAngle - startAngle) / 2) * Math.cos(nextAngle - Math.PI / 2), radius * Math.tan((nextAngle - startAngle) / 2) * Math.sin(nextAngle - Math.PI / 2) ); g.curveTo(x + nextPos.x + controlPos.x, y + nextPos.y + controlPos.y, x + nextPos.x, y + nextPos.y); startAngle = nextAngle; } } // 扇形を描くメソッド private function drawPie(g:Graphics, x:Number, y:Number, radius:Number, startAngle:Number, endAngle:Number):void { g.moveTo(x, y); arcTo(g, x, y, radius, startAngle, endAngle); } } }