lib/row.js
function (newHeight, widowLayoutStyle) {

		var itemWidthSum = this.left,
			rowWidthWithoutSpacing = this.width - (this.items.length - 1) * this.spacing,
			clampedToNativeRatio,
			clampedHeight,
			errorWidthPerItem,
			roundedCumulativeErrors,
			singleItemGeometry,
			centerOffset;

		// Justify unless explicitly specified otherwise.
		if (typeof widowLayoutStyle === 'undefined' || ['justify', 'center', 'left'].indexOf(widowLayoutStyle) < 0) {
			widowLayoutStyle = 'left';
		}

		// Clamp row height to edge case minimum/maximum.
		clampedHeight = Math.max(this.edgeCaseMinRowHeight, Math.min(newHeight, this.edgeCaseMaxRowHeight));

		if (newHeight !== clampedHeight) {

			// If row height was clamped, the resulting row/item aspect ratio will be off,
			// so force it to fit the width (recalculate aspectRatio to match clamped height).
			// NOTE: this will result in cropping/padding commensurate to the amount of clamping.
			this.height = clampedHeight;
			clampedToNativeRatio = (rowWidthWithoutSpacing / clampedHeight) / (rowWidthWithoutSpacing / newHeight);

		} else {

			// If not clamped, leave ratio at 1.0.
			this.height = newHeight;
			clampedToNativeRatio = 1.0;

		}

		// Compute item geometry based on newHeight.
		this.items.forEach(function (item) {

			item.top = this.top;
			item.width = item.aspectRatio * this.height * clampedToNativeRatio;
			item.height = this.height;

			// Left-to-right.
			// TODO right to left
			// item.left = this.width - itemWidthSum - item.width;
			item.left = itemWidthSum;

			// Increment width.
			itemWidthSum += item.width + this.spacing;

		}, this);

		// If specified, ensure items fill row and distribute error
		// caused by rounding width and height across all items.
		if (widowLayoutStyle === 'justify') {

			itemWidthSum -= (this.spacing + this.left);

			errorWidthPerItem = (itemWidthSum - this.width) / this.items.length;
			roundedCumulativeErrors = this.items.map(function (item, i) {
				return Math.round((i + 1) * errorWidthPerItem);
			});


			if (this.items.length === 1) {

				// For rows with only one item, adjust item width to fill row.
				singleItemGeometry = this.items[0];
				singleItemGeometry.width -= Math.round(errorWidthPerItem);

			} else {

				// For rows with multiple items, adjust item width and shift items to fill the row,
				// while maintaining equal spacing between items in the row.
				this.items.forEach(function (item, i) {
					if (i > 0) {
						item.left -= roundedCumulativeErrors[i - 1];
						item.width -= (roundedCumulativeErrors[i] - roundedCumulativeErrors[i - 1]);
					} else {
						item.width -= roundedCumulativeErrors[i];
					}
				});

			}

		} else if (widowLayoutStyle === 'center') {

			// Center widows
			centerOffset = (this.width - itemWidthSum) / 2;

			this.items.forEach(function (item) {
				item.left += centerOffset + this.spacing;
			}, this);

		}

	}
