Book Pauk 4 жил өмнө
parent
commit
17c14722fd

+ 37 - 28
client/components/Reader/TextPage/TextPage.vue

@@ -228,28 +228,31 @@ class TextPage extends Vue {
 
 
         //parsed
         //parsed
         if (this.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, {}))
+            this.testText = 'Это тестовый текст. Его ширина выдается системой неправильно некоторое время.';
+
+            let wideLine = wideLetter;
+            if (!this.drawHelper.measureText(wideLine, {}))
                 throw new Error('Ошибка measureText');
                 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.parsed.testText = 'Это тестовый текст. Его ширина выдается системой неверно некоторое время.';
-            this.parsed.testWidth = this.drawHelper.measureText(this.parsed.testText, {});
+            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
         //scrolling page
@@ -333,19 +336,25 @@ class TextPage extends Vue {
         if (!omitLoadFonts)
         if (!omitLoadFonts)
             await this.loadFonts();
             await this.loadFonts();
 
 
-        this.draw();
-
-        // ширина шрифта некоторое время выдается неверно, поэтому
-        if (!omitLoadFonts) {
+        if (omitLoadFonts) {
+            this.draw();
+        } else {
+            // ширина шрифта некоторое время выдается неверно,
+            // не получилось событийно отловить этот момент, поэтому костыль
             const parsed = this.parsed;
             const parsed = this.parsed;
 
 
             let i = 0;
             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);
                 await utils.sleep(100);
+            }
 
 
             if (this.parsed === parsed) {
             if (this.parsed === parsed) {
-                this.parsed.testWidth = this.drawHelper.measureText(t, {});
+                this.parsed.setSettings({testWidth: this.drawHelper.measureText(t, {})});
                 this.draw();
                 this.draw();
             }
             }
         }
         }

+ 78 - 51
client/components/Reader/share/BookParser.js

@@ -4,23 +4,44 @@ import * as utils from '../../../share/utils';
 
 
 const maxImageLineCount = 100;
 const maxImageLineCount = 100;
 
 
-export default class BookParser {
-    constructor(settings) {
-        if (settings) {
-            this.showInlineImagesInCenter = settings.showInlineImagesInCenter;
-        }
+// 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;
+    },
+};
 
 
-        // defaults
-        this.p = 30;// px, отступ параграфа
-        this.w = 300;// px, ширина страницы
-        this.wordWrap = false;// перенос по слогам
+export default class BookParser {
+    constructor(settings = {}) {
+        this.sets = {};
 
 
-        //заглушка
-        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) {
     async parse(data, callback) {
         if (!callback)
         if (!callback)
             callback = () => {};
             callback = () => {};
@@ -210,14 +231,14 @@ export default class BookParser {
                     if (href[0] == '#') {//local
                     if (href[0] == '#') {//local
                         imageNum++;
                         imageNum++;
 
 
-                        if (inPara && !this.showInlineImagesInCenter && !center)
+                        if (inPara && !this.sets.showInlineImagesInCenter && !center)
                             growParagraph(`<image-inline href="${href}" num="${imageNum}"></image-inline>`, 0);
                             growParagraph(`<image-inline href="${href}" num="${imageNum}"></image-inline>`, 0);
                         else
                         else
                             newParagraph(`<image href="${href}" num="${imageNum}">${' '.repeat(maxImageLineCount)}</image>`, maxImageLineCount);
                             newParagraph(`<image href="${href}" num="${imageNum}">${' '.repeat(maxImageLineCount)}</image>`, maxImageLineCount);
 
 
                         this.images.push({paraIndex, num: imageNum, id, local, alt});
                         this.images.push({paraIndex, num: imageNum, id, local, alt});
 
 
-                        if (inPara && this.showInlineImagesInCenter)
+                        if (inPara && this.sets.showInlineImagesInCenter)
                             newParagraph(' ', 1);
                             newParagraph(' ', 1);
                     } else {//external
                     } else {//external
                         imageNum++;
                         imageNum++;
@@ -632,7 +653,7 @@ export default class BookParser {
         });
         });
 
 
         //длинные слова (или белиберду без пробелов) тоже разобьем
         //длинные слова (или белиберду без пробелов) тоже разобьем
-        const maxWordLength = this.maxWordLength;
+        const maxWordLength = this.sets.maxWordLength;
         const parts = result;
         const parts = result;
         result = [];
         result = [];
         for (const part of parts) {
         for (const part of parts) {
@@ -712,37 +733,43 @@ export default class BookParser {
 
 
     parsePara(paraIndex) {
     parsePara(paraIndex) {
         const para = this.para[paraIndex];
         const para = this.para[paraIndex];
+        const s = this.sets;
 
 
+        //перераспарсиваем только при изменении одного из параметров
         if (!this.force &&
         if (!this.force &&
             para.parsed && 
             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;
             return para.parsed;
 
 
         const 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, //вычисляется позже
             visible: true, //вычисляется позже
         };
         };
 
 
@@ -774,7 +801,7 @@ export default class BookParser {
         let ofs = 0;//смещение от начала параграфа para.offset
         let ofs = 0;//смещение от начала параграфа para.offset
         let imgW = 0;
         let imgW = 0;
         let imageInPara = false;
         let imageInPara = false;
-        const compactWidth = this.measureText('W', {})*this.compactTextPerc/100;
+        const compactWidth = this.measureText('W', {})*parsed.compactTextPerc/100;
         // тут начинается самый замес, перенос по слогам и стилизация, а также изображения
         // тут начинается самый замес, перенос по слогам и стилизация, а также изображения
         for (const part of parts) {
         for (const part of parts) {
             style = part.style;
             style = part.style;
@@ -787,14 +814,14 @@ export default class BookParser {
                 if (!bin)
                 if (!bin)
                     bin = {h: 1, w: 1};
                     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;
                 let maxH2 = maxH;
-                if (this.imageFitWidth && bin.w > this.w) {
+                if (parsed.imageFitWidth && bin.w > this.w) {
                     maxH2 = bin.h*this.w/bin.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);
                 lineCount = (c < lineCount ? c : lineCount);
 
 
@@ -834,10 +861,10 @@ export default class BookParser {
                 continue;
                 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];
                 const bin = this.binary[part.image.id];
                 if (bin) {
                 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;
                     imgW += bin.w*imgH/bin.h;
                     line.parts.push({style, text: '',
                     line.parts.push({style, text: '',
                         image: {local: part.image.local, inline: true, id: part.image.id, num: part.image.num}});
                         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
         //parsed.visible
         if (imageInPara) {
         if (imageInPara) {
-            parsed.visible = this.showImages;
+            parsed.visible = parsed.showImages;
         } else {
         } else {
             parsed.visible = !(
             parsed.visible = !(
-                (para.addIndex > this.addEmptyParagraphs) ||
-                (para.addIndex == 0 && this.cutEmptyParagraphs && paragraphText.trim() == '')
+                (para.addIndex > parsed.addEmptyParagraphs) ||
+                (para.addIndex == 0 && parsed.cutEmptyParagraphs && paragraphText.trim() == '')
             );
             );
         }
         }