Browse Source

Работа над парсером, промежуточный коммит

Book Pauk 6 years ago
parent
commit
cd2d429012

+ 45 - 5
client/components/Reader/TextPage/TextPage.vue

@@ -1,7 +1,8 @@
 <template>
     <div ref="main" class="main">
-        <pre>{{ bookPos }}</pre>
-        <pre>{{ meta }}</pre>
+        <p v-for="item in items" :key="item.id">
+            {{ item.text }}
+        </p>        
     </div>
 </template>
 
@@ -23,9 +24,9 @@ export default @Component({
 })
 class TextPage extends Vue {
     lastBook = null;
-    meta = null;
-    fb2 = null;
-    bookPos = 0;    
+    bookPos = 0;
+
+    items = null;
 
     created() {
         this.commit = this.$store.commit;
@@ -39,6 +40,7 @@ class TextPage extends Vue {
         this.book = null;
         this.meta = null;
         this.fb2 = null;
+        this.parsed = null;
 
         this.drawPage();//пока не загрузили, очистим канвас
 
@@ -60,6 +62,17 @@ class TextPage extends Vue {
                     this.fb2.bookTitle
                 ]).join(' '));
 
+                const parsed = this.book.parsed;
+                parsed.p = 30;//px, отступ параграфа
+                parsed.w = 300;//px, ширина страницы
+                parsed.measureText = (text, style) => {
+                    if (style == 'bold')
+                        return text.length*12;
+                    else
+                        return text.length*10;
+                };                
+
+                this.parsed = parsed;
                 this.drawPage();
             })();
         }
@@ -70,11 +83,33 @@ class TextPage extends Vue {
             return;
 
         //пустой канвас
+        this.items = [];
 
         if (!this.book)
             return;
 
+        const lines = this.parsed.getLines(this.bookPos, 30);
+
+        let newItems = [];
+        for (const line of lines) {
+            /* line:
+            {
+                begin: Number,
+                end: Number,
+                parts: array of {
+                    style: 'bold'|'italic',
+                    text: String,
+                }
+            }*/
+
+            const item = {text: '', id: line.begin};
+            for (const part of line.parts) {
+                item.text += part.text;
+            }
+            newItems.push(item);
+        }
 
+        this.items = newItems;
     }
 
     keyHook(event) {
@@ -88,4 +123,9 @@ class TextPage extends Vue {
     display: flex;
     flex-direction: column;
 }
+
+p {
+    margin: 0;
+    padding: 0;
+}
 </style>

+ 150 - 1
client/components/Reader/share/BookParser.js

@@ -4,6 +4,19 @@ import {sleep} from '../../../share/utils';
 export default class BookParser {
     constructor() {
         this.parser = new EasySAXParser();
+
+        // defaults
+        this.p = 30;// px, отступ параграфа
+        this.w = 300;// px, ширина страницы
+        this.textAlignJustify = false;// выравнивание по ширине
+        this.wordWrap = false;// перенос по слогам, если textAlignJustify = true
+
+        // заглушка
+        this.measureText = (text, style) => {// eslint-disable-line no-unused-vars
+            return text.length*10;
+        };
+
+        // stuff
     }
 
     async parse(data, callback) {
@@ -177,7 +190,7 @@ export default class BookParser {
 
         await parser.parse(data);
 
-        this.meta = fb2;
+        this.fb2 = fb2;
         this.para = para;
 
         callback(100);
@@ -185,4 +198,140 @@ export default class BookParser {
 
         return {fb2};
     }
+
+    findParaIndex(bookPos) {
+        let result = undefined;
+ 
+        //дихотомия
+        let first = 0;
+        let last = this.para.length - 1;
+        while (first < last) {
+            let mid = first + Math.floor((last - first)/2);
+            if (bookPos >= this.para[mid].offset)
+                last = mid;
+            else
+                first = mid + 1;
+        }
+
+        if (last >= 0) {
+            const ofs = this.para[last].offset;
+            if (bookPos >= ofs && bookPos < ofs + this.para[last].length)
+                result = last; 
+        }
+
+        return result;
+    }
+
+    parsePara(paraIndex) {
+        const para = this.para[paraIndex];
+
+        if (para.parsed && 
+            para.parsed.w === this.w &&
+            para.parsed.p === this.p &&
+            para.parsed.textAlignJustify === this.textAlignJustify &&
+            para.parsed.wordWrap === this.wordWrap)
+            return para.parsed;
+
+        const parsed = {
+            w: this.w,
+            p: this.p,
+            textAlignJustify: this.textAlignJustify,
+            wordWrap: this.wordWrap
+        };
+
+        const lines = [];
+        /* array of
+        {
+            begin: Number,
+            end: Number,
+            parts: array of {
+                style: 'bold'|'italic',
+                text: String,
+            }
+        }*/
+        
+        //
+
+        parsed.lines = lines;
+        para.parsed = parsed;
+
+        return parsed;
+    }
+
+    findLineIndex(bookPos, lines) {
+        let result = undefined;
+
+        //дихотомия
+        let first = 0;
+        let last = lines.length - 1;
+        while (first < last) {
+            let mid = first + Math.floor((last - first)/2);
+            if (bookPos >= lines[mid].begin)
+                last = mid;
+            else
+                first = mid + 1;
+        }
+
+        if (last >= 0) {
+            if (bookPos >= lines[last].begin && bookPos <= lines[last].end)
+                result = last; 
+        }
+
+        return result;
+    }
+
+    getLines(bookPos, n) {
+        const result = [];
+        let paraIndex = this.findParaIndex(bookPos);
+
+        if (paraIndex === undefined)
+            return result;
+        
+        if (n > 0) {
+            let parsed = this.parsePara(paraIndex);
+            let i = this.findLineIndex(bookPos, parsed.lines);
+            if (i === undefined)
+                return result;
+
+            while (n > 0) {
+                result.push(parsed.lines[i]);
+                i++;
+
+                if (i >= parsed.lines.length) {
+                    paraIndex++;
+                    if (paraIndex < this.para.length)
+                        parsed = this.parsePara(paraIndex);
+                    else
+                        return result;
+                    i = 0;
+                }
+
+                n--;
+            }
+        } else if (n < 0) {
+            n = -n;
+            let parsed = this.parsePara(paraIndex);
+            let i = this.findLineIndex(bookPos, parsed.lines);
+            if (i === undefined)
+                return result;
+
+            while (n > 0) {
+                result.push(parsed.lines[i]);
+                i--;
+
+                if (i > 0) {
+                    paraIndex--;
+                    if (paraIndex >= this.para.length)
+                        parsed = this.parsePara(paraIndex);
+                    else
+                        return result;
+                    i = parsed.lines.length - 1;
+                }
+                
+                n--;
+            }
+        }
+
+        return result;
+    }
 }