Converted layout method to masonry style

pull/56/head
Glen Cheeny 12 years ago
parent a5c1d6f232
commit 8e03097e1a

@ -182,7 +182,7 @@
<code class="language-javascript">
var options = {
group : 'all' // Which category to show
speed : 800, // Speed of the transition (in milliseconds). 800 = .8 seconds
speed : 600, // Speed of the transition (in milliseconds). 800 = .8 seconds
easing : 'ease-out' // css easing function to use
};
</code>
@ -227,16 +227,8 @@ var options = {
</code>
</pre>
<p>Shuffle takes the width, margin-top, and marigin-right from the <code class="language-css token selector">.item</code>.</p>
<pre rel="CSS">
<code class="language-css">
#grid .item {
width: 230px;
margin-top: 20px;
margin-right: 20px;
}
</code>
</pre>
<p>The <code>columnWidth</code> option is used to calculate the column width. This option <strong style="text-decoration:underline;">can be a function</strong> for responsive layouts. If it's not a function, it uses jQuery's <code class="language-javascript">outerWidth(true)</code> to calculate the column width (this includes margins). If the <code>columnWidth</code> option isn't specified, the width will be the width of the first item.</p>
<p>Sets up the button clicks and runs shuffle</p>
<pre rel="jQuery">
@ -257,11 +249,7 @@ $(document).ready(function(){
});
// instantiate the plugin
$('#grid').shuffle({
group : 'all',
speed : 800,
easing : 'ease-out'
});
$('#grid').shuffle();
});
</code>
</pre>
@ -484,11 +472,7 @@ $('.filter .search').on('keyup change', function() {
});
// instantiate the plugin
$('#grid').shuffle({
group : 'all',
speed : 800,
easing : 'ease-out'
});
$('#grid').shuffle();
// Destroy it! o_O
// $('#grid').shuffle('destroy');

