diff --git a/examples/masonry.html b/examples/masonry.html new file mode 100644 index 0000000..20469a9 --- /dev/null +++ b/examples/masonry.html @@ -0,0 +1,222 @@ + + + + + + sorting + + + + + + + +

sorting

+ +
+

Sort

+ +
+ +
+ +
+

80

+

Hg

+

Mercury

+

200.59

+
+ +
+

52

+

Te

+

Tellurium

+

127.6

+
+ +
+

83

+

Bi

+

Bismuth

+

208.9804

+
+ +
+

48

+

Cd

+

Cadmium

+

112.411

+
+ +
+

20

+

Ca

+

Calcium

+

40.078

+
+ +
+

75

+

Re

+

Rhenium

+

186.207

+
+ +
+

81

+

Tl

+

Thallium

+

204.3833

+
+ +
+

51

+

Sb

+

Antimony

+

121.76

+
+ +
+

27

+

Co

+

Cobalt

+

58.933195

+
+ +
+

71

+

Lu

+

Lutetium

+

174.9668

+
+ +
+

18

+

Ar

+

Argon

+

39.948

+
+ +
+

37

+

Rb

+

Rubidium

+

85.4678

+
+ +
+

7

+

N

+

Nitrogen

+

14.0067

+
+ +
+

93

+

Np

+

Neptunium

+

(237)

+
+ +
+

89

+

Ac

+

Actinium

+

(227)

