动手写一个电子阅读器(js基础版 )

还记得曾经秉烛夜读,抱着手机览过一部又一部小说时的情形。我们用过多少种电子阅读器,而你又钟情于哪一款呐?而如今作为程序员,是不是应该用一款自己做出来的阅读器去浏览小说呐?这定然是必须的。这一次,让我们动手写一个自己的电子阅读器吧。

我们用canvas来绘制电子屏。主要完成了以下几个功能
1.绘制下一页
2.绘制上一页
简单吧,就这俩功能,代码已上传github,大家可以下载试试看效果。

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

运行效果图

下面还是要对整体思路来个介绍的:
1.我们把整个canvas看成一屏,并且把这个屏划分成一个网格,以一个中文字符所占宽来分列,以占高来分行。还有一种情况,当一个字符的Unicode编码小于128时,它只占中文字符一半的宽度,高度不变。这时,可以得知一行最多可以放置2倍的文字。

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

2.把电子书的内容分段,以换行来划分,然后一段一段绘制。
首先为每一页设置两个变量来表示页首跟页尾。这样,后面绘制时,从页尾开始向后绘制,从页头开始向前绘制。

/*本页开始*/
var page_begin = {
    line: 0,//当前行
    offset: 0//当前偏移量
};
/*本页结束*/
var page_end = {
    line: 0,//当前行
    offset: 0//当前偏移量
}

3.绘制下一页,从页尾开始,取出一段文字,逐个检查字符的Unicode编,当一行绘满,开始下一行绘制,同时要检测是否行占满,占满标示此页绘制完成。

/*开始真实绘制下一屏*/
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 ++ ){
            //逐个检查
            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 ++;
    }
    /*未正常跳出,表示到达书尾,直接绘制*/
    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 ++ ){
            //逐个检查
            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))
        }
        
        /*此行为空行,也单独占一行*/
        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);
            }
            
            /*重置页尾数据*/
            page_end.line = page_begin.line;
            page_end.offset = page_begin.offset;
            /*重置页头数据*/
            page_begin.line = line;
            page_begin.offset = str.length - offset;
            break   
        }

        tmp_all_write = tmp_write.concat(tmp_all_write);

        line --;
    }
}

其实这个向前翻页的功能是多余的,可以在向后翻页的时候把当前页的信息记录下来,这样就不需要翻上一页还要计算那么多东西了。

结语:到目前为止只能算是写了个电子阅读器的demo,完成上一页下一页操作。后面需要做的还很多,比如:美化,翻页效果,文本目录结构,利用html5直接从本地读文件等等。有兴趣的在此基础上加上你想要的效果,如果你有好的作品,记得@我一观呦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,242评论 5 461
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,138评论 2 372
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,412评论 0 323
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,380评论 1 266
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,221评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,203评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,607评论 3 384
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,292评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,581评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,650评论 2 311
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,405评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,268评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,646评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,942评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,226评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,601评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,795评论 2 335

推荐阅读更多精彩内容