Добавлен параметр indentTB, рефакторинг, небольшие доработки граничных случаев

This commit is contained in:
Book Pauk
2019-01-29 14:37:19 +07:00
parent e1bfefc188
commit 57bf25c2d5
4 changed files with 141 additions and 142 deletions

View File

@@ -27,7 +27,7 @@
<div class="partHeader">Шрифт</div> <div class="partHeader">Шрифт</div>
<el-form-item label="Локальный/веб"> <el-form-item label="Локальный/веб">
<el-col :span="10"> <el-col :span="11">
<el-select v-model="fontName" placeholder="Шрифт" :disabled="webFontName != ''"> <el-select v-model="fontName" placeholder="Шрифт" :disabled="webFontName != ''">
<el-option v-for="item in fonts" <el-option v-for="item in fonts"
:key="item.name" :key="item.name"
@@ -39,7 +39,7 @@
<el-col :span="1"> <el-col :span="1">
&nbsp; &nbsp;
</el-col> </el-col>
<el-col :span="10"> <el-col :span="11">
<el-tooltip :open-delay="500" effect="light" placement="top"> <el-tooltip :open-delay="500" effect="light" placement="top">
<template slot="content"> <template slot="content">
Веб шрифты дают большое разнообразие,<br> Веб шрифты дают большое разнообразие,<br>
@@ -57,16 +57,14 @@
</el-col> </el-col>
</el-form-item> </el-form-item>
<el-form-item label="Размер"> <el-form-item label="Размер">
<el-col :span="10"> <el-input-number v-model="fontSize" :min="5" :max="100"></el-input-number>
<el-input-number v-model="fontSize" :min="5" :max="100"></el-input-number>
</el-col>
</el-form-item> </el-form-item>
<el-form-item label="Стиль"> <el-form-item label="Стиль">
<el-col :span="11"> <el-col :span="8">
<el-checkbox v-model="fontBold">Жирный</el-checkbox> <el-checkbox v-model="fontBold">Жирный</el-checkbox>
</el-col> </el-col>
<el-col :span="11"> <el-col :span="8">
<el-checkbox v-model="fontItalic">Курсив</el-checkbox> <el-checkbox v-model="fontItalic">Курсив</el-checkbox>
</el-col> </el-col>
</el-form-item> </el-form-item>
@@ -81,6 +79,27 @@
<el-form-item label="Параграф"> <el-form-item label="Параграф">
<el-input-number v-model="p" :min="0" :max="200"></el-input-number> <el-input-number v-model="p" :min="0" :max="200"></el-input-number>
</el-form-item> </el-form-item>
<el-form-item label="Отступ">
<el-col :span="11">
<el-tooltip :open-delay="500" effect="light">
<template slot="content">
Слева/справа
</template>
<el-input-number v-model="indentLR" :min="0" :max="200"></el-input-number>
</el-tooltip>
</el-col>
<el-col :span="1">
&nbsp;
</el-col>
<el-col :span="11">
<el-tooltip :open-delay="500" effect="light">
<template slot="content">
Сверху/снизу
</template>
<el-input-number v-model="indentTB" :min="0" :max="200"></el-input-number>
</el-tooltip>
</el-col>
</el-form-item>
<el-form-item label="Выравнивание"> <el-form-item label="Выравнивание">
<el-checkbox v-model="textAlignJustify">По ширине</el-checkbox> <el-checkbox v-model="textAlignJustify">По ширине</el-checkbox>
<el-checkbox v-model="wordWrap">Перенос по слогам</el-checkbox> <el-checkbox v-model="wordWrap">Перенос по слогам</el-checkbox>
@@ -163,39 +182,12 @@ import Component from 'vue-class-component';
import Window from '../../share/Window.vue'; import Window from '../../share/Window.vue';
import rstore from '../../../store/modules/reader'; import rstore from '../../../store/modules/reader';
const propsData = {
textColor: '#000000',
backgroundColor: '#EBE2C9',
fontStyle: '',// 'italic'
fontWeight: '',// 'bold'
fontSize: 20,// px
fontName: 'ReaderDefault',
webFontName: '',
lineInterval: 3,// px, межстрочный интервал
textAlignJustify: true,// выравнивание по ширине
p: 25,// px, отступ параграфа
indent: 15,// px, отступ всего текста слева и справа
wordWrap: true,//перенос по слогам
keepLastToFirst: true,// перенос последней строки в первую при листании
showStatusBar: true,
statusBarTop: false,// top, bottom
statusBarHeight: 19,// px
statusBarColorAlpha: 0.4,
pageChangeTransition: '',// '' - нет, downShift, rightShift, thaw - протаивание, blink - мерцание
pageChangeTransitionSpeed: 50, //0-100%
allowUrlParamBookPos: true,
};
export default @Component({ export default @Component({
components: { components: {
Window, Window,
}, },
data: function() { data: function() {
return Object.assign({}, propsData); return Object.assign({}, rstore.settingDefaults);
}, },
watch: { watch: {
form: function(newValue) { form: function(newValue) {
@@ -223,7 +215,7 @@ class SettingsPage extends Vue {
this.reader = this.$store.state.reader; this.reader = this.$store.state.reader;
this.form = this.settings; this.form = this.settings;
for (let prop in propsData) { for (let prop in rstore.settingDefaults) {
this[prop] = this.form[prop]; this[prop] = this.form[prop];
this.$watch(prop, (newValue) => { this.$watch(prop, (newValue) => {
this.form = Object.assign({}, this.form, {[prop]: newValue}) this.form = Object.assign({}, this.form, {[prop]: newValue})

View File

@@ -95,6 +95,18 @@ class TextPage extends Vue {
for (const font of rstore.fonts) { for (const font of rstore.fonts) {
this.fontShifts[font.name] = font.fontVertShift; this.fontShifts[font.name] = font.fontVertShift;
} }
/*
const settings = Object.assign({}, this.settings);
let updated = false;
for (let prop in rstore.settingDefaults) {
if (!settings.hasOwnProperty(prop)) {
settings[prop] = rstore.settingDefaults[prop];
updated = true;
}
}
if (updated)
this.commit('reader/setSettings', settings);
*/
} }
mounted() { mounted() {
@@ -121,8 +133,8 @@ class TextPage extends Vue {
this.$refs.layoutEvents.style.width = this.realWidth + 'px'; this.$refs.layoutEvents.style.width = this.realWidth + 'px';
this.$refs.layoutEvents.style.height = this.realHeight + 'px'; this.$refs.layoutEvents.style.height = this.realHeight + 'px';
this.w = this.realWidth - 2*this.indent; this.w = this.realWidth - 2*this.indentLR;
this.h = this.realHeight - (this.showStatusBar ? this.statusBarHeight : 0); this.h = this.realHeight - (this.showStatusBar ? this.statusBarHeight : 0) - 2*this.indentTB;
this.lineHeight = this.fontSize + this.lineInterval; this.lineHeight = this.fontSize + this.lineInterval;
this.pageLineCount = Math.floor(this.h/this.lineHeight); this.pageLineCount = Math.floor(this.h/this.lineHeight);
@@ -226,35 +238,17 @@ class TextPage extends Vue {
getSettings() { getSettings() {
const settings = this.settings; const settings = this.settings;
this.textColor = settings.textColor; for (let prop in rstore.settingDefaults) {
this.backgroundColor = settings.backgroundColor; this[prop] = settings[prop];
this.fontStyle = settings.fontStyle;// 'italic' }
this.fontWeight = settings.fontWeight;// 'bold'
this.fontSize = settings.fontSize;// px
this.fontName = settings.fontName;
const wf = settings.webFontName; const wf = this.webFontName;
const i = _.findIndex(rstore.webFonts, ['name', wf]); const i = _.findIndex(rstore.webFonts, ['name', wf]);
if (wf && i >= 0) { if (wf && i >= 0) {
this.fontName = wf; this.fontName = wf;
this.fontCssUrl = rstore.webFonts[i].css; this.fontCssUrl = rstore.webFonts[i].css;
this.fontVertShift = rstore.webFonts[i].fontVertShift; this.fontVertShift = rstore.webFonts[i].fontVertShift;
} }
this.lineInterval = settings.lineInterval;// px, межстрочный интервал
this.textAlignJustify = settings.textAlignJustify;// выравнивание по ширине
this.p = settings.p;// px, отступ параграфа
this.indent = settings.indent;// px, отступ всего текста слева и справа
this.wordWrap = settings.wordWrap;
this.keepLastToFirst = settings.keepLastToFirst;// перенос последней строки в первую при листании
this.showStatusBar = settings.showStatusBar;
this.statusBarTop = settings.statusBarTop;// top, bottom
this.statusBarHeight = settings.statusBarHeight;// px
this.statusBarColorAlpha = settings.statusBarColorAlpha;
this.pageChangeTransition = settings.pageChangeTransition;// '' - нет, downShift, rightShift, thaw - протаивание, blink - мерцание
this.pageChangeTransitionSpeed = settings.pageChangeTransitionSpeed; //0-100%
} }
async calcPropsAndLoadFonts(omitLoadFonts) { async calcPropsAndLoadFonts(omitLoadFonts) {
@@ -397,8 +391,8 @@ class TextPage extends Vue {
} }
drawPage(bookPos, nextChangeLines) { drawPage(bookPos, nextChangeLines) {
if (!this.lastBook) if (!this.lastBook || this.pageLineCount < 1)
return; return '';
let out = `<div class="layout" style="width: ${this.realWidth}px; height: ${this.realHeight}px;` + let out = `<div class="layout" style="width: ${this.realWidth}px; height: ${this.realHeight}px;` +
` color: ${this.textColor}; background-color: ${this.backgroundColor}">`; ` color: ${this.textColor}; background-color: ${this.backgroundColor}">`;
@@ -419,75 +413,77 @@ class TextPage extends Vue {
this.linesUpNext = this.parsed.getLines(bookPos, -2*this.pageLineCount); this.linesUpNext = this.parsed.getLines(bookPos, -2*this.pageLineCount);
} }
let y = -this.lineInterval/2 + (this.h - this.pageLineCount*this.lineHeight)/2 + this.fontSize*this.fontShift; if (lines) {
if (this.showStatusBar) let y = this.indentTB - this.lineInterval/2 + (this.h - this.pageLineCount*this.lineHeight)/2 + this.fontSize*this.fontShift;
y += this.statusBarHeight*(this.statusBarTop ? 1 : 0); if (this.showStatusBar)
y += this.statusBarHeight*(this.statusBarTop ? 1 : 0);
let len = lines.length; let len = lines.length;
len = (len > this.pageLineCount ? len = this.pageLineCount : len); len = (len > this.pageLineCount ? len = this.pageLineCount : len);
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
const line = lines[i]; const line = lines[i];
/* line: /* line:
{ {
begin: Number, begin: Number,
end: Number, end: Number,
first: Boolean, first: Boolean,
last: Boolean, last: Boolean,
parts: array of { parts: array of {
style: {bold: Boolean, italic: Boolean, center: Boolean} style: {bold: Boolean, italic: Boolean, center: Boolean}
text: String, text: String,
}
}*/
let indent = this.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.center;
}
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 i = 0; i < partWords.length; i++) {
let word = partWords[i];
out += this.drawHelper.fillText(word, x, y, font);
x += this.measureText(word, part.style) + (i < partWords.length - 1 ? space : 0);
}
} }
filled = true; }*/
}
}
// просто выводим текст let indent = this.indentLR + (line.first ? this.p : 0);
if (!filled) {
let x = indent; let lineText = '';
x = (center ? this.indent + (this.w - this.measureText(lineText, centerStyle))/2 : x); let center = false;
let centerStyle = {};
for (const part of line.parts) { for (const part of line.parts) {
let text = part.text; lineText += part.text;
const font = this.fontByStyle(part.style); center = center || part.style.center;
out += this.drawHelper.fillText(text, x, y, font); if (part.style.center)
x += this.measureText(text, part.style); centerStyle = part.style.center;
} }
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 i = 0; i < partWords.length; i++) {
let word = partWords[i];
out += this.drawHelper.fillText(word, x, y, font);
x += this.measureText(word, part.style) + (i < partWords.length - 1 ? space : 0);
}
}
filled = true;
}
}
// просто выводим текст
if (!filled) {
let x = indent;
x = (center ? this.indent + (this.w - this.measureText(lineText, centerStyle))/2 : x);
for (const part of line.parts) {
let text = part.text;
const font = this.fontByStyle(part.style);
out += this.drawHelper.fillText(text, x, y, font);
x += this.measureText(text, part.style);
}
}
y += this.lineHeight;
} }
y += this.lineHeight;
} }
out += '</div>'; out += '</div>';
@@ -500,7 +496,7 @@ class TextPage extends Vue {
return; return;
} }
if (this.showStatusBar && this.linesDown) { if (this.showStatusBar && this.linesDown && this.pageLineCount > 0) {
const lines = this.linesDown; const lines = this.linesDown;
let i = this.pageLineCount; let i = this.pageLineCount;
if (this.keepLastToFirst) if (this.keepLastToFirst)
@@ -514,6 +510,8 @@ class TextPage extends Vue {
lines[i].end, this.parsed.textLength, message); lines[i].end, this.parsed.textLength, message);
this.bookPosSeen = lines[i].end; this.bookPosSeen = lines[i].end;
} }
} else {
this.statusBar = '';
} }
} }
@@ -543,7 +541,7 @@ class TextPage extends Vue {
prepareNextPage() { prepareNextPage() {
// подготовка следующей страницы заранее // подготовка следующей страницы заранее
if (!this.book || !this.parsed.textLength || !this.linesDown) if (!this.book || !this.parsed.textLength || !this.linesDown || this.pageLineCount < 1)
return; return;
if (!this.preparing) { if (!this.preparing) {
@@ -576,19 +574,19 @@ class TextPage extends Vue {
} }
doDown() { doDown() {
if (this.linesDown && this.linesDown.length > this.pageLineCount) { if (this.linesDown && this.linesDown.length > this.pageLineCount && this.pageLineCount > 0) {
this.bookPos = this.linesDown[1].begin; this.bookPos = this.linesDown[1].begin;
} }
} }
doUp() { doUp() {
if (this.linesUp && this.linesUp.length > 1) { if (this.linesUp && this.linesUp.length > 1 && this.pageLineCount > 0) {
this.bookPos = this.linesUp[1].begin; this.bookPos = this.linesUp[1].begin;
} }
} }
doPageDown() { doPageDown() {
if (this.linesDown) { if (this.linesDown && this.pageLineCount > 0) {
let i = this.pageLineCount; let i = this.pageLineCount;
if (this.keepLastToFirst) if (this.keepLastToFirst)
i--; i--;
@@ -602,7 +600,7 @@ class TextPage extends Vue {
} }
doPageUp() { doPageUp() {
if (this.linesUp) { if (this.linesUp && this.pageLineCount > 0) {
let i = this.pageLineCount; let i = this.pageLineCount;
if (this.keepLastToFirst) if (this.keepLastToFirst)
i--; i--;
@@ -620,13 +618,15 @@ class TextPage extends Vue {
} }
doEnd() { doEnd() {
if (this.parsed.para.length) { if (this.parsed.para.length && this.pageLineCount > 0) {
let i = this.parsed.para.length - 1; let i = this.parsed.para.length - 1;
let lastPos = this.parsed.para[i].offset + this.parsed.para[i].length - 1; let lastPos = this.parsed.para[i].offset + this.parsed.para[i].length - 1;
const lines = this.parsed.getLines(lastPos, -this.pageLineCount); const lines = this.parsed.getLines(lastPos, -this.pageLineCount);
i = this.pageLineCount - 1; if (lines) {
i = (i > lines.length - 1 ? lines.length - 1 : i); i = this.pageLineCount - 1;
this.bookPos = lines[i].begin; i = (i > lines.length - 1 ? lines.length - 1 : i);
this.bookPos = lines[i].begin;
}
} }
} }

View File

@@ -598,6 +598,8 @@ export default class BookParser {
} }
} }
if (!result.length)
result = null;
return result; return result;
} }
} }

View File

@@ -18,11 +18,7 @@ const webFonts = [
]; ];
// initial state const settingDefaults = {
const state = {
toolBarActive: true,
openedBook: {},
settings: {
textColor: '#000000', textColor: '#000000',
backgroundColor: '#EBE2C9', backgroundColor: '#EBE2C9',
fontStyle: '',// 'italic' fontStyle: '',// 'italic'
@@ -34,7 +30,8 @@ const state = {
lineInterval: 3,// px, межстрочный интервал lineInterval: 3,// px, межстрочный интервал
textAlignJustify: true,// выравнивание по ширине textAlignJustify: true,// выравнивание по ширине
p: 25,// px, отступ параграфа p: 25,// px, отступ параграфа
indent: 15,// px, отступ всего текста слева и справа indentLR: 15,// px, отступ всего текста слева и справа
indentTB: 0,// px, отступ всего текста сверху и снизу
wordWrap: true,//перенос по слогам wordWrap: true,//перенос по слогам
keepLastToFirst: true,// перенос последней строки в первую при листании keepLastToFirst: true,// перенос последней строки в первую при листании
@@ -47,7 +44,13 @@ const state = {
pageChangeTransitionSpeed: 50, //0-100% pageChangeTransitionSpeed: 50, //0-100%
allowUrlParamBookPos: false, allowUrlParamBookPos: false,
}, };
// initial state
const state = {
toolBarActive: true,
openedBook: {},
settings: Object.assign({}, settingDefaults),
}; };
// getters // getters
@@ -112,6 +115,8 @@ const mutations = {
export default { export default {
fonts, fonts,
webFonts, webFonts,
settingDefaults,
namespaced: true, namespaced: true,
state, state,
getters, getters,