diff --git a/lib/index.js b/lib/index.js index 741ae43..e912e09 100644 --- a/lib/index.js +++ b/lib/index.js @@ -7,17 +7,18 @@ 'use strict'; var merge = require('merge'), - Row = require('./row'), - layoutConfig = {}, - layoutData = {}; + Row = require('./row'); /** -* Create a new, empty row. -* -* @method createNewRow -* @return A new, empty row of the type specified by this layout. -*/ -function createNewRow() { + * Create a new, empty row. + * + * @method createNewRow + * @param layoutConfig {Object} The layout configuration + * @param layoutData {Object} The current state of the layout + * @return A new, empty row of the type specified by this layout. + */ + +function createNewRow(layoutConfig, layoutData) { var isBreakoutRow; @@ -48,10 +49,13 @@ function createNewRow() { * Note: the row must have already been completed. * * @method addRow + * @param layoutConfig {Object} The layout configuration + * @param layoutData {Object} The current state of the layout * @param row {Row} The row to add. * @return {Array} Each item added to the row. */ -function addRow(row) { + +function addRow(layoutConfig, layoutData, row) { layoutData._rows.push(row); layoutData._layoutItems = layoutData._layoutItems.concat(row.getItems()); @@ -63,14 +67,17 @@ function addRow(row) { } /** -* Calculate the current layout for all items in the list that require layout. -* "Layout" means geometry: position within container and size -* -* @method computeLayout -* @param itemLayoutData {Array} Array of items to lay out, with data required to lay out each item -* @return {Object} The newly-calculated layout, containing the new container height, and lists of layout items -*/ -function computeLayout(itemLayoutData) { + * Calculate the current layout for all items in the list that require layout. + * "Layout" means geometry: position within container and size + * + * @method computeLayout + * @param layoutConfig {Object} The layout configuration + * @param layoutData {Object} The current state of the layout + * @param itemLayoutData {Array} Array of items to lay out, with data required to lay out each item + * @return {Object} The newly-calculated layout, containing the new container height, and lists of layout items + */ + +function computeLayout(layoutConfig, layoutData, itemLayoutData) { var laidOutItems = [], itemAdded, @@ -94,7 +101,7 @@ function computeLayout(itemLayoutData) { // If not currently building up a row, make a new one. if (!currentRow) { - currentRow = createNewRow(); + currentRow = createNewRow(layoutConfig, layoutData); } // Attempt to add item to the current row. @@ -103,14 +110,14 @@ function computeLayout(itemLayoutData) { if (currentRow.isLayoutComplete()) { // Row is filled; add it and start a new one - laidOutItems = laidOutItems.concat(addRow(currentRow)); + laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow)); if (layoutData._rows.length >= layoutConfig.maxNumRows) { currentRow = null; return true; } - currentRow = createNewRow(); + currentRow = createNewRow(layoutConfig, layoutData); // Item was rejected; add it to its own row if (!itemAdded) { @@ -120,12 +127,12 @@ function computeLayout(itemLayoutData) { if (currentRow.isLayoutComplete()) { // If the rejected item fills a row on its own, add the row and start another new one - laidOutItems = laidOutItems.concat(addRow(currentRow)); + laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow)); if (layoutData._rows.length >= layoutConfig.maxNumRows) { currentRow = null; return true; } - currentRow = createNewRow(); + currentRow = createNewRow(layoutConfig, layoutData); } } } @@ -155,7 +162,7 @@ function computeLayout(itemLayoutData) { } - laidOutItems = laidOutItems.concat(addRow(currentRow)); + laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow)); layoutConfig._widowCount = currentRow.getItems().length; } @@ -175,14 +182,17 @@ function computeLayout(itemLayoutData) { } /** -* Takes in a bunch of box data and config. Returns -* geometry to lay them out in a justified view. -* -* @method covertSizesToAspectRatios -* @param sizes {Array} Array of objects with widths and heights -* @return {Array} A list of aspect ratios -**/ + * Takes in a bunch of box data and config. Returns + * geometry to lay them out in a justified view. + * + * @method covertSizesToAspectRatios + * @param sizes {Array} Array of objects with widths and heights + * @return {Array} A list of aspect ratios + */ + module.exports = function (input, config) { + var layoutConfig = {}; + var layoutData = {}; // Defaults var defaults = { @@ -229,7 +239,7 @@ module.exports = function (input, config) { layoutConfig._widowCount = 0; // Convert widths and heights to aspect ratios if we need to - return computeLayout(input.map(function (item) { + return computeLayout(layoutConfig, layoutData, input.map(function (item) { if (item.width && item.height) { return { aspectRatio: item.width / item.height }; } else { diff --git a/lib/row.js b/lib/row.js index ade7002..fdff562 100644 --- a/lib/row.js +++ b/lib/row.js @@ -7,24 +7,25 @@ var merge = require('merge'); /** -* Row -* Wrapper for each row in a justified layout. -* Stores relevant values and provides methods for calculating layout of individual rows. -* -* @param {Object} layoutConfig - The same as that passed -* @param {Object} Initialization parameters. The following are all required: -* @param params.top {Number} Top of row, relative to container -* @param params.left {Number} Left side of row relative to container (equal to container left padding) -* @param params.width {Number} Width of row, not including container padding -* @param params.spacing {Number} Horizontal spacing between items -* @param params.targetRowHeight {Number} Layout algorithm will aim for this row height -* @param params.targetRowHeightTolerance {Number} Row heights may vary +/- (`targetRowHeight` x `targetRowHeightTolerance`) -* @param params.edgeCaseMinRowHeight {Number} Absolute minimum row height for edge cases that cannot be resolved within tolerance. -* @param params.edgeCaseMaxRowHeight {Number} Absolute maximum row height for edge cases that cannot be resolved within tolerance. -* @param params.isBreakoutRow {Boolean} Is this row in particular one of those breakout rows? Always false if it's not that kind of photo list -* @param params.widowLayoutStyle {String} If widows are visible, how should they be laid out? -* @constructor -*/ + * Row + * Wrapper for each row in a justified layout. + * Stores relevant values and provides methods for calculating layout of individual rows. + * + * @param {Object} layoutConfig - The same as that passed + * @param {Object} Initialization parameters. The following are all required: + * @param params.top {Number} Top of row, relative to container + * @param params.left {Number} Left side of row relative to container (equal to container left padding) + * @param params.width {Number} Width of row, not including container padding + * @param params.spacing {Number} Horizontal spacing between items + * @param params.targetRowHeight {Number} Layout algorithm will aim for this row height + * @param params.targetRowHeightTolerance {Number} Row heights may vary +/- (`targetRowHeight` x `targetRowHeightTolerance`) + * @param params.edgeCaseMinRowHeight {Number} Absolute minimum row height for edge cases that cannot be resolved within tolerance. + * @param params.edgeCaseMaxRowHeight {Number} Absolute maximum row height for edge cases that cannot be resolved within tolerance. + * @param params.isBreakoutRow {Boolean} Is this row in particular one of those breakout rows? Always false if it's not that kind of photo list + * @param params.widowLayoutStyle {String} If widows are visible, how should they be laid out? + * @constructor + */ + var Row = module.exports = function (params) { // Top of row, relative to container @@ -66,25 +67,26 @@ var Row = module.exports = function (params) { Row.prototype = { /** - * Attempt to add a single item to the row. - * This is the heart of the justified algorithm. - * This method is direction-agnostic; it deals only with sizes, not positions. - * - * If the item fits in the row, without pushing row height beyond min/max tolerance, - * the item is added and the method returns true. - * - * If the item leaves row height too high, there may be room to scale it down and add another item. - * In this case, the item is added and the method returns true, but the row is incomplete. - * - * If the item leaves row height too short, there are too many items to fit within tolerance. - * The method will either accept or reject the new item, favoring the resulting row height closest to within tolerance. - * If the item is rejected, left/right padding will be required to fit the row height within tolerance; - * if the item is accepted, top/bottom cropping will be required to fit the row height within tolerance. - * - * @method addItem - * @param itemData {Object} Item layout data, containing item aspect ratio. - * @return {Boolean} True if successfully added; false if rejected. - */ + * Attempt to add a single item to the row. + * This is the heart of the justified algorithm. + * This method is direction-agnostic; it deals only with sizes, not positions. + * + * If the item fits in the row, without pushing row height beyond min/max tolerance, + * the item is added and the method returns true. + * + * If the item leaves row height too high, there may be room to scale it down and add another item. + * In this case, the item is added and the method returns true, but the row is incomplete. + * + * If the item leaves row height too short, there are too many items to fit within tolerance. + * The method will either accept or reject the new item, favoring the resulting row height closest to within tolerance. + * If the item is rejected, left/right padding will be required to fit the row height within tolerance; + * if the item is accepted, top/bottom cropping will be required to fit the row height within tolerance. + * + * @method addItem + * @param itemData {Object} Item layout data, containing item aspect ratio. + * @return {Boolean} True if successfully added; false if rejected. + */ + addItem: function (itemData) { var newItems = this.items.concat(itemData), @@ -172,24 +174,25 @@ Row.prototype = { }, /** - * Check if a row has completed its layout. - * - * @method isLayoutComplete - * @return {Boolean} True if complete; false if not. - */ + * Check if a row has completed its layout. + * + * @method isLayoutComplete + * @return {Boolean} True if complete; false if not. + */ + isLayoutComplete: function () { return this.height > 0; }, - /** - * Set row height and compute item geometry from that height. - * Will justify items within the row unless instructed not to. - * - * @method completeLayout - * @param newHeight {Number} Set row height to this value. - * @param widowLayoutStyle {String} How should widows display? Supported: left | justify | center - */ + * Set row height and compute item geometry from that height. + * Will justify items within the row unless instructed not to. + * + * @method completeLayout + * @param newHeight {Number} Set row height to this value. + * @param widowLayoutStyle {String} How should widows display? Supported: left | justify | center + */ + completeLayout: function (newHeight, widowLayoutStyle) { var itemWidthSum = this.left, @@ -289,13 +292,14 @@ Row.prototype = { }, /** - * Force completion of row layout with current items. - * - * @method forceComplete - * @param fitToWidth {Boolean} Stretch current items to fill the row width. - * This will likely result in padding. - * @param fitToWidth {Number} - */ + * Force completion of row layout with current items. + * + * @method forceComplete + * @param fitToWidth {Boolean} Stretch current items to fill the row width. + * This will likely result in padding. + * @param fitToWidth {Number} + */ + forceComplete: function (fitToWidth, rowHeight) { // TODO Handle fitting to width @@ -317,12 +321,13 @@ Row.prototype = { }, /** - * Return layout data for items within row. - * Note: returns actual list, not a copy. - * - * @method getItems - * @return Layout data for items within row. - */ + * Return layout data for items within row. + * Note: returns actual list, not a copy. + * + * @method getItems + * @return Layout data for items within row. + */ + getItems: function () { return this.items; }