@ -12,8 +12,8 @@
* Inspired by Isotope http://isotope.metafizzy.co/
* Use it for whatever you want!
* @author Glen Cheney (http://glencheney.com)
* @version 1.5.2
* @date 10/24/12
* @version 1.6
* @date 11/2/12
*/
;(function($, Modernizr) {
'use strict';
@ -52,12 +52,16 @@
self.$container = $container;
self.$items = self.$container.children();
self.$item = self.$items.first();
self.marginTop = parseInt(self.$item.css('marginTop'), 10);
self.marginRight = parseInt(self.$item.css('marginRight'), 10);
self.transitionName = self.prefixed('transition'),
self.transform = self.getPrefixed('transform');
// Get offset from container
self.offset = {
left: parseInt( ( self.$container.css('padding-left') || 0 ), 10 ),
top: parseInt( ( self.$container.css('padding-top') || 0 ), 10 )
};
self.isFluid = self.columnWidth && typeof self.columnWidth === 'function';
// Get transitionend event name
var transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
@ -85,16 +89,7 @@
if (self.supported) {
this.style[self.transitionName] = self.transform + ' ' + self.speed + 'ms ' + self.easing + ', opacity ' + self.speed + 'ms ' + self.easing;
}
// Remove margins, we don't need them anymore
this.style.marginTop = 0;
this.style.marginRight = 0;
});
// Get dimensions of the first item and items per row
self.itemWidth = self.$item.outerWidth();
self.itemHeight = self.$item.outerHeight();
self.itemsPerRow = self.getItemsPerRow();
// http://stackoverflow.com/questions/1852751/window-resize-event-firing-in-internet-explorer
self.windowHeight = $(window).height();
@ -110,17 +105,9 @@
}
});
// If our calculated values are 0 (maybe images haven't loaded), wait until window load
if (self.itemWidth === 0 || self.itemHeight === 0) {
$(window).on('load.shuffle', function() {
self.itemWidth = self.$item.outerWidth();
self.itemHeight = self.$item.outerHeight();
self.itemsPerRow = self.getItemsPerRow();
self.shuffle(self.group);
})
} else {
self.shuffle(self.group);
}
self._getColumns();
self._resetCols();
self.shuffle( self.group );
};
Shuffle.prototype = {
@ -144,8 +131,9 @@
// whether to hide it or not.
if ($.isFunction(category)) {
self.$items.each(function() {
var $item = $(this);
$item.addClass(category($item, self) ? 'filtered' : 'concealed');
var $item = $(this),
passes = category.call($item[0], $item, self);
$item.addClass(passes ? 'filtered' : 'concealed');
});
}
@ -164,14 +152,16 @@
});
}
// category === all, add filtered class to everything
// category === 'all', add filtered class to everything
else {
self.$items.addClass('filtered');
}
}
// How many filtered elements?
self.visibleItems = self.$items.filter('.filtered').length;
// self.visibleItems = self.$items.filter('.filtered').length;
self._resetCols();
// Shrink each concealed item
self.fire('shrink');
@ -180,37 +170,49 @@
// Update transforms on .filtered elements so they will animate to their new positions
self.fire('filter');
self.filter();
// Adjust the height of the container
self.resizeContainer();
},
getItemsPerRow : function() {
// calculates number of columns
// i.e. this.colWidth = 200
_getColumns : function() {
var self = this,
totalWidth = self.$container.width(),
num = Math.floor(totalWidth / self.itemWidth);
containerWidth = self.$container.width(),
gutter = typeof self.gutterWidth === 'function' ? self.gutterWidth( containerWidth ) :
// Option explicitly set?
self.gutterWidth || 0;
// console.log();
// use fluid columnWidth function if there
self.colWidth = self.isFluid ? self.columnWidth( containerWidth ) :
// if not, how about the explicitly set option?
self.columnWidth ||
// or use the size of the first item
self.$items.outerWidth(true) ||
// if there's no items, use size of container
containerWidth;
// console.log(self.colWidth, gutter, self.colWidth + gutter);
self.colWidth += gutter;
// Make sure the items will fit with margins too
if (num * (self.itemWidth + self.marginRight) - self.marginRight > totalWidth) {
num -= 1;
}
return num;
self.cols = Math.floor( ( containerWidth + gutter ) / self.colWidth );
self.cols = Math.max( self.cols, 1 );
},
/**
* Adjust the height of the grid
*/
resizeContainer : function() {
setContainerSize : function() {
var self = this,
gridHeight = (Math.ceil(self.visibleItems / self.itemsPerRow) * (self.itemHeight + self.marginTop)) - self.marginTop;
self.$container.css('height', gridHeight + 'px');
gridHeight = Math.max.apply( Math, self.colYs );
self.$container.css( 'height', gridHeight + 'px' );
},
/**
* Fire events with .shuffle namespace
*/
fire : function(name) {
fire : function( name ) {
this.$container.trigger(name + '.shuffle', [this]);
},
@ -229,8 +231,8 @@
self.shrinkTransitionEnded = false;
$concealed.each(function() {
var $this = $(this),
x = parseInt($this.attr('data-x'), 10),
y = parseInt($this.attr('data-y'), 10);
x = parseInt($this.data('x'), 10),
y = parseInt($this.data('y'), 10);
if (!x) x = 0;
if (!y) y = 0;
@ -240,12 +242,12 @@
$this: $this,
x: x,
y: y,
left: (x + (self.itemWidth / 2)) + 'px',
top: (y + (self.itemHeight / 2)) + 'px',
left: (x + ($this.outerWidth(true) / 2)) + 'px',
top: (y + ($this.outerHeight(true) / 2)) + 'px',
scale : 0.001,
opacity: 0,
height: '0px',
width: '0px',
height: 0,
width: 0,
callback: self.shrinkEnd
});
});
@ -259,9 +261,8 @@
* Because jQuery collection are always ordered in DOM order, we can't pass a jq collection
* @param {function} complete callback function
*/
layout: function(items, fn) {
var self = this,
y = 0;
layout: function( items, fn ) {
var self = this;
// Abort if no items
if (items.length === 0) {
@ -271,30 +272,102 @@
self.layoutTransitionEnded = false;
$.each(items, function(index) {
var $this = $(items[index]),
x = (index % self.itemsPerRow) * (self.itemWidth + self.marginRight),
row = Math.floor(index / self.itemsPerRow);
//how many columns does this brick span
colSpan = Math.ceil( $this.outerWidth(true) / self.colWidth );
colSpan = Math.min( colSpan, self.cols );
// console.log('colSpan: ', colSpan);
if (index % self.itemsPerRow === 0) {
y = row * (self.itemHeight + self.marginTop);
if ( colSpan === 1 ) {
// if brick spans only one column, just like singleMode
self._placeItem( $this, self.colYs, fn );
} else {
// brick spans more than one column
// how many different places could this brick fit horizontally
var groupCount = self.cols + 1 - colSpan,
groupY = [],
groupColY,
i;
// for each group potential horizontal position
for ( i = 0; i < groupCount; i++ ) {
// make an array of colY values for that one group
groupColY = self.colYs.slice( i, i + colSpan );
// and get the max value of the array
groupY[i] = Math.max.apply( Math, groupColY );
}
self._placeItem( $this, groupY, fn );
}
});
// Save data for shrink
$this.attr({'data-x' : x, 'data-y' : y});
// Adjust the height of the container
self.setContainerSize();
},
self.transition({
from: 'layout',
$this: $this,
x: x,
y: y,
left: x + 'px',
top: y + 'px',
scale : 1,
opacity: 1,
height: self.itemHeight + 'px',
width: self.itemWidth + 'px',
callback: fn
});
_resetCols : function() {
// reset columns
var i = this.cols;
this.colYs = [];
while (i--) {
this.colYs.push( 0 );
}
},
_reLayout : function( callback ) {
callback = callback || this.filterEnd;
this._resetCols();
// apply layout logic to all bricks
this.layout( this.$items.get(), callback );
},
// worker method that places brick in the columnSet with the the minY
_placeItem : function( $item, setY, callback ) {
// get the minimum Y value from the columns
var self = this,
minimumY = Math.min.apply( Math, setY ),
shortCol = 0;
// Find index of short column, the first from the left where this item will go
for (var i = 0, len = setY.length; i < len; i++) {
if ( setY[i] === minimumY ) {
shortCol = i;
break;
}
}
// console.log('shortCol: ', shortCol, 'minimumY: ', minimumY);
// Position the item
var x = self.colWidth * shortCol,
y = minimumY;
x = Math.round( x + self.offset.left );
y = Math.round( y + self.offset.top );
// Save data for shrink
$item.data( {x: x, y: y} );
// Apply setHeight to necessary columns
var setHeight = minimumY + $item.outerHeight(true),
setSpan = self.cols + 1 - len;
for ( i = 0; i < setSpan; i++ ) {
self.colYs[ shortCol + i ] = setHeight;
}
self.transition({
from: 'layout',
$this: $item,
x: x,
y: y,
left: x + 'px',
top: y + 'px',
scale : 1,
opacity: 1,
height: $item.outerHeight(true) + 'px',
width: $item.outerWidth(true) + 'px',
callback: callback
});
},
/**
@ -320,6 +393,7 @@
sort: function(opts, fromFilter) {
var self = this,
items = self.$items.filter('.filtered').sorted(opts);
self._resetCols();
self.layout(items, function() {
if (fromFilter) {
self.filterEnd();
@ -370,7 +444,6 @@
transition: function(opts) {
var self = this,
transform,
// Only fire callback once per collection's transition
complete = function() {
if (!self.layoutTransitionEnded && opts.from === 'layout') {
@ -382,7 +455,6 @@
}
};
// Use CSS Transforms if we have them
if (self.supported) {
if (self.threeD) {
@ -408,15 +480,12 @@
},
/**
* On window resize, recalculate the width, height, and items per row.
* Relayout everthing
*/
resized: function() {
var self = this;
self.itemWidth = self.$items.filter('.filtered').outerWidth();
self.itemHeight = self.$items.filter('.filtered').outerHeight();
self.itemsPerRow = self.getItemsPerRow();
self.filter();
self.resizeContainer();
// get updated colCount
this._getColumns();
this._reLayout();
},
shrinkEnd: function() {
@ -436,7 +505,14 @@
self.$container.removeAttr('style').removeData('shuffle');
$(window).off('.shuffle');
self.$items.removeAttr('style data-y data-x').removeClass('concealed filtered');
self.$items.removeAttr('style').removeClass('concealed filtered');
},
update: function() {
var self = this;
self.$items = self.$container.children();
self.resized();
}
};
@ -464,6 +540,8 @@
shuffle.sort(sortObj);
} else if (opts === 'destroy') {
shuffle.destroy();
} else if (opts === 'update') {
shuffle.update();
} else {
shuffle.shuffle(opts);
}
@ -474,7 +552,7 @@
// Overrideable options
$.fn.shuffle.options = {
group : 'all',
speed : 800,
speed : 600,
easing : 'ease-out',
keepSorted: true
};

@ -15,13 +15,6 @@
<!--[if lt IE 9]>
<script src="js/html5shiv.js"></script>
<![endif]-->
<style>
#grid > div {
margin-right: 5px;
margin-top: 5px;
}
</style>
</head>
<body>
<div class="container container-main">

Loading…
Cancel
Save