動(dòng)手寫一個(gè)電子閱讀器(js基礎(chǔ)版 )

還記得曾經(jīng)秉燭夜讀嫌佑,抱著手機(jī)覽過一部又一部小說時(shí)的情形亥啦。我們用過多少種電子閱讀器缰揪,而你又鐘情于哪一款吶索抓?而如今作為程序員家肯,是不是應(yīng)該用一款自己做出來的閱讀器去瀏覽小說吶闷尿?這定然是必須的萎战。這一次媳否,讓我們動(dòng)手寫一個(gè)自己的電子閱讀器吧特恬。

我們用canvas來繪制電子屏执俩。主要完成了以下幾個(gè)功能
1.繪制下一頁
2.繪制上一頁
簡單吧,就這倆功能癌刽,代碼已上傳github役首,大家可以下載試試看效果。

github地址:https://github.com/lzuntalented/lzTxt-js

運(yùn)行效果圖

下面還是要對整體思路來個(gè)介紹的:
1.我們把整個(gè)canvas看成一屏显拜,并且把這個(gè)屏劃分成一個(gè)網(wǎng)格衡奥,以一個(gè)中文字符所占寬來分列,以占高來分行远荠。還有一種情況矮固,當(dāng)一個(gè)字符的Unicode編碼小于128時(shí),它只占中文字符一半的寬度譬淳,高度不變档址。這時(shí),可以得知一行最多可以放置2倍的文字邻梆。

var len_char = 1;
if(str.charCodeAt(i) > 128){//檢查字符的Unicode編
    len_char = 2;
}

2.把電子書的內(nèi)容分段守伸,以換行來劃分,然后一段一段繪制浦妄。
首先為每一頁設(shè)置兩個(gè)變量來表示頁首跟頁尾尼摹。這樣,后面繪制時(shí)剂娄,從頁尾開始向后繪制蠢涝,從頁頭開始向前繪制。

/*本頁開始*/
var page_begin = {
    line: 0,//當(dāng)前行
    offset: 0//當(dāng)前偏移量
};
/*本頁結(jié)束*/
var page_end = {
    line: 0,//當(dāng)前行
    offset: 0//當(dāng)前偏移量
}

3.繪制下一頁阅懦,從頁尾開始和二,取出一段文字,逐個(gè)檢查字符的Unicode編故黑,當(dāng)一行繪滿儿咱,開始下一行繪制庭砍,同時(shí)要檢測是否行占滿场晶,占滿標(biāo)示此頁繪制完成混埠。

/*開始真實(shí)繪制下一屏*/
function check(current){
    ctx.clearRect(0,0,canvas.width,canvas.height);
    
    var total = panel.col * panel.row * 2;//字符有占一位和兩位的,一行最多可繪制2倍長度
    var count = 0;
    var tag = false;

    var tmp_all_write = [];
    var isBreak = false;//檢查是否正常跳出
    while(current < str_write_list.length){
        
        var len = str_write_list[current].length;
        var tmp_write = [];
        var str = str_write_list[current];
        var start = 0;
        if(!tag){
            start = page_end.offset;
            tag = true;
        }
        
        var tmp = 0;
        var begin = start;
        for(var i = start; i < len ; i ++ ){
            //逐個(gè)檢查
            if(tmp >= panel.col * 2 - 1){
                tmp_write.push(str.substring(begin,i));
                begin = i;
                tmp = 0;
            }
            
            var len_char = 1;
            if(str.charCodeAt(i) > 128){
                len_char = 2;
            }
            
            tmp += len_char;
        }
        
        if(tmp > 0){
            tmp_write.push(str.substring(begin,i))
        }
        
        if(str == "") {
            tmp_write.push("");
        };
        
        var offset = 0;
        if(tmp_all_write.length + tmp_write.length > panel.row) {
            for(var i = 0 ; i < tmp_all_write.length ; i ++){
                ctx.fillText(tmp_all_write[i],0, (i + 1) * font.size);
            }
            
            for(var j = 0 ; j < tmp_write.length && j + i < panel.row ; j ++){
                offset += tmp_write[j].length;
                ctx.fillText(tmp_write[j],0, (i + j + 1) * font.size);
            }
            page_end.line = current;
            page_end.offset = offset;
            isBreak = true;
            break   ;
        }

        tmp_all_write = tmp_all_write.concat(tmp_write);

        current ++;
    }
    /*未正常跳出诗轻,表示到達(dá)書尾钳宪,直接繪制*/
    if(!isBreak){
        for(var i = 0 ; i < tmp_all_write.length ; i ++){
            ctx.fillText(tmp_all_write[i],0, (i + 1) * font.size);
        }
    }
    
}

3.繪制上一頁,從頁頭開始扳炬,倒著取出一段文字吏颖,繪制一行,檢測行占滿恨樟。