+
+
+ + + + + + + + + + + + + + + + + + + + diff --git a/isotope.js b/isotope.js index 3da2b6b..4b44e70 100644 --- a/isotope.js +++ b/isotope.js @@ -13,18 +13,26 @@ // -------------------------- helpers -------------------------- // +// extend objects +function extend( a, b ) { + for ( var prop in b ) { + a[ prop ] = b[ prop ]; + } + return a; +} + + // -------------------------- isotopeDefinition -------------------------- // // used for AMD definition and requires -function isotopeDefinition( Outlayer, getSize, matchesSelector, Item ) { +function isotopeDefinition( Outlayer, getSize, matchesSelector, Item, layoutMode ) { // create an Outlayer layout class var Isotope = Outlayer.create( 'isotope', { sortAscending: true }); Isotope.Item = Isotope.prototype.settings.item = Item; - - Isotope.layoutModes = {}; + Isotope.layoutMode = layoutMode; Isotope.prototype._create = function() { this.itemGUID = 0; @@ -34,7 +42,7 @@ function isotopeDefinition( Outlayer, getSize, matchesSelector, Item ) { // create layout modes this.modes = {}; // create from registered layout modes - for ( var name in Isotope.layoutModes ) { + for ( var name in layoutMode.modes ) { this._initLayoutMode( name ); } // keep of track of sortBys @@ -62,7 +70,12 @@ function isotopeDefinition( Outlayer, getSize, matchesSelector, Item ) { // -------------------------- layout -------------------------- // Isotope.prototype._initLayoutMode = function( name ) { - var LayoutMode = Isotope.layoutModes[ name ]; + var LayoutMode = layoutMode.modes[ name ]; + // set mode options + // HACK extend initial options, back-fill in default options + this.options[ name ] = LayoutMode.options ? + extend( LayoutMode.options, this.options[ name ] || {} ) : {}; + // init layout mode instance this.modes[ name ] = new LayoutMode( this ); }; @@ -222,10 +235,11 @@ function isotopeDefinition( Outlayer, getSize, matchesSelector, Item ) { if ( typeof define === 'function' && define.amd ) { // AMD define( [ - 'outlayer', - 'get-size', - 'matches-selector', - './item.js' + 'outlayer/outlayer', + 'get-size/get-size', + 'matches-selector/matches-selector', + './item.js', + './layout-modes.js' ], isotopeDefinition ); } else { @@ -234,7 +248,8 @@ if ( typeof define === 'function' && define.amd ) { window.Outlayer, window.getSize, window.matchesSelector, - window.Isotope.Item + window.Isotope.Item, + window.Isotope.layoutMode ); } diff --git a/layout-mode.js b/layout-mode.js index 06af062..4e701c6 100644 --- a/layout-mode.js +++ b/layout-mode.js @@ -4,20 +4,62 @@ // -------------------------- -------------------------- // -var Isotope = window.Isotope; +// var Isotope = window.Isotope; -Isotope.createLayoutMode = function( namespace, options ) { +var layoutMode = {}; + +layoutMode.options = {}; +layoutMode.modes = {}; + +layoutMode.create = function( namespace, options ) { function LayoutMode( isotope ) { this.isotope = isotope; - // link options to isotope.options - this.options = isotope && isotope.options[ this.namespace ]; + // link properties + if ( isotope ) { + this.options = isotope.options[ this.namespace ]; + console.log( this.options ); + this._getMeasurement = isotope._getMeasurement; + this.element = isotope.element; + this.items = isotope.items; + this.size = isotope.size; + // this.getSize = isotope.getSize; + // this._getElementOffset = isotope._getElementOffset; + } } + + // default options + if ( options ) { + LayoutMode.options = options; + } + + // Outlayer.prototype._getMeasurement = function( measurement, size ) { + // var option = this.options[ measurement ]; + // var elem; + // if ( !option ) { + // // default to 0 + // this[ measurement ] = 0; + // } else { + // if ( typeof option === 'string' ) { + // elem = this.element.querySelector( option ); + // } else if ( isElement( option ) ) { + // elem = option; + // } + // // use size of element, if element + // this[ measurement ] = elem ? getSize( elem )[ size ] : option; + // } + // }; + + + LayoutMode.prototype.namespace = namespace; // set default options - Isotope.prototype.options[ namespace ] = options || {}; + // layoutMode.options[ namespace ] = options || {}; // register in Isotope - Isotope.layoutModes[ namespace ] = LayoutMode; + layoutMode.modes[ namespace ] = LayoutMode; return LayoutMode; }; +var Isotope = window.Isotope = window.Isotope || {}; +Isotope.layoutMode = layoutMode; + })( window ); diff --git a/layout-modes/masonry.js b/layout-modes/masonry.js new file mode 100644 index 0000000..b2738c7 --- /dev/null +++ b/layout-modes/masonry.js @@ -0,0 +1,211 @@ +/*! + * Masonry v3.1.1 + * Cascading grid layout library + * http://masonry.desandro.com + * MIT License + * by David DeSandro + */ + +( function( window ) { + +'use strict'; + +// vars +// var document = window.document; + +// -------------------------- helpers -------------------------- // + +var indexOf = Array.prototype.indexOf ? + function( items, value ) { + return items.indexOf( value ); + } : + function ( items, value ) { + for ( var i=0, len = items.length; i < len; i++ ) { + var item = items[i]; + if ( item === value ) { + return i; + } + } + return -1; + }; + +// -------------------------- masonryDefinition -------------------------- // + +// used for AMD definition and requires +function masonryDefinition( layoutMode, getSize ) { + // create an Outlayer layout class + var Masonry = layoutMode.create('masonry'); + + Masonry.prototype._resetLayout = function() { + this.isotope.getSize(); + this._getMeasurement( 'columnWidth', 'outerWidth' ); + this._getMeasurement( 'gutter', 'outerWidth' ); + this.measureColumns(); + + // reset column Y + var i = this.cols; + this.colYs = []; + while (i--) { + this.colYs.push( 0 ); + } + + this.maxY = 0; + }; + + Masonry.prototype.measureColumns = function() { + var container = this._getSizingContainer(); + // if columnWidth is 0, default to outerWidth of first item + var firstItem = this.items[0]; + var firstItemElem = firstItem && firstItem.element; + if ( !this.columnWidth ) { + // columnWidth fall back to item of first element + this.columnWidth = firstItemElem ? getSize( firstItemElem ).outerWidth : + // or size of container + this.size.innerWidth; + } + this.columnWidth += this.gutter; + + this._containerWidth = getSize( container ).innerWidth; + this.cols = Math.floor( ( this._containerWidth + this.gutter ) / this.columnWidth ); + this.cols = Math.max( this.cols, 1 ); + }; + + Masonry.prototype._getSizingContainer = function() { + return this.options.isFitWidth ? this.element.parentNode : this.element; + }; + + Masonry.prototype._getItemLayoutPosition = function( item ) { + item.getSize(); + // how many columns does this brick span + var colSpan = Math.ceil( item.size.outerWidth / this.columnWidth ); + colSpan = Math.min( colSpan, this.cols ); + + var colGroup = this._getColGroup( colSpan ); + // get the minimum Y value from the columns + var minimumY = Math.min.apply( Math, colGroup ); + var shortColIndex = indexOf( colGroup, minimumY ); + + // position the brick + var position = { + x: this.columnWidth * shortColIndex, + y: minimumY + }; + + // apply setHeight to necessary columns + var setHeight = minimumY + item.size.outerHeight; + var setSpan = this.cols + 1 - colGroup.length; + for ( var i = 0; i < setSpan; i++ ) { + this.colYs[ shortColIndex + i ] = setHeight; + } + + return position; + }; + + /** + * @param {Number} colSpan - number of columns the element spans + * @returns {Array} colGroup + */ + Masonry.prototype._getColGroup = function( colSpan ) { + if ( colSpan === 1 ) { + // if brick spans only one column, use all the column Ys + return this.colYs; + } + + var colGroup = []; + // how many different places could this brick fit horizontally + var groupCount = this.cols + 1 - colSpan; + // for each group potential horizontal position + for ( var i = 0; i < groupCount; i++ ) { + // make an array of colY values for that one group + var groupColYs = this.colYs.slice( i, i + colSpan ); + // and get the max value of the array + colGroup[i] = Math.max.apply( Math, groupColYs ); + } + return colGroup; + }; + + Masonry.prototype._manageStamp = function( stamp ) { + var stampSize = getSize( stamp ); + var offset = this.isotope._getElementOffset( stamp ); + // get the columns that this stamp affects + var firstX = this.isotope.options.isOriginLeft ? offset.left : offset.right; + var lastX = firstX + stampSize.outerWidth; + var firstCol = Math.floor( firstX / this.columnWidth ); + firstCol = Math.max( 0, firstCol ); + var lastCol = Math.floor( lastX / this.columnWidth ); + lastCol = Math.min( this.cols - 1, lastCol ); + // set colYs to bottom of the stamp + var stampMaxY = ( this.isotope.options.isOriginTop ? offset.top : offset.bottom ) + + stampSize.outerHeight; + for ( var i = firstCol; i <= lastCol; i++ ) { + this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); + } + }; + + Masonry.prototype._getContainerSize = function() { + this.maxY = Math.max.apply( Math, this.colYs ); + var size = { + height: this.maxY + }; + + if ( this.options.isFitWidth ) { + size.width = this._getContainerFitWidth(); + } + + return size; + }; + + Masonry.prototype._getContainerFitWidth = function() { + var unusedCols = 0; + // count unused columns + var i = this.cols; + while ( --i ) { + if ( this.colYs[i] !== 0 ) { + break; + } + unusedCols++; + } + // fit container to columns that have been used + return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; + }; + + // debounced, layout on resize + // HEADS UP this overwrites Outlayer.resize + // Any changes in Outlayer.resize need to be manually added here + Masonry.prototype.resize = function() { + // don't trigger if size did not change + var container = this._getSizingContainer(); + var size = getSize( container ); + // check that this.size and size are there + // IE8 triggers resize on body size change, so they might not be + var hasSizes = this.size && size; + if ( hasSizes && size.innerWidth === this._containerWidth ) { + return; + } + + this.layout(); + + delete this.isotope.resizeTimeout; + }; + + return Masonry; +} + +// -------------------------- transport -------------------------- // + +if ( typeof define === 'function' && define.amd ) { + // AMD + define( [ + '../isotope', + 'get-size/get-size' + ], + masonryDefinition ); +} else { + // browser global + masonryDefinition( + window.Isotope.layoutMode, + window.getSize + ); +} + +})( window ); diff --git a/notes.md b/notes.md index c264b32..ffb28b7 100644 --- a/notes.md +++ b/notes.md @@ -11,3 +11,10 @@ filter on init doesn't do transition sortAscending sortAscending for object + + +--- + +set default options somewhere + +new layout mode comes with those options by default \ No newline at end of file