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


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

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

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



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

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

private var charTime:int = 100;

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

private var size:int = 14;

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


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

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

タイマーが描画遅れに追いついて文字が消えた時は目が点になりました・・・
001.<?xml version="1.0" encoding="utf-8"?>
002.<mx:Application
003.    xmlns:mx="http://www.adobe.com/2006/mxml"
004.    xmlns:rs="com.rubenswieringa.book.*"
005.    initialize="initData();"
006.    layout="absolute"
007.>
008. 
009.<mx:Style>
010. 
011.    Application {
012.        backgroundGradientColors: 9737053,0
013.    }
014. 
015.</mx:Style>
016. 
017. 
018.<mx:Script>
019.<![CDATA[
020.             
021.    import com.rubenswieringa.book.*;
022.    import mx.controls.*;
023.    import mx.events.*;
024.    import mx.rpc.events.*;
025.    import mx.formatters.*;
026.    import flash.external.*;
027. 
028.    // ページ数
029.    private var numPage:int = 6;
030.    //
031.    [Bindable]
032.    private var canvasWidth:int = 400;
033.    [Bindable]
034.    private var canvasHeight:int = 530;
035. 
036.    // タイマー
037.    // あまり速くするとタイマーが追いついて文字が飛んでしまいます
038.    private var myTimer:Timer = new Timer(1000);    // この時間はダミー
039.    private var charTime:int = 100; // 文字描画間隔
040. 
041.    private var endTimer:Timer = new Timer(1000);
042. 
043.    // Label用ワーク変数
044.    private var ch:Label = null;
045. 
046.    // フォントサイズ
047.    private var size:int = 14;
048.    private var fk:Number = 1.0;
049. 
050.    // 横のマス数
051.    private var a:int = 0;
052.    // 縦のマス数
053.    private var b:int = 0;
054. 
055.    // カウンタ
056.    private var i:int = 0;
057.    private var seq:int = 0;
058. 
059.    // 文字マスとしての座標
060.    private var xm:int = 0;
061.    private var ym:int = 0;
062. 
063.    // 実際の座標
064.    private var xl:int = 0;
065.    private var yl:int = 0;
066. 
067.    private var bmp:BitmapData = null;
068. 
069.    // 書き込み済みのページ番号
070.    private var writingPage:int = 0;
071. 
072.    private var cvsWork:Canvas;
073. 
074.    private var str:String;
075. 
076.    // *********************************************************
077.    // アプリケーションの初期化
078.    // *********************************************************
079.    public function initData():void {
080. 
081.        fk = Math.round( size / 14 );
082. 
083.        // 横のマス数
084.        a = ( canvasWidth - 10 ) / ( size + 2 );
085.        // 縦のマス数
086.        b = ( canvasHeight - 10 ) / ( size + 2 ) - 1;
087. 
088. 
089.        // カウンタ初期化
090.        i = 1;
091.        seq = 0;
092. 
093.        // 効果
094.        myFade1.play();
095. 
096.        myTimer.addEventListener("timer", drawChar);
097.        endTimer.addEventListener("timer", endAction);
098. 
099.    }
100. 
101.    // *****************************************************
102.    // ページをめくると文章が書かれます
103.    // *****************************************************
104.    private function drawAction(eventPage:BookEvent):void {
105. 
106. 
107.        var pageId:String = eventPage.page.id;
108.        switch( pageId ) {
109.            case "pg0":
110.                if ( writingPage == 0 ) {
111.                    writingPage = 1;
112.                    cvsWork = cvs1;
113.                    bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
114.                    myTimer.delay = 400;    // 文字描画開始までの待ち時間
115.                    sendAction();
116.                }
117.                break;
118.            case "pg2":
119.                if ( writingPage == 2 && i == 1 ) {
120.                    writingPage = 3;
121.                    cvsWork = cvs3;
122.                    bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
123.                    myTimer.delay = 400;    // 文字描画開始までの待ち時間
124.                    sendAction();
125.                }
126.                break;
127.            case "pg4":
128.                if ( writingPage == 4 && i == 1 ) {
129.                    writingPage = 5;
130.                    cvsWork = cvs5;
131.                    bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
132.                    myTimer.delay = 400;    // 文字描画開始までの待ち時間
133.                    sendAction();
134.                }
135.                break;
136.        }
137. 
138. 
139.    }
140. 
141.    // *****************************************************
142.    // 最後の処理
143.    // *****************************************************
144.    private function endAction(event:TimerEvent):void {
145. 
146.        endTimer.stop();
147. 
148.    }
149. 
150.    // *****************************************************
151.    // 1文字づつの書き込み
152.    // *****************************************************
153.    private function drawChar(event:TimerEvent):void {
154. 
155.        if ( i > str.length ) {
156.            drawCanvas( cvsWork );
157.            myTimer.stop();
158. 
159.            // 最後の処理
160.            if ( writingPage == 5 ) {
161.                endTimer.start();
162.            }
163. 
164.            i = 1;
165.            seq = 0;
166. 
167.            switch( writingPage ) {
168.                case 1:
169.                    writingPage = 2;
170.                    cvsWork = cvs2;
171.                    bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
172.                    sendAction();
173.                    break;
174.                case 3:
175.                    writingPage = 4;
176.                    cvsWork = cvs4;
177.                    bmp = new BitmapData(canvasWidth, canvasHeight,true,0);
178.                    sendAction();
179.                    break;
180.            }
181.            return;
182.        }
183.        // 30 回に一回背景に書き込んで、Label を削除する
184.        if ( i % 30 == 0 ) {
185.            drawCanvas( cvsWork );
186.        }
187. 
188.        // 以下、1文字づつの書き込み
189.        seq++;
190. 
191.        if ( i == 1 ) {
192.            myTimer.delay = charTime;
193.            seq++;
194.        }
195.        if ( str.charAt( i-1 ) == "\n" ) {
196.            seq += b-((seq-1)%b); 
197.        }
198. 
199.        xm = a - Math.floor( (seq-1) / b ) - 1;
200.        ym = (seq-1) % b;
201.        xl = xm * (size + 2);
202.        yl = ym * (size + 2)+4;
203. 
204.        var tc:String = str.charAt( i-1 );
205.        var fs:String = size.toString();
206. 
207.        switch( tc ) {
208.            case 'ー':
209.            case '-':
210.            case '-':
211.                tc = "|";
212.                fs = (size - 1).toString();
213.                xl += Math.round(fk * 1);
214.                break;
215.            case "。":
216.                xl += Math.round(fk * 5);
217.                yl -= Math.round(fk * 8);
218.                break;
219.            case "、":
220.                xl += Math.round(fk * 7);
221.                yl -= Math.round(fk * 8);
222.                break;
223.            case 'ぁ':
224.            case 'ぅ':
225.            case 'ぇ':
226.            case 'ぉ':
227.            case 'ゃ':
228.            case 'ゅ':
229.            case 'ょ':
230.            case 'っ':
231.            case 'ァ':
232.            case 'ゥ':
233.            case 'ェ':
234.            case 'ォ':
235.            case 'ャ':
236.            case 'ュ':
237.            case 'ョ':
238.            case 'ッ':
239.                xl += Math.round(fk * 3);
240.                yl -= Math.round(fk * 2);
241.                break;
242.            case "「":
243.                xl -= Math.round(fk * 9);
244.                yl += Math.round(fk * 6);
245.                break;
246.            case "」":
247.                xl += Math.round(fk * 8);
248.                yl -= Math.round(fk * 5);
249.                break;
250.        }
251. 
252.        ch = new Label();
253.        ch.text = tc;
254.        ch.x = xl;
255.        ch.y = yl;
256.        ch.setStyle("textAlign", "center");
257.        ch.setStyle("fontSize", fs);
258.        cvsWork.addChild( ch );
259. 
260.        i++;
261. 
262.    }
263. 
264.    // *****************************************************
265.    // 10文字毎の、背景への転送
266.    // *****************************************************
267.    private function drawCanvas(target:Canvas):void {
268. 
269.        // 自分自身の背景に(Labelを含めた)全体を上書きする
270.        bmp.draw(target,null,null,"normal");
271.        target.graphics.clear();
272.        target.graphics.beginBitmapFill(bmp);
273.        target.graphics.drawRect(0, 0, canvasWidth, canvasHeight);
274.        target.graphics.endFill();
275.        target.removeAllChildren();
276.    }
277. 
278.    // *****************************************************
279.    // ページの本文取得
280.    // *****************************************************
281.    private function sendAction():void  {
282.     
283.        httpService.url = "response" + writingPage + ".txt";
284.        httpService.send();
285.     
286.    }
287. 
288.    // *****************************************************
289.    // タイマー書き込み開始
290.    // *****************************************************
291.    private function actResult(event:ResultEvent):void{
292. 
293.        str = event.result.toString();
294.        myTimer.start();
295. 
296.    }
297.     
298.    private function actFault(event:FaultEvent):void{
299. 
300.        Alert.show(event.message.toString());
301. 
302.    }
303. 
304.]]>
305.</mx:Script>
306. 
307.<mx:HTTPService
308.    id="httpService"
309.    method="GET"
310.    result="actResult(event)"
311.    fault="actFault(event)"
312.    resultFormat="text"
313./>
314. 
315.<rs:Book id="myBook"
316.    x="{Math.round(Application.application.width/2-400)}"
317.    y="30"
318.    width="800" height="530"
319.    openAt="5"
320.    autoFlipDuration="600"
321.    easing="0.7"
322.    regionSize="150"
323.    sideFlip="true"
324.    hardCover="true"
325.    hover="true"
326.    snap="false"
327.    flipOnClick="true"
328.    pageTurned="drawAction(event)"
329.>
330. 
331.    <rs:Page backgroundColor="0xFFFFFF" backgroundAlpha="1" id="pg5">
332.        <mx:Image
333.            source="@Embed('p5.jpg')"
334.            alpha="0.4"
335.        />
336.        <mx:Canvas id="cvs5"
337.            width="{canvasWidth}"
338.            height="{canvasHeight}"
339.            textAlign="left"
340.        >
341.        </mx:Canvas>
342.    </rs:Page>
343. 
344.    <rs:Page backgroundColor="0xD9D6B6" backgroundAlpha="0.93" id="pg4">
345.        <mx:Canvas id="cvs4"
346.            width="{canvasWidth}"
347.            height="{canvasHeight}"
348.            textAlign="left"
349.        >
350.        </mx:Canvas>
351.    </rs:Page>
352. 
353.    <rs:Page backgroundColor="0xD9D6B6" backgroundAlpha="0.93" id="pg3">
354.        <mx:Canvas id="cvs3"
355.            width="{canvasWidth}"
356.            height="{canvasHeight}"
357.            textAlign="left"
358.        >
359.        </mx:Canvas>
360.    </rs:Page>
361. 
362.    <rs:Page backgroundColor="0xD9D6B6" backgroundAlpha="0.93" id="pg2">
363.        <mx:Canvas id="cvs2"
364.            width="{canvasWidth}"
365.            height="{canvasHeight}"
366.            textAlign="left"
367.        >
368.        </mx:Canvas>
369.    </rs:Page>
370. 
371.    <rs:Page backgroundColor="0xD9D6B6" backgroundAlpha="0.93" id="pg1">
372.        <mx:Canvas id="cvs1"
373.            width="{canvasWidth}"
374.            height="{canvasHeight}"
375.            textAlign="left"
376.        >
377.        </mx:Canvas>
378.    </rs:Page>
379. 
380.    <rs:Page backgroundColor="0xFFFFFF" backgroundAlpha="1" id="pg0">
381.        <mx:Image id="p0"
382.            source="@Embed('p0.jpg')"
383.            alpha="0.4"
384.        />
385.        <mx:Image id="title"
386.            x="{Math.round((400-title.width)/2)}"
387.            y="{Math.round((530-title.height)/2)}"
388.            source="@Embed('title.png')"
389.        />
390.    </rs:Page>
391. 
392.</rs:Book>
393. 
394.<mx:Fade id="myFade1"
395.     target="{title}"
396.     duration="3000"
397.     alphaFrom="0" alphaTo="1"
398./>
399. 
400.</mx:Application>
先頭ページのデータ
01.今は昔、竹取の翁といふ者ありけり。
02.野山にまじりて竹を取りつつ、よろづのことに 使ひけり。
03. 
04.名をば、さぬきの造となむいひける。
05.その竹の中に、もと光る竹なむ一筋ありける。
06. 
07.怪しがりて、寄りて見るに、筒の中光りたり。
08.それを見れば、三寸ばかりなる人、いとうつくしうてゐたり。
09. 
10.翁、言ふやう、
11. 
12.「我、朝ごと夕ごとに見る竹の中におはするにて、知りぬ」
13. 
14.「子となり給ふべき人なめり」
15. 
16.とて、手にうち入れて、家へ持ちて来ぬ。
17.妻の嫗に預けて養はす。
18.うつくしきこと限りなし。
19. 
20.いと幼ければ籠に入れて養ふ。
「 とか 」は、既存の文字使っているので、向きが逆です。
実際は画像を作って使う必要があります。

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

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

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