From 4fd9b8f2b5a98bfcde57970b48fed2488a80f356 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Fri, 17 Sep 2021 21:53:37 +0300 Subject: add in master snapshot of epubjs --- lib/epub.js/src/layout.js | 260 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 lib/epub.js/src/layout.js (limited to 'lib/epub.js/src/layout.js') diff --git a/lib/epub.js/src/layout.js b/lib/epub.js/src/layout.js new file mode 100644 index 0000000..4f16a0f --- /dev/null +++ b/lib/epub.js/src/layout.js @@ -0,0 +1,260 @@ +import { extend } from "./utils/core"; +import { EVENTS } from "./utils/constants"; +import EventEmitter from "event-emitter"; + +/** + * Figures out the CSS values to apply for a layout + * @class + * @param {object} settings + * @param {string} [settings.layout='reflowable'] + * @param {string} [settings.spread] + * @param {number} [settings.minSpreadWidth=800] + * @param {boolean} [settings.evenSpreads=false] + */ +class Layout { + constructor(settings) { + this.settings = settings; + this.name = settings.layout || "reflowable"; + this._spread = (settings.spread === "none") ? false : true; + this._minSpreadWidth = settings.minSpreadWidth || 800; + this._evenSpreads = settings.evenSpreads || false; + + if (settings.flow === "scrolled" || + settings.flow === "scrolled-continuous" || + settings.flow === "scrolled-doc") { + this._flow = "scrolled"; + } else { + this._flow = "paginated"; + } + + + this.width = 0; + this.height = 0; + this.spreadWidth = 0; + this.delta = 0; + + this.columnWidth = 0; + this.gap = 0; + this.divisor = 1; + + this.props = { + name: this.name, + spread: this._spread, + flow: this._flow, + width: 0, + height: 0, + spreadWidth: 0, + delta: 0, + columnWidth: 0, + gap: 0, + divisor: 1 + }; + + } + + /** + * Switch the flow between paginated and scrolled + * @param {string} flow paginated | scrolled + * @return {string} simplified flow + */ + flow(flow) { + if (typeof(flow) != "undefined") { + if (flow === "scrolled" || + flow === "scrolled-continuous" || + flow === "scrolled-doc") { + this._flow = "scrolled"; + } else { + this._flow = "paginated"; + } + // this.props.flow = this._flow; + this.update({flow: this._flow}); + } + return this._flow; + } + + /** + * Switch between using spreads or not, and set the + * width at which they switch to single. + * @param {string} spread "none" | "always" | "auto" + * @param {number} min integer in pixels + * @return {boolean} spread true | false + */ + spread(spread, min) { + + if (spread) { + this._spread = (spread === "none") ? false : true; + // this.props.spread = this._spread; + this.update({spread: this._spread}); + } + + if (min >= 0) { + this._minSpreadWidth = min; + } + + return this._spread; + } + + /** + * Calculate the dimensions of the pagination + * @param {number} _width width of the rendering + * @param {number} _height height of the rendering + * @param {number} _gap width of the gap between columns + */ + calculate(_width, _height, _gap){ + + var divisor = 1; + var gap = _gap || 0; + + //-- Check the width and create even width columns + // var fullWidth = Math.floor(_width); + var width = _width; + var height = _height; + + var section = Math.floor(width / 12); + + var columnWidth; + var spreadWidth; + var pageWidth; + var delta; + + if (this._spread && width >= this._minSpreadWidth) { + divisor = 2; + } else { + divisor = 1; + } + + if (this.name === "reflowable" && this._flow === "paginated" && !(_gap >= 0)) { + gap = ((section % 2 === 0) ? section : section - 1); + } + + if (this.name === "pre-paginated" ) { + gap = 0; + } + + //-- Double Page + if(divisor > 1) { + // width = width - gap; + // columnWidth = (width - gap) / divisor; + // gap = gap / divisor; + columnWidth = (width / divisor) - gap; + pageWidth = columnWidth + gap; + } else { + columnWidth = width; + pageWidth = width; + } + + if (this.name === "pre-paginated" && divisor > 1) { + width = columnWidth; + } + + spreadWidth = (columnWidth * divisor) + gap; + + delta = width; + + this.width = width; + this.height = height; + this.spreadWidth = spreadWidth; + this.pageWidth = pageWidth; + this.delta = delta; + + this.columnWidth = columnWidth; + this.gap = gap; + this.divisor = divisor; + + // this.props.width = width; + // this.props.height = _height; + // this.props.spreadWidth = spreadWidth; + // this.props.pageWidth = pageWidth; + // this.props.delta = delta; + // + // this.props.columnWidth = colWidth; + // this.props.gap = gap; + // this.props.divisor = divisor; + + this.update({ + width, + height, + spreadWidth, + pageWidth, + delta, + columnWidth, + gap, + divisor + }); + + } + + /** + * Apply Css to a Document + * @param {Contents} contents + * @return {Promise} + */ + format(contents, section, axis){ + var formating; + + if (this.name === "pre-paginated") { + formating = contents.fit(this.columnWidth, this.height, section); + } else if (this._flow === "paginated") { + formating = contents.columns(this.width, this.height, this.columnWidth, this.gap, this.settings.direction); + } else if (axis && axis === "horizontal") { + formating = contents.size(null, this.height); + } else { + formating = contents.size(this.width, null); + } + + return formating; // might be a promise in some View Managers + } + + /** + * Count number of pages + * @param {number} totalLength + * @param {number} pageLength + * @return {{spreads: Number, pages: Number}} + */ + count(totalLength, pageLength) { + + let spreads, pages; + + if (this.name === "pre-paginated") { + spreads = 1; + pages = 1; + } else if (this._flow === "paginated") { + pageLength = pageLength || this.delta; + spreads = Math.ceil( totalLength / pageLength); + pages = spreads * this.divisor; + } else { // scrolled + pageLength = pageLength || this.height; + spreads = Math.ceil( totalLength / pageLength); + pages = spreads; + } + + return { + spreads, + pages + }; + + } + + /** + * Update props that have changed + * @private + * @param {object} props + */ + update(props) { + // Remove props that haven't changed + Object.keys(props).forEach((propName) => { + if (this.props[propName] === props[propName]) { + delete props[propName]; + } + }); + + if(Object.keys(props).length > 0) { + let newProps = extend(this.props, props); + this.emit(EVENTS.LAYOUT.UPDATED, newProps, props); + } + } +} + +EventEmitter(Layout.prototype); + +export default Layout; -- cgit v1.2.3