diff --git a/client/components/Reader/TextPage/TextPage.vue b/client/components/Reader/TextPage/TextPage.vue index 1f5cba06..32dd8d4b 100644 --- a/client/components/Reader/TextPage/TextPage.vue +++ b/client/components/Reader/TextPage/TextPage.vue @@ -228,28 +228,31 @@ class TextPage extends Vue { //parsed if (this.parsed) { - this.parsed.p = this.p; - this.parsed.w = this.w;// px, ширина текста - this.parsed.font = this.font; - this.parsed.fontSize = this.fontSize; - this.parsed.wordWrap = this.wordWrap; - this.parsed.cutEmptyParagraphs = this.cutEmptyParagraphs; - this.parsed.addEmptyParagraphs = this.addEmptyParagraphs; - let t = wideLetter; - if (!this.drawHelper.measureText(t, {})) - throw new Error('Ошибка measureText'); - while (this.drawHelper.measureText(t, {}) < this.w) t += wideLetter; - this.parsed.maxWordLength = t.length - 1; - this.parsed.measureText = this.drawHelper.measureText.bind(this.drawHelper); - this.parsed.lineHeight = this.lineHeight; - this.parsed.showImages = this.showImages; - this.parsed.showInlineImagesInCenter = this.showInlineImagesInCenter; - this.parsed.imageHeightLines = this.imageHeightLines; - this.parsed.imageFitWidth = this.imageFitWidth; - this.parsed.compactTextPerc = this.compactTextPerc; + this.testText = 'Это тестовый текст. Его ширина выдается системой неправильно некоторое время.'; - this.parsed.testText = 'Это тестовый текст. Его ширина выдается системой неверно некоторое время.'; - this.parsed.testWidth = this.drawHelper.measureText(this.parsed.testText, {}); + let wideLine = wideLetter; + if (!this.drawHelper.measureText(wideLine, {})) + throw new Error('Ошибка measureText'); + while (this.drawHelper.measureText(wideLine, {}) < this.w) wideLine += wideLetter; + + this.parsed.setSettings({ + p: this.p, + w: this.w, + font: this.font, + fontSize: this.fontSize, + wordWrap: this.wordWrap, + cutEmptyParagraphs: this.cutEmptyParagraphs, + addEmptyParagraphs: this.addEmptyParagraphs, + maxWordLength: wideLine.length - 1, + lineHeight: this.lineHeight, + showImages: this.showImages, + showInlineImagesInCenter: this.showInlineImagesInCenter, + imageHeightLines: this.imageHeightLines, + imageFitWidth: this.imageFitWidth, + compactTextPerc: this.compactTextPerc, + testWidth: this.drawHelper.measureText(this.testText, {}), + measureText: this.drawHelper.measureText.bind(this.drawHelper), + }); } //scrolling page @@ -333,19 +336,25 @@ class TextPage extends Vue { if (!omitLoadFonts) await this.loadFonts(); - this.draw(); - - // ширина шрифта некоторое время выдается неверно, поэтому - if (!omitLoadFonts) { + if (omitLoadFonts) { + this.draw(); + } else { + // ширина шрифта некоторое время выдается неверно, + // не получилось событийно отловить этот момент, поэтому костыль const parsed = this.parsed; let i = 0; - const t = this.parsed.testText; - while (i++ < 50 && this.parsed === parsed && this.drawHelper.measureText(t, {}) === this.parsed.testWidth) + const t = this.testText; + const tw = this.drawHelper.measureText(t, {}); + //5 секунд проверяем изменения шрифта + while (i++ < 50 && this.parsed === parsed && this.drawHelper.measureText(t, {}) === tw) { + if (i == 10) //через 1 сек + this.draw(); await utils.sleep(100); + } if (this.parsed === parsed) { - this.parsed.testWidth = this.drawHelper.measureText(t, {}); + this.parsed.setSettings({testWidth: this.drawHelper.measureText(t, {})}); this.draw(); } } diff --git a/client/components/Reader/share/BookParser.js b/client/components/Reader/share/BookParser.js index 500a64bc..aadb746f 100644 --- a/client/components/Reader/share/BookParser.js +++ b/client/components/Reader/share/BookParser.js @@ -4,23 +4,44 @@ import * as utils from '../../../share/utils'; const maxImageLineCount = 100; +// defaults +const defaultSettings = { + p: 30, //px, отступ параграфа + w: 500, //px, ширина страницы + + font: '', //css описание шрифта + fontSize: 20, //px, размер шрифта + wordWrap: false, //перенос по слогам + cutEmptyParagraphs: false, //убирать пустые параграфы + addEmptyParagraphs: 0, //добавлять n пустых параграфов перед непустым + maxWordLength: 500, //px, максимальная длина слова без пробелов + lineHeight: 26, //px, высота строки + showImages: true, //показыввать изображения + showInlineImagesInCenter: true, //выносить изображения в центр, работает на этапе первичного парсинга (parse) + imageHeightLines: 100, //кол-во строк, максимальная высота изображения + imageFitWidth: true, //ширина изображения не более ширины страницы + compactTextPerc: 0, //проценты, степень компактности текста + testWidth: 0, //ширина тестовой строки, пересчитывается извне при изменении шрифта браузером + + //заглушка, измеритель ширины текста + measureText: (text, style) => {// eslint-disable-line no-unused-vars + return text.length*20; + }, +}; + export default class BookParser { - constructor(settings) { - if (settings) { - this.showInlineImagesInCenter = settings.showInlineImagesInCenter; - } + constructor(settings = {}) { + this.sets = {}; - // defaults - this.p = 30;// px, отступ параграфа - this.w = 300;// px, ширина страницы - this.wordWrap = false;// перенос по слогам - - //заглушка - this.measureText = (text, style) => {// eslint-disable-line no-unused-vars - return text.length*20; - }; + this.setSettings(defaultSettings); + this.setSettings(settings); } + setSettings(settings = {}) { + this.sets = Object.assign({}, this.sets, settings); + this.measureText = this.sets.measureText; + } + async parse(data, callback) { if (!callback) callback = () => {}; @@ -210,14 +231,14 @@ export default class BookParser { if (href[0] == '#') {//local imageNum++; - if (inPara && !this.showInlineImagesInCenter && !center) + if (inPara && !this.sets.showInlineImagesInCenter && !center) growParagraph(``, 0); else newParagraph(`${' '.repeat(maxImageLineCount)}`, maxImageLineCount); this.images.push({paraIndex, num: imageNum, id, local, alt}); - if (inPara && this.showInlineImagesInCenter) + if (inPara && this.sets.showInlineImagesInCenter) newParagraph(' ', 1); } else {//external imageNum++; @@ -632,7 +653,7 @@ export default class BookParser { }); //длинные слова (или белиберду без пробелов) тоже разобьем - const maxWordLength = this.maxWordLength; + const maxWordLength = this.sets.maxWordLength; const parts = result; result = []; for (const part of parts) { @@ -712,37 +733,43 @@ export default class BookParser { parsePara(paraIndex) { const para = this.para[paraIndex]; + const s = this.sets; + //перераспарсиваем только при изменении одного из параметров if (!this.force && para.parsed && - para.parsed.testWidth === this.testWidth && - para.parsed.w === this.w && - para.parsed.p === this.p && - para.parsed.wordWrap === this.wordWrap && - para.parsed.maxWordLength === this.maxWordLength && - para.parsed.font === this.font && - para.parsed.cutEmptyParagraphs === this.cutEmptyParagraphs && - para.parsed.addEmptyParagraphs === this.addEmptyParagraphs && - para.parsed.showImages === this.showImages && - para.parsed.imageHeightLines === this.imageHeightLines && - para.parsed.imageFitWidth === this.imageFitWidth && - para.parsed.compactTextPerc === this.compactTextPerc + para.parsed.p === s.p && + para.parsed.w === s.w && + para.parsed.font === s.font && + para.parsed.fontSize === s.fontSize && + para.parsed.wordWrap === s.wordWrap && + para.parsed.cutEmptyParagraphs === s.cutEmptyParagraphs && + para.parsed.addEmptyParagraphs === s.addEmptyParagraphs && + para.parsed.maxWordLength === s.maxWordLength && + para.parsed.lineHeight === s.lineHeight && + para.parsed.showImages === s.showImages && + para.parsed.imageHeightLines === s.imageHeightLines && + para.parsed.imageFitWidth === s.imageFitWidth && + para.parsed.compactTextPerc === s.compactTextPerc && + para.parsed.testWidth === s.testWidth ) return para.parsed; const parsed = { - testWidth: this.testWidth, - w: this.w, - p: this.p, - wordWrap: this.wordWrap, - maxWordLength: this.maxWordLength, - font: this.font, - cutEmptyParagraphs: this.cutEmptyParagraphs, - addEmptyParagraphs: this.addEmptyParagraphs, - showImages: this.showImages, - imageHeightLines: this.imageHeightLines, - imageFitWidth: this.imageFitWidth, - compactTextPerc: this.compactTextPerc, + p: s.p, + w: s.w, + font: s.font, + fontSize: s.fontSize, + wordWrap: s.wordWrap, + cutEmptyParagraphs: s.cutEmptyParagraphs, + addEmptyParagraphs: s.addEmptyParagraphs, + maxWordLength: s.maxWordLength, + lineHeight: s.lineHeight, + showImages: s.showImages, + imageHeightLines: s.imageHeightLines, + imageFitWidth: s.imageFitWidth, + compactTextPerc: s.compactTextPerc, + testWidth: s.testWidth, visible: true, //вычисляется позже }; @@ -774,7 +801,7 @@ export default class BookParser { let ofs = 0;//смещение от начала параграфа para.offset let imgW = 0; let imageInPara = false; - const compactWidth = this.measureText('W', {})*this.compactTextPerc/100; + const compactWidth = this.measureText('W', {})*parsed.compactTextPerc/100; // тут начинается самый замес, перенос по слогам и стилизация, а также изображения for (const part of parts) { style = part.style; @@ -787,14 +814,14 @@ export default class BookParser { if (!bin) bin = {h: 1, w: 1}; - let lineCount = this.imageHeightLines; - let c = Math.ceil(bin.h/this.lineHeight); + let lineCount = parsed.imageHeightLines; + let c = Math.ceil(bin.h/parsed.lineHeight); - const maxH = lineCount*this.lineHeight; + const maxH = lineCount*parsed.lineHeight; let maxH2 = maxH; - if (this.imageFitWidth && bin.w > this.w) { + if (parsed.imageFitWidth && bin.w > this.w) { maxH2 = bin.h*this.w/bin.w; - c = Math.ceil(maxH2/this.lineHeight); + c = Math.ceil(maxH2/parsed.lineHeight); } lineCount = (c < lineCount ? c : lineCount); @@ -834,10 +861,10 @@ export default class BookParser { continue; } - if (part.image.id && part.image.inline && this.showImages) { + if (part.image.id && part.image.inline && parsed.showImages) { const bin = this.binary[part.image.id]; if (bin) { - let imgH = (bin.h > this.fontSize ? this.fontSize : bin.h); + let imgH = (bin.h > parsed.fontSize ? parsed.fontSize : bin.h); imgW += bin.w*imgH/bin.h; line.parts.push({style, text: '', image: {local: part.image.local, inline: true, id: part.image.id, num: part.image.num}}); @@ -952,11 +979,11 @@ export default class BookParser { //parsed.visible if (imageInPara) { - parsed.visible = this.showImages; + parsed.visible = parsed.showImages; } else { parsed.visible = !( - (para.addIndex > this.addEmptyParagraphs) || - (para.addIndex == 0 && this.cutEmptyParagraphs && paragraphText.trim() == '') + (para.addIndex > parsed.addEmptyParagraphs) || + (para.addIndex == 0 && parsed.cutEmptyParagraphs && paragraphText.trim() == '') ); }