関連ページ  
【WEB Flex】縦書き Flex book で古典を読む(竹取物語)


ブラウザでダウンロード
めくりながら、一文字づつ表示されて行きます。
作った本人が言うのもなんですが、風情がありますね・・・・

テキストはページ毎にサーバに用意します。
ページ数や、表示速度やフォントサイズの変更はビルドする必要があります。

もうちょっと頑張れば汎用的になると思います。
( 誰かやって・・ )
↓実行リンク



ソースコード
先にページをめくっても、ページを書き終わってからめくらないと前へすすみません。
左右のページが開いている場合は、右から左へイベントが進みます。

メインのパラメータは以下ですが、実際はソースコードの
微調整が必要になって来るでしょう。

private var charTime:int = 100;

	1文字1文字の描画のタイマー間隔です

private var size:int = 14;

	文字のフォントサイズ
	( あまり大きいと美しく無いです )


ソースは凝った事をせずに、ベタな書き方をしていますが、
このほうが誰でもコードを追えるはずです。

というか、Flex で凝った事すると、絶対痛い目にあいます。
それでなくとも、非同期です。

タイマーが描画遅れに追いついて文字が消えた時は目が点になりました・・・
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:rs="com.rubenswieringa.book.*"
	initialize="initData();"
	layout="absolute"
>

<mx:Style>

	Application {
		backgroundGradientColors: 9737053,0
	}

</mx:Style>


