2010年10月8日 星期五

[Javascript] EPUB Reader 翻頁效果的原理

幾天前收到一個問題,關於坊間常見得 Javascript 版 EPUB Reader ,他們處理翻頁的效果是怎樣做的呢?


可以看看以下的 Demo:



Javascript EPUB Reader 的實作,原理就是將 EPUB 裡頭以XHTML、HTML單一檔案為單位,把整個 XHTML 弄成一個物件擺入指定的 DIV 裡頭,藉以顯示出來,就像用瀏覽器瀏覽 XHTML 檔案一樣。如此一來,只是透過 Javascript 去抽取該 XHTML 內的資料出來呈現。


至於翻頁的效果呢?假設要呈現的內容範圍是 640x480,以 ePub js 的原始碼看來,先產生一個 div-tmp ,動態把一個 XHTML 的資料,以 <p> 為單位地,慢慢地一個個加入到 div-tmp,並且動態地查看 div-tmp 的高度,若超過 480 時,則把前一個才加入的 <p> 內容,以空白切字,從後面慢慢地移出一個字出來,直到 div-tmp 的高度滿足 480 的限制,並且把移出來的內容另外建立一個新的 <p> 並擺在其後,以便下一頁的使用。而 rePublish 也是使用類似的概念,細節可以 rePublish - paginator.js 看到。


但是,以空白切字是有危險的,例如僅適用於英文字這種好切的語言,因此我嘗試使用 Monocle 發現他並沒有切字切不好的現象,再仔細一看,發現他的實作方式並非使用切字、填補的方式,並採用兩個 div 的處理機制。而後發現使採用 CSS Multi-column Layout Module (W3C Candidate Recommendation 17 December 2009)。


概念就是產生兩個 div ,一個是現在的這頁,另一個是下一頁用來顯示的,假設這兩頁是同一份的 XHTML 資料,且這個 XHTML 檔案不分頁顯示時,呈現共佔 640x800 大小,那第一頁就類似顯示 640x480,剩下的 640x(800-480) 之後的內容。然而,這樣還可能存在邊界關係,例如第一頁的最後一列,可能會整列因為視窗大小不夠顯示,而把整列的字都切了一半。實際測試,發現並沒這個問題,我用 Firebug 去觀察相關的 div style,整理一個小範例:


<html>
        <head>
                <title>Monocle Test</title>
                <style type="text/css">
                        #container
                        {   
                                width: 100%;
                                height: 100%;
                                position: relative;
                        }   
                        #show {
                                position: absolute;
                                top: 1em; bottom: 1em; left: 1em; right: 1em;
                                overflow: hidden;
                        }   
                        #content
                        {   
                                position: absolute;
                                top: 0pt; bottom: 0pt; min-width: 200%;
                                -moz-column-gap: 0pt; -moz-column-width: 1219px;
                        }   
                </style>
        </head>
        <body>
                <div id="container">
                        <div id="show">
                                <div id="content">
                                        <p>  詞曰:滾滾長江東逝水,浪花淘盡英雄。是非成敗轉頭空:青山仿舊在,幾度夕陽紅。白髮漁樵江渚上,慣看秋月春風。一壺
濁酒喜相逢:古今多少事,都付笑談中。</p>
                                        <p/>
                                        <p>  話說天下大勢,分久必合,合久必分:周末七國分爭,并入於秦。及秦滅之後,楚、漢分爭,又并入於漢。漢朝自高祖斬白蛇
而起義,一統天下。後來光武中興,傳至獻帝,遂分為三國。推其致亂之由,殆始於桓、靈二帝。桓帝禁錮善類,崇信宦官。及桓帝崩,靈帝即位,大將軍竇武、太傅陳蕃,共相>輔佐。時有宦官曹節等弄權,竇武、陳蕃謀誅之,作事不密,反為所害。中涓自此愈橫。</p>
                                        <p/>
                                        <p>  建寧二年四月望日,帝御溫德殿。方陞座,殿角狂風驟起,只見一條大青蛇,從梁上飛將下來,蟠於椅上。帝驚倒,左右急救
入宮,百官俱奔避。須臾,蛇不見了。忽然大雷大雨,加以冰雹,落到半夜方止,壞卻房屋無數。建寧四年二月,洛陽地震;又海水泛溢,沿海居民,盡被大浪捲入海中。光和元>年,雌雞化雄。六月朔,黑氣十餘丈,飛入溫德殿中。秋七月,有虹見於玉堂;五原山岸,盡皆崩裂。種種不祥,非止一端。</p>
            
                                </div>
                        </div>
                </div>
        </body>
</html>


可以使用 Firefox 瀏覽器瀏覽上述內容,並且試著把視窗的高度縮小,可以發現並不會造成最後一列字被切一半。原理就是使用 css 來處理。另外一提的,#content 裡的 -moz-column-width 是跟我的視窗大小有關,測試時要改一下囉。


而 Moncle 使用的技巧就是上面的東西,再加上一個 Display Screen 的移換,將上述的 CSS 更新:


<style type="text/css">
    #container
    {
        width: 100%;
        height: 100%;
        position: relative;
    }
    #show {
        position: absolute;
        top: 1em; bottom: 1em; left: 1em; right: 1em;
        overflow: hidden;
    }
    #content
    {
        position: absolute;
        top: 0pt; bottom: 0pt; min-width: 200%;
        -moz-column-gap: 0pt; -moz-column-width: 320px;
    }
</style>


呈現的樣貌:


CSS Pagination


因此關於切換頁面的部份,就只是移換要顯示的框框位置,上例就是左邊為第一頁,右邊是第二頁


1 則留言:

  1. 第三页无法显示,请问如何显示第三页?
    在第二页点击“next”没有反应

    回覆刪除