/*上一頁*/
function write_before(){
    var tag = false;
    var total = panel.col * panel.row * 2;
    var count = 0;
    var line = page_begin.offset > 0 ? page_begin.line : page_begin.line - 1 ;
    var t = 0;
    var tmp_all_write = [];
    while(line >= 0){
        
        var len = str_write_list[line].length;
        var tmp_write = [];
        var str = str_write_list[line];
        var start = len;
        if(!tag){
            if(page_begin.offset > 0 ){
                start = page_begin.offset
            }

            tag = true;
        }
        
        var tmp = 0;
        var begin = 0;
        for(var i = 0; i < start ; i ++ ){
            //逐個(gè)檢查
            if(tmp >= panel.col * 2  - 1){
                tmp_write.push(str.substring(i,begin));
                begin = i;
                tmp = 0;
            }
            
            var len_char = 1;
            if(str.charCodeAt(i) > 128){
                len_char = 2;
            }
            
            tmp += len_char;
        }
        
        if(tmp > 0){
            tmp_write.push(str.substring(begin,i))
        }
        
        /*此行為空行半醉,也單獨(dú)占一行*/
        if(str == "") {
            tmp_write.push("");
        };
        
        var offset = 0;
        if(tmp_all_write.length + tmp_write.length >= panel.row) {
            ctx.clearRect(0,0,canvas.width,canvas.height);
            var y = panel.row;
            
            for(var i = tmp_all_write.length - 1 ; i >= 0  ; i --){
                ctx.fillText(tmp_all_write[i],0, (y--) * font.size);
            }
            i = tmp_all_write.length;
//                      
            var k = 0;
            for(var j = tmp_write.length - 1 ; j >= 0 && (k + i) < panel.row ; j --){
                offset += tmp_write[j].length;
                k++;
                ctx.fillText(tmp_write[j],0, (y--) * font.size);
            }
            
            /*重置頁尾數(shù)據(jù)*/
            page_end.line = page_begin.line;
            page_end.offset = page_begin.offset;
            /*重置頁頭數(shù)據(jù)*/
            page_begin.line = line;
            page_begin.offset = str.length - offset;
            break   
        }

        tmp_all_write = tmp_write.concat(tmp_all_write);

        line --;
    }
}

其實(shí)這個(gè)向前翻頁的功能是多余的,可以在向后翻頁的時(shí)候把當(dāng)前頁的信息記錄下來劝术,這樣就不需要翻上一頁還要計(jì)算那么多東西了缩多。

結(jié)語:到目前為止只能算是寫了個(gè)電子閱讀器的demo,完成上一頁下一頁操作养晋。后面需要做的還很多衬吆,比如:美化,翻頁效果绳泉,文本目錄結(jié)構(gòu)逊抡,利用html5直接從本地讀文件等等。有興趣的在此基礎(chǔ)上加上你想要的效果零酪,如果你有好的作品冒嫡,記得@我一觀呦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末四苇,一起剝皮案震驚了整個(gè)濱河市灯谣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蛔琅,老刑警劉巖胎许,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異罗售,居然都是意外死亡辜窑,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門寨躁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穆碎,“玉大人,你說我怎么就攤上這事职恳∷鳎” “怎么了方面?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長色徘。 經(jīng)常有香客問我恭金,道長,這世上最難降的妖魔是什么褂策? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任横腿,我火速辦了婚禮,結(jié)果婚禮上斤寂,老公的妹妹穿的比我還像新娘耿焊。我一直安慰自己,他們只是感情好遍搞,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布罗侯。 她就那樣靜靜地躺著,像睡著了一般溪猿。 火紅的嫁衣襯著肌膚如雪钩杰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天再愈,我揣著相機(jī)與錄音榜苫,去河邊找鬼。 笑死翎冲,一個(gè)胖子當(dāng)著我的面吹牛垂睬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抗悍,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼驹饺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了缴渊?” 一聲冷哼從身側(cè)響起赏壹,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衔沼,沒想到半個(gè)月后蝌借,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡指蚁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年菩佑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凝化。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稍坯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出搓劫,到底是詐尸還是另有隱情瞧哟,我是刑警寧澤混巧,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站勤揩,受9級特大地震影響咧党,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜雄可,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一凿傅、第九天 我趴在偏房一處隱蔽的房頂上張望缠犀。 院中可真熱鬧数苫,春花似錦、人聲如沸辨液。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滔迈。三九已至止吁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間燎悍,已是汗流浹背敬惦。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谈山,地道東北人俄删。 一個(gè)月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像奏路,于是被迫代替她去往敵國和親畴椰。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,332評論 25 707
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協(xié)議鸽粉。它實(shí)...
    香橙柚子閱讀 23,921評論 8 183
  • 1 我一懶媽触机,自己的娃兒都不想帶帚戳,放去午托班,反正有老師輔導(dǎo)作業(yè)儡首,有阿姨做飯片任,給我省出來不少時(shí)間。 可要花錢啊椒舵,在...
    妮娜讀書閱讀 457評論 0 4
  • 人人都有手機(jī)蚂踊,因此,也就等于人人手上都有了相機(jī)笔宿。因此人人都有了成為攝影師的硬件設(shè)備犁钟。 大多數(shù)人覺得煩惱的是棱诱,為什么...
    瑞田學(xué)習(xí)力閱讀 537評論 0 3
  • 我相信每一個(gè)人,都有很多的好朋友涝动。但是迈勋,我有一個(gè)最好的朋友。她的名字叫:季恬宇醋粟。 季恬宇是一個(gè)...
    Monica莫閱讀 403評論 3 1