I'm doing an eshop with goods displayed as "tiles" in grid as usual. I just want to use various sizes of tiles and make sure (via jQuery) there are no free spaces.
In basic situation, I have a 960px wrapper and want to use 240x180px (class .grid_4) tiles and 480x360px (class .grid_8) tiles. See image (imagine no margins/paddings there):
alt text http://img580.imageshack.us/img580/2828/screenshot2010041508h52.png
Problems without jQuery:
- when the CMS provides the big tile as 6th, there would be a free space under the 5th one
- when the CMS provides the big tile as 7th, there would be a free space under 5th and 6th
- when the CMS provides the big tile as 8th, it would shift to next line, leaving position no.8 free
My solution so far looks like this:
$(".grid_8").each(function(){
//console.log("BIG on position "+($(this).index()+1)+" which is "+(($(this).index()+1)%2?"ODD":"EVEN"));
switch (($(this).index()+1)%4) {
case 1:
// nothing needed
//console.log("case 1");
break;
case 2:
//need to shift one position and wrap into 240px div
//console.log("case 2");
$(this).insertAfter($(this).next()); //swaps this with next
$(this).prevAll(":nth(0), :nth(1)").wrapAll("<div class=\"grid_4\" />");
break;
case 3:
//need to shift two positions and wrap into 480px div
//console.log("case 3");
$(this).prevAll(":nth(0), :nth(1)").wrapAll("<div class=\"grid_4\" />"); //wraps previous two - forcing them into column
$(this).nextAll(":nth(0), :nth(1)").wrapAll("<div class=\"grid_4\" />"); //wraps next two - forcing them into column
$(this).insertAfter($(this).next()); //moves behind the second column
break;
case 0:
//need to shift one position
//console.log("case 4");
$(this).insertAfter($(this).next());
//console.log("shifted to next line");
break;
}
});
It should be obvious from the comments how it works - generally always makes sure that the big tile is on odd position (count of preceding small tiles is even) by shifting one position back if needed. Also small tiles to the left from the big one need to be wrapped 开发者_开发百科in another div so that they appear in column rather than row.
Now finally the questions:
- how to generalize the function so that I can use even more tile dimensions like 720x360 (3x2), 480x540 (2x3), etc.?
- is there a way to simplify the function?
- I need to make sure that big tile counts as a multiple of small tiles when checking the actual position. Because using index() on the tile on position 12 (last tile in 3rd row) would now return 7 (position 8) because tiles on positions 5 and 9 are wrapped together in one column and the big tile is also just a single div, but spans 2x2 positions. Any clean way to ensure this?
Thank you very much for any hints. Feel free to reuse the code, I think it can be useful.
Josef
Sounds like you need to use the jQuery plugin called masonry.
You can find it here
Is this simplified enough for you?
$(".grid_8")
.each(function () {
switch (($(this)
.index() + 1) % 4) {
case 1:
break;
case 2:
$(this)
.insertAfter($(this)
.next()), $(this)
.prevAll(":nth(0), :nth(1)")
.wrapAll('<div class="grid_4" />');
break;
case 3:
$(this)
.prevAll(":nth(0), :nth(1)")
.wrapAll('<div class="grid_4" />'), $(this)
.nextAll(":nth(0), :nth(1)")
.wrapAll('<div class="grid_4" />'), $(this)
.insertAfter($(this)
.next());
break;
case 0:
$(this)
.insertAfter($(this)
.next())
}
})
精彩评论