angular-justified-layout
Version:
Angularjs wrapper for Flickr Justified Layout
9 lines (8 loc) • 12.5 kB
JavaScript
/**
* Package: angular-justified-layout - v0.0.1
* Description: Angularjs wrapper for Flickr Justified Layout
* Last build: 2017-07-15
* @author codekraft-studio
* @license ISC
*/
require=function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n||e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){"use strict";var merge=require("merge");(module.exports=function(params){this.top=params.top,this.left=params.left,this.width=params.width,this.spacing=params.spacing,this.targetRowHeight=params.targetRowHeight,this.targetRowHeightTolerance=params.targetRowHeightTolerance,this.minAspectRatio=this.width/params.targetRowHeight*(1-params.targetRowHeightTolerance),this.maxAspectRatio=this.width/params.targetRowHeight*(1+params.targetRowHeightTolerance),this.edgeCaseMinRowHeight=params.edgeCaseMinRowHeight||Number.NEGATIVE_INFINITY,this.edgeCaseMaxRowHeight=params.edgeCaseMaxRowHeight||Number.POSITIVE_INFINITY,this.rightToLeft=params.rightToLeft,this.isBreakoutRow=params.isBreakoutRow,this.items=[],this.height=0}).prototype={addItem:function(itemData){var previousRowWidthWithoutSpacing,previousAspectRatio,previousTargetAspectRatio,newItems=this.items.concat(itemData),rowWidthWithoutSpacing=this.width-(newItems.length-1)*this.spacing,newAspectRatio=newItems.reduce(function(sum,item){return sum+item.aspectRatio},0),targetAspectRatio=rowWidthWithoutSpacing/this.targetRowHeight;return this.isBreakoutRow&&0===this.items.length&&itemData.aspectRatio>=1?(this.items.push(itemData),this.completeLayout(rowWidthWithoutSpacing/itemData.aspectRatio),!0):0!==newAspectRatio&&(newAspectRatio<this.minAspectRatio?(this.items.push(merge(itemData)),!0):newAspectRatio>this.maxAspectRatio?0===this.items.length?(this.items.push(merge(itemData)),this.completeLayout(rowWidthWithoutSpacing/newAspectRatio),!0):(previousRowWidthWithoutSpacing=this.width-(this.items.length-1)*this.spacing,previousAspectRatio=this.items.reduce(function(sum,item){return sum+item.aspectRatio},0),previousTargetAspectRatio=previousRowWidthWithoutSpacing/this.targetRowHeight,Math.abs(newAspectRatio-targetAspectRatio)>Math.abs(previousAspectRatio-previousTargetAspectRatio)?(this.completeLayout(previousRowWidthWithoutSpacing/previousAspectRatio),!1):(this.items.push(merge(itemData)),this.completeLayout(rowWidthWithoutSpacing/newAspectRatio),!0)):(this.items.push(merge(itemData)),this.completeLayout(rowWidthWithoutSpacing/newAspectRatio),!0))},isLayoutComplete:function(){return this.height>0},completeLayout:function(newHeight,justify){var clampedToNativeRatio,roundedHeight,clampedHeight,errorWidthPerItem,roundedCumulativeErrors,singleItemGeometry,itemWidthSum=this.rightToLeft?-this.left:this.left,rowWidthWithoutSpacing=this.width-(this.items.length-1)*this.spacing,self=this;void 0===justify&&(justify=!0),(roundedHeight=Math.round(newHeight))!==(clampedHeight=Math.max(this.edgeCaseMinRowHeight,Math.min(roundedHeight,this.edgeCaseMaxRowHeight)))?(this.height=clampedHeight,clampedToNativeRatio=rowWidthWithoutSpacing/clampedHeight/(rowWidthWithoutSpacing/roundedHeight)):(this.height=roundedHeight,clampedToNativeRatio=1),this.items.forEach(function(item,i){item.top=self.top,item.width=Math.round(item.aspectRatio*self.height*clampedToNativeRatio),item.height=self.height,self.rightToLeft?item.left=self.width-itemWidthSum-item.width:item.left=itemWidthSum,itemWidthSum+=item.width+self.spacing}),justify&&(this.rightToLeft||(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)}),1===this.items.length?((singleItemGeometry=this.items[0]).width-=Math.round(errorWidthPerItem),this.rightToLeft&&(singleItemGeometry.left+=Math.round(errorWidthPerItem))):this.items.forEach(function(item,i){i>0?(item.left-=roundedCumulativeErrors[i-1],item.width-=roundedCumulativeErrors[i]-roundedCumulativeErrors[i-1]):item.width-=roundedCumulativeErrors[i]}))},forceComplete:function(fitToWidth,rowHeight){var rowWidthWithoutSpacing=this.width-(this.items.length-1)*this.spacing,currentAspectRatio=this.items.reduce(function(sum,item){return sum+item.aspectRatio},0);"number"==typeof rowHeight?this.completeLayout(rowHeight,!1):fitToWidth?this.completeLayout(rowWidthWithoutSpacing/currentAspectRatio):this.completeLayout(this.targetRowHeight,!1)},getItems:function(){return this.items}}},{merge:2}],2:[function(require,module,exports){!function(isNode){function merge_recursive(base,extend){if("object"!==typeOf(base))return extend;for(var key in extend)"object"===typeOf(base[key])&&"object"===typeOf(extend[key])?base[key]=merge_recursive(base[key],extend[key]):base[key]=extend[key];return base}function merge(clone,recursive,argv){var result=argv[0],size=argv.length;(clone||"object"!==typeOf(result))&&(result={});for(var index=0;index<size;++index){var item=argv[index];if("object"===typeOf(item))for(var key in item){var sitem=clone?Public.clone(item[key]):item[key];result[key]=recursive?merge_recursive(result[key],sitem):sitem}}return result}function typeOf(input){return{}.toString.call(input).slice(8,-1).toLowerCase()}var Public=function(clone){return merge(!0===clone,!1,arguments)};Public.recursive=function(clone){return merge(!0===clone,!0,arguments)},Public.clone=function(input){var index,size,output=input,type=typeOf(input);if("array"===type)for(output=[],size=input.length,index=0;index<size;++index)output[index]=Public.clone(input[index]);else if("object"===type){output={};for(index in input)output[index]=Public.clone(input[index])}return output},isNode?module.exports=Public:window.merge=Public}("object"==typeof module&&module&&"object"==typeof module.exports&&module.exports)},{}],"justified-layout":[function(require,module,exports){"use strict";function computeLayout(itemLayoutData){var notAddedNotComplete,itemAdded,currentRow,nextToLastRowHeight,laidOutItems=[];return layoutConfig.forceAspectRatio&&itemLayoutData.forEach(function(itemData){itemData.forcedAspectRatio=!0,itemData.aspectRatio=layoutConfig.forceAspectRatio}),itemLayoutData.some(function(itemData,i){if(notAddedNotComplete=!1,currentRow||(currentRow=createNewRow()),itemAdded=currentRow.addItem(itemData),currentRow.isLayoutComplete()){if(laidOutItems=laidOutItems.concat(addRow(currentRow)),layoutData._rows.length>=layoutConfig.maxNumRows)return currentRow=null,!0;if(currentRow=createNewRow(),!itemAdded)if(itemAdded=currentRow.addItem(itemData),currentRow.isLayoutComplete()){if(laidOutItems=laidOutItems.concat(addRow(currentRow)),layoutData._rows.length>=layoutConfig.maxNumRows)return currentRow=null,!0;currentRow=createNewRow()}else itemAdded||(notAddedNotComplete=!0)}else itemAdded||(notAddedNotComplete=!0)}),currentRow&¤tRow.getItems().length&&layoutConfig.showWidows&&(layoutData._rows.length?(nextToLastRowHeight=layoutData._rows[layoutData._rows.length-1].isBreakoutRow?layoutData._rows[layoutData._rows.length-1].targetRowHeight:layoutData._rows[layoutData._rows.length-1].height,currentRow.forceComplete(!1,nextToLastRowHeight||layoutConfig.targetRowHeight)):currentRow.forceComplete(!1),laidOutItems=laidOutItems.concat(addRow(currentRow))),layoutData._containerHeight=layoutData._containerHeight-(layoutConfig.boxSpacing.vertical||layoutConfig.boxSpacing),layoutData._containerHeight=layoutData._containerHeight+(layoutConfig.containerPadding.bottom||layoutConfig.containerPadding),{containerHeight:layoutData._containerHeight,boxes:layoutData._layoutItems}}function createNewRow(){if(!1!==layoutConfig.fullWidthBreakoutRowCadence&&(layoutData._rows.length+1)%layoutConfig.fullWidthBreakoutRowCadence==0)var isBreakoutRow=!0;return new Row({top:layoutData._containerHeight,left:layoutConfig.containerPadding.left,width:layoutConfig.containerWidth-layoutConfig.containerPadding.left-layoutConfig.containerPadding.right,spacing:layoutConfig.boxSpacing.horizontal,targetRowHeight:layoutConfig.targetRowHeight,targetRowHeightTolerance:layoutConfig.targetRowHeightTolerance,edgeCaseMinRowHeight:.5*layoutConfig.targetRowHeight,edgeCaseMaxRowHeight:2*layoutConfig.targetRowHeight,rightToLeft:!1,isBreakoutRow:isBreakoutRow})}function addRow(row){return layoutData._rows.push(row),layoutData._layoutItems=layoutData._layoutItems.concat(row.getItems()),layoutData._containerHeight+=row.height+layoutConfig.boxSpacing.vertical,row.items}var merge=require("merge"),Row=require("./row"),layoutConfig={},layoutData={};module.exports=function(input){var config=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],defaults={containerWidth:1060,containerPadding:10,boxSpacing:10,targetRowHeight:320,targetRowHeightTolerance:.25,maxNumRows:Number.POSITIVE_INFINITY,forceAspectRatio:!1,showWidows:!0,fullWidthBreakoutRowCadence:!1};layoutConfig=merge(defaults,config);var containerPadding={},boxSpacing={};return containerPadding.top=isNaN(parseFloat(layoutConfig.containerPadding.top))?layoutConfig.containerPadding:layoutConfig.containerPadding.top,containerPadding.right=isNaN(parseFloat(layoutConfig.containerPadding.right))?layoutConfig.containerPadding:layoutConfig.containerPadding.right,containerPadding.bottom=isNaN(parseFloat(layoutConfig.containerPadding.bottom))?layoutConfig.containerPadding:layoutConfig.containerPadding.bottom,containerPadding.left=isNaN(parseFloat(layoutConfig.containerPadding.left))?layoutConfig.containerPadding:layoutConfig.containerPadding.left,boxSpacing.horizontal=isNaN(parseFloat(layoutConfig.boxSpacing.horizontal))?layoutConfig.boxSpacing:layoutConfig.boxSpacing.horizontal,boxSpacing.vertical=isNaN(parseFloat(layoutConfig.boxSpacing.vertical))?layoutConfig.boxSpacing:layoutConfig.boxSpacing.vertical,layoutConfig.containerPadding=containerPadding,layoutConfig.boxSpacing=boxSpacing,layoutData._layoutItems=[],layoutData._awakeItems=[],layoutData._inViewportItems=[],layoutData._leadingOrphans=[],layoutData._trailingOrphans=[],layoutData._containerHeight=layoutConfig.containerPadding.top,layoutData._rows=[],layoutData._orphans=[],computeLayout(input.map(function(item){return item.width&&item.width?{aspectRatio:item.width/item.height}:{aspectRatio:item}}))}},{"./row":1,merge:2}]},{},[]),angular.module("angular-justified-layout",[]),angular.module("angular-justified-layout").directive("justifiedLayout",function($log,$window){function _addPixels(value){return value+"px"}function _addItemsStyle(items,geometry){angular.forEach(items,function(item,index){var box=geometry.boxes[index],item=angular.isObject(item)?item:{width:box.width,height:box.height},style={width:_addPixels(box.width),height:_addPixels(box.height),top:_addPixels(box.top),left:_addPixels(box.left),position:"absolute"};item.style=angular.isObject(item.style)?angular.extend(item.style,style):style,items[index]=item})}var justifiedLayout=require("justified-layout"),defaults={containerPadding:5,boxSpacing:5};return{restrict:"E",replace:!0,transclude:!0,template:['<div class="justified-container">',"<ng-transclude>",'<div ng-repeat="item in items track by $index" class="box" ng-style="item.style">','<img ng-if="item.url" ng-src="{{ item.url }}" />',"</div>","</ng-transclude>","</div>"].join("\n"),scope:{items:"=",options:"=?"},link:function(scope,elem,attrs,ctrl,transclude){var geometry,collectionLength=0;elem.css({position:"relative"}),angular.isObject(scope.options)?scope.options=angular.extend({},defaults,scope.options):scope.options=angular.copy(defaults);var onResize=function(e){scope.options.containerWidth=elem[0].clientWidth,geometry=justifiedLayout(scope.items,scope.options),elem.css({height:_addPixels(geometry.containerHeight)}),_addItemsStyle(scope.items,geometry),scope.$apply()},collectionWatch=function(newVal){newVal&&newVal.length&&angular.isArray(newVal)&&(collectionLength=newVal.length,scope.options.containerWidth=elem[0].clientWidth,geometry=justifiedLayout(scope.items,scope.options),elem.css({height:_addPixels(geometry.containerHeight)}),_addItemsStyle(scope.items,geometry))};angular.element($window).on("resize",onResize),scope.$watchCollection("items",collectionWatch),scope.$on("$destroy",function(){angular.element($window).off("resize",onResize),collectionWatch()})}}});