<mx:Script>
<![CDATA[
			
	import com.rubenswieringa.book.*;
	import mx.controls.*;
	import mx.events.*; 
	import mx.rpc.events.*;
	import mx.formatters.*;
	import flash.external.*;

	// ページ数
	private var numPage:int = 6;
	// 
	[Bindable]
	private var canvasWidth:int = 400;
	[Bindable]
	private var canvasHeight:int = 530;

	// タイマー
	// あまり速くするとタイマーが追いついて文字が飛んでしまいます
	private var myTimer:Timer = new Timer(1000);	// この時間はダミー
	private var charTime:int = 100;	// 文字描画間隔

	private var endTimer:Timer = new Timer(1000);

	// Label用ワーク変数
	private var ch:Label = null;

	// フォントサイズ
	private var size:int = 14;
	private var fk:Number = 1.0;

	// 横のマス数
	private var a:int = 0;
	// 縦のマス数
	private var b:int = 0;

	// カウンタ
	private var i:int = 0;
	private var seq:int = 0;

	// 文字マスとしての座標
	private var xm:int = 0;
	private var ym:int = 0;

	// 実際の座標
	private var xl:int = 0;
	private var yl:int = 0;

	private	var bmp:BitmapData = null;

	// 書き込み済みのページ番号
	private var writingPage:int = 0;

	private var cvsWork:Canvas;

	private var str:String;

	// *********************************************************
	// アプリケーションの初期化
	// *********************************************************
	public function initData():void {

		fk = Math.round( size / 14 );

		// 横のマス数
		a = ( canvasWidth - 10 ) / ( size + 2 );
		// 縦のマス数
		b = ( canvasHeight - 10 ) / ( size + 2 ) - 1;


		// カウンタ初期化
		i = 1;
		seq = 0;

		// 効果
		myFade1.play();

		myTimer.addEventListener("timer", drawChar);
		endTimer.addEventListener("timer", endAction);

	}

	// *****************************************************
	// ページをめくると文章が書かれます
	// *****************************************************
	private function drawAction(eventPage:BookEvent):void {


		var pageId:String = eventPage.page.id;
		switch( pageId ) {
			case "pg0":
				if ( writingPage == 0 ) {
					writingPage = 1;
					cvsWork = cvs1;
					bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
					myTimer.delay = 400;	// 文字描画開始までの待ち時間
					sendAction();
				}
				break;
			case "pg2":
				if ( writingPage == 2 && i == 1 ) {
					writingPage = 3;
					cvsWork = cvs3;
					bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
					myTimer.delay = 400;	// 文字描画開始までの待ち時間
					sendAction();
				}
				break;
			case "pg4":
				if ( writingPage == 4 && i == 1 ) {
					writingPage = 5;
					cvsWork = cvs5;
					bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
					myTimer.delay = 400;	// 文字描画開始までの待ち時間
					sendAction();
				}
				break;
		}


	}

	// *****************************************************
	// 最後の処理
	// *****************************************************
	private function endAction(event:TimerEvent):void {

		endTimer.stop();

	}

	// *****************************************************
	// 1文字づつの書き込み
	// *****************************************************
	private function drawChar(event:TimerEvent):void {

		if ( i > str.length ) {
			drawCanvas( cvsWork );
			myTimer.stop();

			// 最後の処理
			if ( writingPage == 5 ) {
				endTimer.start();
			}

			i = 1;
			seq = 0;

			switch( writingPage ) {
				case 1:
					writingPage = 2;
					cvsWork = cvs2;
					bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
					sendAction();
					break;
				case 3:
					writingPage = 4;
					cvsWork = cvs4;
					bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
					sendAction();
					break;
			}
			return;
		}
		// 30 回に一回背景に書き込んで、Label を削除する
		if ( i % 30 == 0 ) {
			drawCanvas( cvsWork );
		}

		// 以下、1文字づつの書き込み
		seq++;

		if ( i == 1 ) {
			myTimer.delay = charTime;
			seq++;
		}
		if ( str.charAt( i-1 ) == "\n" ) {
			seq += b-((seq-1)%b);  
		}

		xm = a - Math.floor( (seq-1) / b ) - 1;
		ym = (seq-1) % b;
		xl = xm * (size + 2);
		yl = ym * (size + 2)+4;

		var tc:String = str.charAt( i-1 );
		var fs:String = size.toString();

		switch( tc ) {
			case 'ー':
			case '−':
			case '-':
				tc = "|";
				fs = (size - 1).toString();
				xl += Math.round(fk * 1);
				break;
			case "。":
				xl += Math.round(fk * 5);
				yl -= Math.round(fk * 8);
				break;
			case "、":
				xl += Math.round(fk * 7);
				yl -= Math.round(fk * 8);
				break;
			case 'ぁ':
			case 'ぅ':
			case 'ぇ':
			case 'ぉ':
			case 'ゃ':
			case 'ゅ':
			case 'ょ':
			case 'っ':
			case 'ァ':
			case 'ゥ':
			case 'ェ':
			case 'ォ':
			case 'ャ':
			case 'ュ':
			case 'ョ':
			case 'ッ':
				xl += Math.round(fk * 3);
				yl -= Math.round(fk * 2);
				break;
			case "「":
				xl -= Math.round(fk * 9);
				yl += Math.round(fk * 6);
				break;
			case "」":
				xl += Math.round(fk * 8);
				yl -= Math.round(fk * 5);
				break;
		}

		ch = new Label();
		ch.text = tc;
		ch.x = xl;
		ch.y = yl;
		ch.setStyle("textAlign", "center");
		ch.setStyle("fontSize", fs);
		cvsWork.addChild( ch );

		i++;

	}

	// *****************************************************
	// 10文字毎の、背景への転送
	// *****************************************************
	private function drawCanvas(target:Canvas):void {

		// 自分自身の背景に(Labelを含めた)全体を上書きする
		bmp.draw(target,null,null,"normal");
		target.graphics.clear();
		target.graphics.beginBitmapFill(bmp); 
		target.graphics.drawRect(0, 0, canvasWidth, canvasHeight); 
		target.graphics.endFill();
		target.removeAllChildren();
	}

	// *****************************************************
	// ページの本文取得
	// *****************************************************
	private function sendAction():void  {
	
		httpService.url = "response" + writingPage + ".txt";
		httpService.send();
	
	}

	// *****************************************************
	// タイマー書き込み開始
	// *****************************************************
	private function actResult(event:ResultEvent):void{

		str = event.result.toString();
		myTimer.start();

	}
	
	private function actFault(event:FaultEvent):void{

		Alert.show(event.message.toString());

	}

]]>
</mx:Script>

