diff --git a/client/components/Reader/TextPage/TextPage.vue b/client/components/Reader/TextPage/TextPage.vue index 78ebf8a9..6274e01d 100644 --- a/client/components/Reader/TextPage/TextPage.vue +++ b/client/components/Reader/TextPage/TextPage.vue @@ -1,7 +1,8 @@ @@ -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; +} \ No newline at end of file diff --git a/client/components/Reader/share/BookParser.js b/client/components/Reader/share/BookParser.js index 2cf6253a..bb1fc59a 100644 --- a/client/components/Reader/share/BookParser.js +++ b/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; + } } \ No newline at end of file