縦書き文字列の出力 ActionScript 3.0,Flex SDK 4

2010年5月21日に行われた(仮)クラウド研究会にて実演させていただいた内容の中から縦書き文字列を出力するActionScript 3.0のコードを記載させていただきます。次回クラウド研究会では前回お伝えできなかったXML演算子について+ジョークアプリのご紹介となります。

以下よりミニ解説およびソースコードとなります。

ビルド方法 - Windows

FlexSDK はオープンソースとなっており、Adobe Open Source より入手が可能です。
http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4
こちらは、Release 版をご取得ください。またJava が必要になります。IEをお持ちの方はJavaプラグインをインストールお願いします。

ダウンロード後。ファイルを展開、展開フォルダを任意のフォルダに配置します。この時コピー先フォルダをメモしておきます。

コマンドプロンプトを開き、PATHを追加します。パスの追加は、

SET PATH=%PATH%;[コピー先フォルダ]¥bin

を指定します。上記パスを追加することで、Flex SDKのコンパイラ群を利用することができます。

解説

ソースコードのオリジナルはFlash CS シリーズにてパブリッシュ(SDKではビルド相当) 可能な縦書きコンポーネントを無料で入手可能なFlex SDK 4 にてビルド可能な形に変更したものです。変更の際にコンポーネントは取りやめ(主に時間的な制約です)。サンプルコードに仕立てています。

一部不思議なコードとして、クラスTategaki のコンストラクタTategaki() にて一度Sprite オブジェクトを作成、updateData() 呼び出し後、削除しています。何故でしょう?これはSpriteに幅高さが無いと、文字列が配置できないというトラブルを回避するためのもので子要素としてSprite を作成。ActionScript の策がオブジェクトGraphics を用いて矩形を描画(#FF0000で塗りつぶし)。その後文字列を追加完了後に削除という手順を取っています。


package
{
import flash.display.*;
import flash.text.engine.*;
import flash.system.Capabilities;

public class Tategaki extends Sprite
{
protected var __text:String = "";
protected var __targetTextLine:TextLine = null;
protected var __fontSize:Number = 25;
protected var __fontColor:uint = 0x000000;
protected var __fontName:String = "_明朝";
protected var __rotateMethod:String = "RotateByBlock";
protected var __alignMethod:String = "AlignTop";
protected var __letterSpacing :Number = 0.0;

public function Tategaki():void
{
trace( "Tategaki.Tategaki(): call" );

var p:Sprite = new Sprite();
p.graphics.beginFill( 0xFFFFFF );
p.graphics.drawRect(0,0,__fontSize,480);
p.graphics.endFill();
addChild( p );

// リサイズモードの変更

__text = "縦書き文字列";
__fontColor = 0x000000;

updateData();

removeChild( p );

trace( "Tategaki.Tategaki(): call" );
}

protected function updateData():void
{
trace( "Tategaki.updateData(): call" );

trace( "updateData(): tag - 1" );
if( __targetTextLine != null ){
this.removeChild( __targetTextLine );
__targetTextLine = null;
}
trace( "updateData(): tag - 2" );

if( __text != null && __text.length > 0 ){
trace( "updateData(): tag - 3" );
trace( "updateData(): __text=" + __text );
trace( "updateData(): __text.length=" + __text.length );

var Japanese_txt:String = __text;

trace( "updateData(): tag - 4" );

var textBlock:TextBlock = new TextBlock();
var font:FontDescription = new FontDescription( __fontName, FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.DEVICE, RenderingMode.CFF );

// フォントの設定
// font.fontName = __fontName;

var format:ElementFormat = new ElementFormat(font);
format.fontSize = __fontSize;
format.locale = "ja";
format.color = __fontColor;
format.trackingRight = __letterSpacing;

textBlock.baselineZero = TextBaseline.IDEOGRAPHIC_CENTER;
textBlock.textJustifier = (__rotateMethod == "RotateByElement") ? new SpaceJustifier("en", (__alignMethod != "AlignJustify") ? LineJustification.UNJUSTIFIED : LineJustification.ALL_INCLUDING_LAST ) : new EastAsianJustifier("ja", (__alignMethod != "AlignJustify") ? LineJustification.UNJUSTIFIED : LineJustification.ALL_INCLUDING_LAST );
// そろえの設定

switch( __rotateMethod ){
case "RotateByElement":
break;
case "RotateByBlock":
default:
textBlock.lineRotation = TextRotation.ROTATE_90;
break;
}

textBlock.content = new TextElement(Japanese_txt, format);

var previousLine:TextLine = null;

trace( "updateData(): tag - 5" );

__targetTextLine = textBlock.createTextLine(previousLine, height);

trace( "updateData(): x=" + x );
trace( "updateData(): width=" + width );
trace( "updateData(): scaleX=" + scaleX );
trace( "updateData(): __fontSize=" + __fontSize );
trace( "updateData(): __targetTextLine.width=" + __targetTextLine.width );

switch( __rotateMethod ){
case "RotateByElement":
__targetTextLine.rotation = 90;
break;
case "RotateByBlock":
default:
break;
}

__targetTextLine.x = x + width / 2;
__targetTextLine.y = y;

switch( __alignMethod ){
case "AlignCenter": // 中央寄席
__targetTextLine.y +=( (height - __targetTextLine.unjustifiedTextWidth) /2 );
break;
case "AlignBottom": // 下寄席
trace( "height=" + height );
__targetTextLine.y += (height - __targetTextLine.unjustifiedTextWidth);
break;
}
this.addChild(__targetTextLine);
}
}

// ユーティリティ
private function trim(str:String, char:String):String {
return trimBack(trimFront(str, char), char);
}

private function trimFront(str:String, char:String):String {
char = stringToCharacter(char);
if (str.charAt(0) == char) {
str = trimFront(str.substring(1), char);
}
return str;
}

private function trimBack(str:String, char:String):String {
char = stringToCharacter(char);
if (str.charAt(str.length - 1) == char) {
str = trimBack(str.substring(0, str.length - 1), char);
}
return str;
}

private function stringToCharacter(str:String):String {
if (str.length == 1) {
return str;
}
return str.slice(0, 1);
}

}
}