<mx:HTTPService
	id="httpService" 
	method="GET"
	result="actResult(event)" 
	fault="actFault(event)"
	resultFormat="text"
/>

<rs:Book id="myBook"
	x="{Math.round(Application.application.width/2-400)}"
	y="30"
	width="800" height="530" 
	openAt="5"
	autoFlipDuration="600"
	easing="0.7"
	regionSize="150"
	sideFlip="true"
	hardCover="true"
	hover="true"
	snap="false"
	flipOnClick="true"
	pageTurned="drawAction(event)"
>

	<rs:Page backgroundColor="0xFFFFFF" backgroundAlpha="1" id="pg5">
		<mx:Image
			source="@Embed('p5.jpg')"
			alpha="0.4"
		/>
		<mx:Canvas id="cvs5"
			width="{canvasWidth}"
			height="{canvasHeight}"
			textAlign="left"
		>
		</mx:Canvas>
	</rs:Page>

	<rs:Page backgroundColor="0xD9D6B6" backgroundAlpha="0.93" id="pg4">
		<mx:Canvas id="cvs4"
			width="{canvasWidth}"
			height="{canvasHeight}"
			textAlign="left"
		>
		</mx:Canvas>
	</rs:Page>

	<rs:Page backgroundColor="0xD9D6B6" backgroundAlpha="0.93" id="pg3">
		<mx:Canvas id="cvs3"
			width="{canvasWidth}"
			height="{canvasHeight}"
			textAlign="left"
		>
		</mx:Canvas>
	</rs:Page>

	<rs:Page backgroundColor="0xD9D6B6" backgroundAlpha="0.93" id="pg2">
		<mx:Canvas id="cvs2"
			width="{canvasWidth}"
			height="{canvasHeight}"
			textAlign="left"
		>
		</mx:Canvas>
	</rs:Page>

	<rs:Page backgroundColor="0xD9D6B6" backgroundAlpha="0.93" id="pg1">
		<mx:Canvas id="cvs1"
			width="{canvasWidth}"
			height="{canvasHeight}"
			textAlign="left"
		>
		</mx:Canvas>
	</rs:Page>

	<rs:Page backgroundColor="0xFFFFFF" backgroundAlpha="1" id="pg0">
		<mx:Image id="p0"
			source="@Embed('p0.jpg')"
			alpha="0.4"
		/>
		<mx:Image id="title"
			x="{Math.round((400-title.width)/2)}"
			y="{Math.round((530-title.height)/2)}"
			source="@Embed('title.png')"
		/>
	</rs:Page>

</rs:Book>

<mx:Fade id="myFade1"
	 target="{title}"
	 duration="3000"
	 alphaFrom="0" alphaTo="1"
/>

</mx:Application>
先頭ページのデータ
今は昔、竹取の翁といふ者ありけり。
野山にまじりて竹を取りつつ、よろづのことに 使ひけり。

名をば、さぬきの造となむいひける。
その竹の中に、もと光る竹なむ一筋ありける。

怪しがりて、寄りて見るに、筒の中光りたり。
それを見れば、三寸ばかりなる人、いとうつくしうてゐたり。

翁、言ふやう、

「我、朝ごと夕ごとに見る竹の中におはするにて、知りぬ」

「子となり給ふべき人なめり」

とて、手にうち入れて、家へ持ちて来ぬ。
妻の嫗に預けて養はす。
うつくしきこと限りなし。

いと幼ければ籠に入れて養ふ。
「 とか 」は、既存の文字使っているので、向きが逆です。
実際は画像を作って使う必要があります。

文字によっては、中央がズレるのがあるので微調整するべきですが・・・

デザインは専門では無いので、あんまり手をつけなかったのですが、
画像や Flash のテクニックはなんでもありのはずですね。

( タイトルだけフェードインしましたけど )