From 594ff954b13a90d5730a4a83eb9f2b5e70471c65 Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Fri, 15 Feb 2019 19:03:05 +0700 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Reader/TextPage/DrawHelper.js | 118 ++++++++++ .../components/Reader/TextPage/TextPage.vue | 205 ++++-------------- 2 files changed, 165 insertions(+), 158 deletions(-) diff --git a/client/components/Reader/TextPage/DrawHelper.js b/client/components/Reader/TextPage/DrawHelper.js index 75030bb8..4a9e1520 100644 --- a/client/components/Reader/TextPage/DrawHelper.js +++ b/client/components/Reader/TextPage/DrawHelper.js @@ -3,6 +3,124 @@ export default class DrawHelper { return `${size}px ${this.fontName}`; } + fontByStyle(style) { + return `${style.italic ? 'italic' : this.fontStyle} ${style.bold ? 'bold' : this.fontWeight} ${this.fontSize}px ${this.fontName}`; + } + + measureText(text, style) {// eslint-disable-line no-unused-vars + this.context.font = this.fontByStyle(style); + return this.context.measureText(text).width; + } + + measureTextFont(text, font) {// eslint-disable-line no-unused-vars + this.context.font = font; + return this.context.measureText(text).width; + } + + drawPage(lines) { + if (!this.lastBook || this.pageLineCount < 1 || !this.book || !lines || !this.parsed.textLength) + return ''; + + const spaceWidth = this.measureText(' ', {}); + + let out = `
`; + + let len = lines.length; + len = (len > this.pageLineCount + 1 ? this.pageLineCount + 1 : len); + + let y = this.fontSize*this.textShift; + + for (let i = 0; i < len; i++) { + const line = lines[i]; + /* line: + { + begin: Number, + end: Number, + first: Boolean, + last: Boolean, + parts: array of { + style: {bold: Boolean, italic: Boolean, center: Boolean} + text: String, + } + }*/ + + let indent = line.first ? this.p : 0; + + let lineText = ''; + let center = false; + let centerStyle = {}; + for (const part of line.parts) { + lineText += part.text; + center = center || part.style.center; + if (part.style.center) + centerStyle = part.style; + } + + let filled = false; + // если выравнивание по ширине включено + if (this.textAlignJustify && !line.last && !center) { + const words = lineText.split(' '); + + if (words.length > 1) { + const spaceCount = words.length - 1; + + const space = (this.w - line.width + spaceWidth*spaceCount)/spaceCount; + + let x = indent; + for (const part of line.parts) { + const font = this.fontByStyle(part.style); + let partWords = part.text.split(' '); + + for (let j = 0; j < partWords.length; j++) { + let f = font; + let style = part.style; + let word = partWords[j]; + if (i == 0 && this.searching && word.toLowerCase().indexOf(this.needle) >= 0) { + style = Object.assign({}, part.style, {bold: true}); + f = this.fontByStyle(style); + } + out += this.fillText(word, x, y, f); + x += this.measureText(word, style) + (j < partWords.length - 1 ? space : 0); + } + } + filled = true; + } + } + + // просто выводим текст + if (!filled) { + let x = indent; + x = (center ? (this.w - this.measureText(lineText, centerStyle))/2 : x); + for (const part of line.parts) { + let font = this.fontByStyle(part.style); + + if (i == 0 && this.searching) {//для поиска, разбивка по словам + let partWords = part.text.split(' '); + for (let j = 0; j < partWords.length; j++) { + let f = font; + let style = part.style; + let word = partWords[j]; + if (word.toLowerCase().indexOf(this.needle) >= 0) { + style = Object.assign({}, part.style, {bold: true}); + f = this.fontByStyle(style); + } + out += this.fillText(word, x, y, f); + x += this.measureText(word, style) + (j < partWords.length - 1 ? spaceWidth : 0); + } + } else { + out += this.fillText(part.text, x, y, font); + x += this.measureText(part.text, part.style); + } + } + } + y += this.lineHeight; + } + + out += '
'; + return out; + } + drawPercentBar(x, y, w, h, font, fontSize, bookPos, textLength) { const pad = 3; const fh = h - 2*pad; diff --git a/client/components/Reader/TextPage/TextPage.vue b/client/components/Reader/TextPage/TextPage.vue index b793222e..1b1b6a04 100644 --- a/client/components/Reader/TextPage/TextPage.vue +++ b/client/components/Reader/TextPage/TextPage.vue @@ -112,9 +112,9 @@ class TextPage extends Vue { this.toggleLayout = !this.toggleLayout; if (this.toggleLayout) - this.page1 = this.drawPage(lines); + this.page1 = this.drawHelper.drawPage(lines); else - this.page2 = this.drawPage(lines); + this.page2 = this.drawHelper.drawPage(lines); this.doPageTransition(); }, 10); @@ -148,28 +148,7 @@ class TextPage extends Vue { this.lineHeight = this.fontSize + this.lineInterval; this.pageLineCount = 1 + Math.floor((this.h - this.fontSize)/this.lineHeight); - if (this.parsed) { - this.parsed.p = this.p; - this.parsed.w = this.w;// px, ширина текста - this.parsed.font = this.font; - this.parsed.wordWrap = this.wordWrap; - let t = ''; - while (this.measureText(t, {}) < this.w) t += 'Щ'; - this.parsed.maxWordLength = t.length - 1; - this.parsed.measureText = this.measureText; - } - - //сообщение "Загрузка шрифтов..." - const flText = 'Загрузка шрифта...'; - this.$refs.fontsLoading.innerHTML = flText; - const fontsLoadingStyle = this.$refs.fontsLoading.style; - fontsLoadingStyle.position = 'absolute'; - fontsLoadingStyle.fontSize = this.fontSize + 'px'; - fontsLoadingStyle.top = (this.realHeight/2 - 2*this.fontSize) + 'px'; - fontsLoadingStyle.left = (this.realWidth - this.measureText(flText, {}))/2 + 'px'; - //stuff - this.statusBarColor = this.hex2rgba(this.textColor || '#000000', this.statusBarColorAlpha); this.currentTransition = ''; this.pageChangeDirectionDown = true; this.fontShift = this.fontVertShift/100; @@ -178,17 +157,52 @@ class TextPage extends Vue { //drawHelper this.drawHelper.realWidth = this.realWidth; this.drawHelper.realHeight = this.realHeight; + this.drawHelper.lastBook = this.lastBook; + this.drawHelper.book = this.book; + this.drawHelper.parsed = this.parsed; + this.drawHelper.pageLineCount = this.pageLineCount; this.drawHelper.backgroundColor = this.backgroundColor; this.drawHelper.statusBarColor = this.statusBarColor; + this.drawHelper.fontStyle = this.fontStyle; + this.drawHelper.fontWeight = this.fontWeight; + this.drawHelper.fontSize = this.fontSize; this.drawHelper.fontName = this.fontName; this.drawHelper.fontShift = this.fontShift; - this.drawHelper.measureText = this.measureText; - this.drawHelper.measureTextFont = this.measureTextFont; + this.drawHelper.textColor = this.textColor; + this.drawHelper.textShift = this.textShift; + this.drawHelper.p = this.p; + this.drawHelper.w = this.w; + this.drawHelper.textAlignJustify = this.textAlignJustify; + this.drawHelper.lineHeight = this.lineHeight; + this.drawHelper.context = this.context; + //сообщение "Загрузка шрифтов..." + const flText = 'Загрузка шрифта...'; + this.$refs.fontsLoading.innerHTML = flText; + const fontsLoadingStyle = this.$refs.fontsLoading.style; + fontsLoadingStyle.position = 'absolute'; + fontsLoadingStyle.fontSize = this.fontSize + 'px'; + fontsLoadingStyle.top = (this.realHeight/2 - 2*this.fontSize) + 'px'; + fontsLoadingStyle.left = (this.realWidth - this.drawHelper.measureText(flText, {}))/2 + 'px'; + + //parsed + if (this.parsed) { + this.parsed.p = this.p; + this.parsed.w = this.w;// px, ширина текста + this.parsed.font = this.font; + this.parsed.wordWrap = this.wordWrap; + let t = ''; + while (this.drawHelper.measureText(t, {}) < this.w) t += 'Щ'; + this.parsed.maxWordLength = t.length - 1; + this.parsed.measureText = this.drawHelper.measureText.bind(this.drawHelper); + } + + //statusBar this.$refs.statusBar.style.left = '0px'; this.$refs.statusBar.style.top = (this.statusBarTop ? 1 : this.realHeight - this.statusBarHeight) + 'px'; + this.statusBarColor = this.hex2rgba(this.textColor || '#000000', this.statusBarColorAlpha); this.statusBarClickable = this.drawHelper.statusBarClickable(this.statusBarTop, this.statusBarHeight); //scrolling page @@ -208,16 +222,6 @@ class TextPage extends Vue { page2.style.left = this.indentLR + 'px'; } - measureText(text, style) {// eslint-disable-line no-unused-vars - this.context.font = this.fontByStyle(style); - return this.context.measureText(text).width; - } - - measureTextFont(text, font) {// eslint-disable-line no-unused-vars - this.context.font = font; - return this.context.measureText(text).width; - } - async checkLoadedFonts() { let loaded = await Promise.all(this.fontList.map(font => document.fonts.check(font))); if (loaded.some(r => !r)) { @@ -323,7 +327,6 @@ class TextPage extends Vue { this.linesUp = null; this.linesDown = null; - this.searching = false; this.statusBarMessage = ''; @@ -407,31 +410,27 @@ class TextPage extends Vue { return `${this.fontStyle} ${this.fontWeight} ${this.fontSize}px ${this.fontName}`; } - fontByStyle(style) { - return `${style.italic ? 'italic' : this.fontStyle} ${style.bold ? 'bold' : this.fontWeight} ${this.fontSize}px ${this.fontName}`; - } - onScrollingTransitionEnd() { if (this.resolveTransitionFinish) this.resolveTransitionFinish(); } startSearch(needle) { - this.needle = ''; + this.drawHelper.needle = ''; const words = needle.split(' '); for (const word of words) { if (word != '') { - this.needle = word; + this.drawHelper.needle = word; break; } } - this.searching = true; + this.drawHelper.searching = true; this.draw(); } stopSearch() { - this.searching = false; + this.drawHelper.searching = false; this.draw(); } @@ -508,7 +507,7 @@ class TextPage extends Vue { const lines = this.getLines(this.bookPos); this.linesDown = lines.linesDown; this.linesUp = lines.linesUp; - this.page1 = this.drawPage(lines.linesDown); + this.page1 = this.drawHelper.drawPage(lines.linesDown); } //caching next @@ -518,7 +517,7 @@ class TextPage extends Vue { if (this.linesDown && this.linesDown.length > this.pageLineCount && this.pageLineCount > 0) { this.cachedPos = this.linesDown[1].begin; this.linesCached = this.getLines(this.cachedPos); - this.pageCached = this.drawPage(this.linesCached.linesDown); + this.pageCached = this.drawHelper.drawPage(this.linesCached.linesDown); } this.cachedPageTimer = null; }, 20); @@ -549,12 +548,6 @@ class TextPage extends Vue { const lines = this.getLines(this.bookPos); this.linesDown = lines.linesDown; this.linesUp = lines.linesUp; - - /*if (this.toggleLayout) - this.page1 = this.drawPage(lines.linesDown); - else - this.page2 = this.drawPage(lines.linesDown);*/ - this.debouncedUpdatePage(lines.linesDown); } @@ -590,110 +583,6 @@ class TextPage extends Vue { }; } - drawPage(lines) { - if (!this.lastBook || this.pageLineCount < 1 || !this.book || !lines || !this.parsed.textLength) - return ''; - - const spaceWidth = this.measureText(' ', {}); - - let out = `
`; - - let len = lines.length; - len = (len > this.pageLineCount + 1 ? this.pageLineCount + 1 : len); - - let y = this.fontSize*this.textShift; - - for (let i = 0; i < len; i++) { - const line = lines[i]; - /* line: - { - begin: Number, - end: Number, - first: Boolean, - last: Boolean, - parts: array of { - style: {bold: Boolean, italic: Boolean, center: Boolean} - text: String, - } - }*/ - - let indent = line.first ? this.p : 0; - - let lineText = ''; - let center = false; - let centerStyle = {}; - for (const part of line.parts) { - lineText += part.text; - center = center || part.style.center; - if (part.style.center) - centerStyle = part.style; - } - - let filled = false; - // если выравнивание по ширине включено - if (this.textAlignJustify && !line.last && !center) { - const words = lineText.split(' '); - - if (words.length > 1) { - const spaceCount = words.length - 1; - - const space = (this.w - line.width + spaceWidth*spaceCount)/spaceCount; - - let x = indent; - for (const part of line.parts) { - const font = this.fontByStyle(part.style); - let partWords = part.text.split(' '); - - for (let j = 0; j < partWords.length; j++) { - let f = font; - let style = part.style; - let word = partWords[j]; - if (i == 0 && this.searching && word.toLowerCase().indexOf(this.needle) >= 0) { - style = Object.assign({}, part.style, {bold: true}); - f = this.fontByStyle(style); - } - out += this.drawHelper.fillText(word, x, y, f); - x += this.measureText(word, style) + (j < partWords.length - 1 ? space : 0); - } - } - filled = true; - } - } - - // просто выводим текст - if (!filled) { - let x = indent; - x = (center ? (this.w - this.measureText(lineText, centerStyle))/2 : x); - for (const part of line.parts) { - let font = this.fontByStyle(part.style); - - if (i == 0 && this.searching) {//для поиска, разбивка по словам - let partWords = part.text.split(' '); - for (let j = 0; j < partWords.length; j++) { - let f = font; - let style = part.style; - let word = partWords[j]; - if (word.toLowerCase().indexOf(this.needle) >= 0) { - style = Object.assign({}, part.style, {bold: true}); - f = this.fontByStyle(style); - } - out += this.drawHelper.fillText(word, x, y, f); - x += this.measureText(word, style) + (j < partWords.length - 1 ? spaceWidth : 0); - } - } else { - out += this.drawHelper.fillText(part.text, x, y, font); - x += this.measureText(part.text, part.style); - } - } - } - y += this.lineHeight; - } - - out += '
'; - return out; - } - drawStatusBar(message) { if (this.w < minLayoutWidth) { this.statusBar = null; @@ -790,9 +679,9 @@ class TextPage extends Vue { this.linesUpNext = lines.linesUp; if (this.toggleLayout) - this.page2 = this.drawPage(lines.linesDown);//наоборот + this.page2 = this.drawHelper.drawPage(lines.linesDown);//наоборот else - this.page1 = this.drawPage(lines.linesDown); + this.page1 = this.drawHelper.drawPage(lines.linesDown); this.pagePrepared = true; }