summaryrefslogtreecommitdiff
path: root/lib/epub.js/src/layout.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/epub.js/src/layout.js')
-rw-r--r--lib/epub.js/src/layout.js260
1 files changed, 260 insertions, 0 deletions
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;