Browse Source

add masonry; ka-jiggle layout-mode

pull/563/head
David DeSandro 12 years ago
parent
commit
63cca0f026
  1. 222
      examples/masonry.html
  2. 35
      isotope.js
  3. 54
      layout-mode.js
  4. 211
      layout-modes/masonry.js
  5. 7
      notes.md

222
examples/masonry.html

@ -0,0 +1,222 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>sorting</title>
<link rel="stylesheet" href="examples.css" />
<style>
.element.alkali { width: 170px; height: 120px; }
.element.alkaline-earth {}
.element.lanthanoid { height: 170px; }
.element.actinoid { width: 170px; }
.element.transition { height: 220px; }
/* .element.post-transition { background: #0FF; background: hsl( 180, 100%, 50%); }
.element.metalloid { background: #08F; background: hsl( 216, 100%, 50%); }
.element.other.nonmetal { background: #00F; background: hsl( 252, 100%, 50%); }
.element.halogen { background: #F0F; background: hsl( 288, 100%, 50%); }
.element.noble-gas { background: #F08; background: hsl( 324, 100%, 50%); }*/
</style>
</head>
<body>
<h1>sorting</h1>
<div id="options">
<h2>Sort</h2>
<ul class="option-set">
<li><a href="#original-order">original-order</a></li>
<li><a href="#number">number</a></li>
<li><a href="#name">name</a></li>
<li><a href="#symbol">symbol</a></li>
<li><a href="#weight">weight</a></li>
<li><a href="#category">category</a></li>
</ul>
</div>
<div id="container">
<div class="element transition metal " data-symbol="Hg" data-category="transition">
<p class="number">80</p>
<h3 class="symbol">Hg</h3>
<h2 class="name">Mercury</h2>
<p class="weight">200.59</p>
</div>
<div class="element metalloid " data-symbol="Te" data-category="metalloid">
<p class="number">52</p>
<h3 class="symbol">Te</h3>
<h2 class="name">Tellurium</h2>
<p class="weight">127.6</p>
</div>
<div class="element post-transition metal " data-symbol="Bi" data-category="post-transition">
<p class="number">83</p>
<h3 class="symbol">Bi</h3>
<h2 class="name">Bismuth</h2>
<p class="weight">208.9804</p>
</div>
<div class="element transition metal " data-symbol="Cd" data-category="transition">
<p class="number">48</p>
<h3 class="symbol">Cd</h3>
<h2 class="name">Cadmium</h2>
<p class="weight">112.411</p>
</div>
<div class="element alkaline-earth metal " data-symbol="Ca" data-category="alkaline-earth">
<p class="number">20</p>
<h3 class="symbol">Ca</h3>
<h2 class="name">Calcium</h2>
<p class="weight">40.078</p>
</div>
<div class="element transition metal " data-symbol="Re" data-category="transition">
<p class="number">75</p>
<h3 class="symbol">Re</h3>
<h2 class="name">Rhenium</h2>
<p class="weight">186.207</p>
</div>
<div class="element post-transition metal " data-symbol="Tl" data-category="post-transition">
<p class="number">81</p>
<h3 class="symbol">Tl</h3>
<h2 class="name">Thallium</h2>
<p class="weight">204.3833</p>
</div>
<div class="element metalloid " data-symbol="Sb" data-category="metalloid">
<p class="number">51</p>
<h3 class="symbol">Sb</h3>
<h2 class="name">Antimony</h2>
<p class="weight">121.76</p>
</div>
<div class="element transition metal " data-symbol="Co" data-category="transition">
<p class="number">27</p>
<h3 class="symbol">Co</h3>
<h2 class="name">Cobalt</h2>
<p class="weight">58.933195</p>
</div>
<div class="element lanthanoid metal inner-transition " data-symbol="Lu" data-category="lanthanoid">
<p class="number">71</p>
<h3 class="symbol">Lu</h3>
<h2 class="name">Lutetium</h2>
<p class="weight">174.9668</p>
</div>
<div class="element noble-gas nonmetal " data-symbol="Ar" data-category="noble-gas">
<p class="number">18</p>
<h3 class="symbol">Ar</h3>
<h2 class="name">Argon</h2>
<p class="weight">39.948</p>
</div>
<div class="element alkali metal " data-symbol="Rb" data-category="alkali">
<p class="number">37</p>
<h3 class="symbol">Rb</h3>
<h2 class="name">Rubidium</h2>
<p class="weight">85.4678</p>
</div>
<div class="element other nonmetal " data-symbol="N" data-category="other">
<p class="number">7</p>
<h3 class="symbol">N</h3>
<h2 class="name">Nitrogen</h2>
<p class="weight">14.0067</p>
</div>
<div class="element actinoid metal inner-transition " data-symbol="Np" data-category="actinoid">
<p class="number">93</p>
<h3 class="symbol">Np</h3>
<h2 class="name">Neptunium</h2>
<p class="weight">(237)</p>
</div>
<div class="element actinoid metal inner-transition " data-symbol="Ac" data-category="actinoid">
<p class="number">89</p>
<h3 class="symbol">Ac</h3>
<h2 class="name">Actinium</h2>
<p class="weight">(227)</p>
</div>
</div>
<script src="../bower_components/eventEmitter/EventEmitter.js"></script>
<script src="../bower_components/eventie/eventie.js"></script>
<script src="../bower_components/doc-ready/doc-ready.js"></script>
<script src="../bower_components/get-style-property/get-style-property.js"></script>
<script src="../bower_components/get-size/get-size.js"></script>
<script src="../bower_components/jquery-bridget/jquery.bridget.js"></script>
<script src="../bower_components/matches-selector/matches-selector.js"></script>
<script src="../bower_components/outlayer/item.js"></script>
<script src="../bower_components/outlayer/outlayer.js"></script>
<script src="../item.js"></script>
<script src="../layout-mode.js"></script>
<script src="../isotope.js"></script>
<script src="../layout-modes/masonry.js"></script>
<script>
docReady( function() {
var container = document.querySelector('#container');
var iso = window.iso = new Isotope( container, {
layoutMode: 'masonry',
masonry: {
columnWidth: 120
},
getSortData: {
// number: function( itemElem ) {
// return parseInt( getText( itemElem.querySelector('.number') ), 10 );
// },
// symbol: function( itemElem ) {
// return getText( itemElem.querySelector('.symbol') );
// },
// name: function( itemElem ) {
// return getText( itemElem.querySelector('.name') );
// },
// category: function( itemElem ) {
// return itemElem.getAttribute('data-category');
// },
number: '.number parseInt',
symbol: '.symbol',
name: '.name',
category: '[data-category]',
weight: function( itemElem ) {
// remove parenthesis
return parseFloat( getText( itemElem.querySelector('.weight') ).replace( /[\(\)]/g, '') );
}
}
});
var options = document.querySelector('#options');
eventie.bind( options, 'click', function( event ) {
if ( !matchesSelector( event.target, 'a' ) ) {
return;
}
// use link's href, remove leading hash
var sortBy = event.target.getAttribute('href').slice( 1 );
sortBy.slice( 0, 1 );
iso.options.sortBy = sortBy;
iso.layout();
event.preventDefault();
});
});
function getText( elem ) {
return elem.textContent || elem.innerText;
}
</script>
</body>
</html>

35
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
);
}

54
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 );

211
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 );

7
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
Loading…
Cancel
Save