function (newHeight, widowLayoutStyle) {

		var itemWidthSum = this.left,
			rowWidthWithoutSpacing = this.width - (this.items.length - 1) * this.spacing,
			clampedToNativeRatio,
			clampedHeight,
			errorWidthPerItem,
			roundedCumulativeErrors,
			singleItemGeometry,
			centerOffset;

		// Justify unless explicitly specified otherwise.
		if (typeof widowLayoutStyle === 'undefined' || ['justify', 'center', 'left'].indexOf(widowLayoutStyle) < 0) {
			widowLayoutStyle = 'left';
		}

		// Clamp row height to edge case minimum/maximum.
		clampedHeight = Math.max(this.edgeCaseMinRowHeight, Math.min(newHeight, this.edgeCaseMaxRowHeight));

		if (newHeight !== clampedHeight) {

			// If row height was clamped, the resulting row/item aspect ratio will be off,
			// so force it to fit the width (recalculate aspectRatio to match clamped height).
			// NOTE: this will result in cropping/padding commensurate to the amount of clamping.
			this.height = clampedHeight;
			clampedToNativeRatio = (rowWidthWithoutSpacing / clampedHeight) / (rowWidthWithoutSpacing / newHeight);

		} else {

			// If not clamped, leave ratio at 1.0.
			this.height = newHeight;
			clampedToNativeRatio = 1.0;

		}

		// Compute item geometry based on newHeight.
		this.items.forEach(function (item) {

			item.top = this.top;
			item.width = item.aspectRatio * this.height * clampedToNativeRatio;
			item.height = this.height;

			// Left-to-right.
			// TODO right to left
			// item.left = this.width - itemWidthSum - item.width;
			item.left = itemWidthSum;

			// Increment width.
			itemWidthSum += item.width + this.spacing;

		}, this);

		// If specified, ensure items fill row and distribute error
		// caused by rounding width and height across all items.
		if (widowLayoutStyle === 'justify') {

			itemWidthSum -= (this.spacing + this.left);

			errorWidthPerItem = (itemWidthSum - this.width) / this.items.length;
			roundedCumulativeErrors = this.items.map(function (item, i) {
				return Math.round((i + 1) * errorWidthPerItem);
			});


			if (this.items.length === 1) {

				// For rows with only one item, adjust item width to fill row.
				singleItemGeometry = this.items[0];
				singleItemGeometry.width -= Math.round(errorWidthPerItem);

			} else {

				// For rows with multiple items, adjust item width and shift items to fill the row,
				// while maintaining equal spacing between items in the row.
				this.items.forEach(function (item, i) {
					if (i > 0) {
						item.left -= roundedCumulativeErrors[i - 1];
						item.width -= (roundedCumulativeErrors[i] - roundedCumulativeErrors[i - 1]);
					} else {
						item.width -= roundedCumulativeErrors[i];
					}
				});

			}

		} else if (widowLayoutStyle === 'center') {

			// Center widows
			centerOffset = (this.width - itemWidthSum) / 2;

			this.items.forEach(function (item) {
				item.left += centerOffset + this.spacing;
			}, this);

		}

	}
function ( newHeight , widowLayoutStyle ) { var itemWidthSum = this . left , rowWidthWithoutSpacing = this . width - ( this . items . length - 1 ) * this . spacing , clampedToNativeRatio , clampedHeight , errorWidthPerItem , roundedCumulativeErrors , singleItemGeometry , centerOffset ; // Justify unless explicitly specified otherwise. if ( typeof widowLayoutStyle === 'undefined' || [ 'justify' , 'center' , 'left' ] . indexOf ( widowLayoutStyle ) < 0 ) { widowLayoutStyle = 'left' ; } // Clamp row height to edge case minimum/maximum. clampedHeight = Math . max ( this . edgeCaseMinRowHeight , Math . min ( newHeight , this . edgeCaseMaxRowHeight ) ) ; if ( newHeight !== clampedHeight ) { // If row height was clamped, the resulting row/item aspect ratio will be off, // so force it to fit the width (recalculate aspectRatio to match clamped height). // NOTE: this will result in cropping/padding commensurate to the amount of clamping. this . height = clampedHeight ; clampedToNativeRatio = ( rowWidthWithoutSpacing / clampedHeight ) / ( rowWidthWithoutSpacing / newHeight ) ; } else { // If not clamped, leave ratio at 1.0. this . height = newHeight ; clampedToNativeRatio = 1.0 ; } // Compute item geometry based on newHeight. this . items . forEach ( function ( item ) { item . top = this . top ; item . width = item . aspectRatio * this . height * clampedToNativeRatio ; item . height = this . height ; // Left-to-right. // TODO right to left // item.left = this.width - itemWidthSum - item.width; item . left = itemWidthSum ; // Increment width. itemWidthSum += item . width + this . spacing ; } , this ) ; // If specified, ensure items fill row and distribute error // caused by rounding width and height across all items. if ( widowLayoutStyle === 'justify' ) { itemWidthSum -= ( this . spacing + this . left ) ; errorWidthPerItem = ( itemWidthSum - this . width ) / this . items . length ; roundedCumulativeErrors = this . items . map ( function ( item , i ) { return Math . round ( ( i + 1 ) * errorWidthPerItem ) ; } ) ; if ( this . items . length === 1 ) { // For rows with only one item, adjust item width to fill row. singleItemGeometry = this . items [ 0 ] ; singleItemGeometry . width -= Math . round ( errorWidthPerItem ) ; } else { // For rows with multiple items, adjust item width and shift items to fill the row, // while maintaining equal spacing between items in the row. this . items . forEach ( function ( item , i ) { if ( i > 0 ) { item . left -= roundedCumulativeErrors [ i - 1 ] ; item . width -= ( roundedCumulativeErrors [ i ] - roundedCumulativeErrors [ i - 1 ] ) ; } else { item . width -= roundedCumulativeErrors [ i ] ; } } ) ; } } else if ( widowLayoutStyle === 'center' ) { // Center widows centerOffset = ( this . width - itemWidthSum ) / 2 ; this . items . forEach ( function ( item ) { item . left += centerOffset + this . spacing ; } , this ) ; } }
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 .