Hello everyone and I hope you're doing well. I am using Isotope and below you can see the JavaScript that I have written. I find it impossible to center li elements if they are the Isotope elements. To see what I mean by centering, please see the images below. I've managed to center the whole Isotope to the screen but I need the elements to be centered too and not just float to the left side.
Let's start with my script code:
<script>
$(document).ready(function(e) {
$(".ullist li").addClass('element-item');
});
</script>
<script>
$(document).ready(function(e) {
// external js: isotope.pkgd.js
// init Isotope
var $grid = $('.grid').isotope({
itemSelector: '.element-item',
//layoutMode: 'fitRows',
});
//$('.grid').isotope({ layoutMode : 'fitRows' });
// filter functions
var filterFns = {
// show if number is greater than 50
numberGreaterThan50: function() {
var number = $(this).find('.number').text();
return parseInt( number, 10 ) > 50;
},
// show if name ends with -ium
ium: function() {
var name = $(this).find('.name').text();
return name.match( /ium$/ );
}
};
// bind filter button click
$('#filters').on( 'click', 'a', function() {
var filterValue = $( this ).attr('data-filter');
// use filterFn if matches value
filterValue = filterFns[ filterValue ] || filterValue;
$grid.isotope({ filter: filterValue });
});
// change is-checked class on buttons
$('.secmenu ul a').each( function( i, buttonGroup ) {
var $buttonGroup = $( buttonGroup );
$buttonGroup.on( 'click', 'a', function() {
$buttonGroup.find('.is-checked').removeClass('is-checked');
$( this ).addClass('is-checked');
});
});});
</script>
<script>
$(function(){
var $container = $('.grid'),
$body = $('body'),
colW = 20,
columns = null;
$container.isotope({
// disable window resizing
resizable: true,
masonry: {
columnWidth: colW,
isFitWidth: true
}
});
$(window).smartresize(function(){
// check if columns has changed
var currentColumns = Math.floor( ( $body.width() -10 ) / colW );
if ( currentColumns !== columns ) {
// set new column count
columns = currentColumns;
// apply width to container manually, then trigger relayout
$container.width( columns * colW )
.isotope('reLayout');
}
}).smartresize(); // trigger resize to set container width
});
</script>
Basic HTML structure:
<ul class="ullist grid">
<li> ... </li>
<li> ... </li>
<li> ... </li>
<li> ... </li>
</ul>
Isotope works pretty well with no issues (so far). This is my current layout:
And this is the desired layout.
I even checked here and tried to use David DeSandro's repository but with no success. So please guys can you help me here to achieve the layout above?
Thank you all in advance.
jQuery isotope centering
You might need to add some extra markup and increase the number of columns that Isotope is fitting items into.
<ul class="ullist grid">
<li><span class="box">...</span></li>
<li><span class="box">...</span></li>
<li><span class="box">...</span></li>
<li><span class="box">...</span></li>
</ul>
You'll then set the number of columns to something that is divisible by both 2 and 3. If you create 6, you can have the first 6 li items span two columns, and the final two span 3:
Then, use CSS to position your .boxes within the li items.
This gets tricky if you don't know how many 'stray' items you'll have at the end - you might need to use javascript to figure this out, append a class (such as .span-2, .span-3, .span-6
The best solution for this is using the flex-box if you not concerned to support for old browsers(below IE8). Check this pen for flex-box solution codepen Link.
ul {
width: 600px;
list-style: none;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
li {
width: calc((100% / 3) - 60px);
height: 200px;
background-color: #d91c5c;
margin: 30px;
}`
Related
Several days ago I tried to incorporate Isotope into my site, and combine it with Fancybox 2 to create a nice looking gallery with filtering/sorting possibilities. Since many pages contain a lot of images, I prefer to show and append each image directly after it has finished loading rather than showing a loader until all images have been loaded.
In order to achieve this, I came up with this piece of code so far:
$( function() {
// init isotope
var $container = $('.isotope_container').isotope({
itemSelector: '.isotope_image',
layoutMode: 'fitRows',
transitionDuration: '0.7s'
});
// reveal initial images
$container.isotopeImagesReveal($('#images_container').find('.isotope_image'));
});
$.fn.isotopeImagesReveal = function( $items ) {
var iso = this.data('isotope');
var itemSelector = iso.options.itemSelector;
// hide by default
$items.hide();
// append to container
this.append( $items );
$items.imagesLoaded().progress( function( imgLoad, image ) {
// get item
// image is imagesLoaded class, not <img>, <img> is image.img
var $item = $( image.img ).parents( itemSelector );
// un-hide item
$item.show();
// isotope does its thing
iso.appended( $item );
});
return this;
};
});
The code above already does to some extent what I am after. It 'pulls' the images initially present in the <div id='images_container'>, and appends an item to isotope once an image has finished loading. The problem however is that the code appends and shows images in the order they finish loading (image loaded first becomes #1 in grid, then #2 etc.). Adding the sortby parameter to the isotope options does not work, as the images are not loaded at the point isotope is initiated. Re-sorting them with isotope after all images have been appended this way is possible, but looks very messy.
What I would like to achieve is to have the images loaded in the order they are present in the <div id='images_container'>. Chronologically when it comes to the original document order so to say. So basically start loading image 1, show and append it once it has been loaded. Then proceed to image 2, show and append it after loading, etc. until all images have been processed.
I think the solution is to alter the $.fn.isotopeImagesReveal function to process each of the div items in chronological order, but I can't figure out how.
Update: added example of current code. http://codepen.io/micksanders/pen/KwXmwO
Firstly you need to add a sorting field to your markup. I added a data-order="xxxx" attribute to all elements with the .isotope_image class, like so:
<div class='isotope_image' data-order="1">
<p>1</p>
<img src='http://lorempixel.com/600/600/sports'>
</div>
...
Then you need to add that sorting field to your isotope initialisation code... both the getSortData and sortBy options are needed:
var $container = $('.isotope_container').isotope({
itemSelector: '.isotope_image',
layoutMode: 'fitRows',
transitionDuration: '0.7s',
getSortData: {
order: "[data-order]"
},
sortBy: 'order'
});
Finally at the end of your imagesLoaded.progress() function, use iso.insert($item) instead of iso.appended($item).
Here's the full amended code:
http://codepen.io/BenStevens/pen/MYEmBb
$( function() {
var $container = $('#container').isotope({
itemSelector: '.item',
masonry: {
columnWidth: 200
}
});
$('#load-images').click( function() {
var $items = getItems();
$container.isotopeImagesReveal( $items );
});
});
$.fn.isotopeImagesReveal = function( $items ) {
var iso = this.data('isotope');
var itemSelector = iso.options.itemSelector;
// hide by default
$items.hide();
// append to container
this.append( $items );
$items.imagesLoaded().progress( function( imgLoad, image ) {
// get item
// image is imagesLoaded class, not <img>, <img> is image.img
var $item = $( image.img ).parents( itemSelector );
// un-hide item
$item.show();
// isotope does its thing
iso.appended( $item );
});
return this;
};
function randomInt( min, max ) {
return Math.floor( Math.random() * max + min );
}
function getItem() {
var width = randomInt( 150, 400 );
var height = randomInt( 150, 250 );
var item = '<div class="item">'+
'<img src="http://lorempixel.com/' +
width + '/' + height + '/nature" /></div>';
return item;
}
function getItems() {
var items = '';
for ( var i=0; i < 12; i++ ) {
items += getItem();
}
// return jQuery object
return $( items );
}
See reveal each image as they load
I am using this jquery plugin http://packery.metafizzy.co/ to create a dynamic grid layout. The plugin is working perfectly.
The problem is :
I am trying to create an option to add a dynamic grid on click event. If I hand code the html code for grid then the grid shows up perfectly but if I append the grid code to my template layout using jquery then the grid shows up from the very top of the layout and the plugin doesn't seem to adjust the grid position.
You can check my code and see the problem live here: http://jsfiddle.net/A7ubj/2/
I think the plugin is not adjusting the grid because my jquery append code is making the grid seat on the top.
Could you please tell me how to append the grid so that the plugin can adjust the grid perfectly?
This is how I am appending:
$(function(){
$('#myID').click(function(){
$( "#container" ).append( $( '<div class="item diff">Grid</div>' ) );
});
});
And this is my entire code:
JS:
<script src="http://code.jquery.com/jquery-1.10.2.min.js" type="text/javascript"></script>
<script src="packery.pkgd.min.js" type="text/javascript"></script>
<script>
$( document ).ready(function() {
var $container = $('#container');
// initialize
$container.packery({
itemSelector: '.item',
gutter: 10
});
});
</script>
<script>
$(function(){
$('#myID').click(function(){
$( "#container" ).append( $( '<div class="item diff">Grid</div>' ) );
});
});
</script>
CSS:
#container{
background-color:#F00;
width: 1130px;
margin:0px auto;
}
.item { width: 275px; background-color:#0C0;}
.item.w2 { width: 560px; background-color:#036; }
.diff{
min-height:300px;
}
.diff2{
min-height:250px;
}
HTML:
<button id="myID">Click</button>
<div id="container">
<div class="item diff">Grid</div>
<div class="item w2 diff2">Grid</div>
</div>
You can call packery.reload() or just use the packery initialization function again after you have append the images and to calculate every new image position. I use the masonry plugin and masonry.reload().
Update: To make masonry work with infinitescroll use a callback function: How to enable infinite scrolling with masonry?
Here is the code from my website. I use jquery templates and prepend. You can see that it call masonry('reload') after the prepend. It also init masonry from the new container. It also correct the width and the height of each image because I think there is an error in masonry. I think it's not really what you need because I don't cache the brick but I rebuild the entire container when I need it to show a new category. In your example you physically add a brick but I don't understand why it didn't work. The result is the same but not so clean.
$j.getJSON($j("#tag") function(response)
{
// Start masonry animated
if (response && response.length)
{
var container = $j('#container');
container.masonry({
itemSelector: '.brick',
columnWidth: brick_width,
isAnimated: !Modernizr.csstransitions
});
boxCount = response.length;
counter = 0;
$j.each(response, function(idx, ele)
{
container.prepend($j("#brickTemplate").tmpl(ele)).masonry('reload');
}
container.imagesLoaded(function()
{
$j("#brick").each(function()
{
var content = $j(this).find(">div");
var height = $j(this).find("img").attr("height");
if ( height == undefined )
{
content.css({
height: "300px"
});
} else {
content.css({
height: height
});
}
// bricks fade in
$j(this).delay(Math.floor(Math.random() * 1600)).fadeIn('slow');
// Bind Mousemove
$j(this).mousemove(function()
{
.....
}
}
}
}
I am referring to the following tutorial:
http://www.webdeveloperjuice.com/2011/08/07/how-to-fix-element-position-after-some-scroll-using-jquery/
While the demo in the page looks fine, but when I implement it on my site, I get the "jumping" effect. Often, the 1st item gets jumped, and straight to half of the 2nd item.
How do I fix this?
Below is my HTML:
<div id="map_container">
<div id="map" class="well"></div>
</div>
<ul>
<li>1. Many contents here...</li>
<li>2. Many contents here...</li>
<li>3. Many contents here...</li>
<li>4. Many contents here...</li>
<li>5. Many contents here...</li>
<li>6. Many contents here...</li>
<li>7. Many contents here...</li>
</ul>
The following is the Javascript:
$(document).ready( function(){
$('#map_container').css("width", $('#map').width());
$("#map_container").scrollFixed({hideBeforeDiv:'footer'});
});
(function($){
$.fn.scrollFixed = function(params){
params = $.extend( {appearAfterDiv: 0, hideBeforeDiv: 0}, params);
var element = $(this);
if(params.appearAfterDiv)
var distanceTop = element.offset().top + $(params.appearAfterDiv).outerHeight(true) + element.outerHeight(true);
else
var distanceTop = element.offset().top;
if(params.hideBeforeDiv)
var bottom = $(params.hideBeforeDiv).offset().top - element.outerHeight(true) - 10;
else
var bottom = 200000;
$(window).scroll(function(){
if( $(window).scrollTop() > distanceTop && $(window).scrollTop() < bottom )
element.css({'position':'fixed', 'top':'0'});
else
element.css({'position':'static'});
});
};
})(jQuery);
When Javascript dynamically adds a position: fixed to the #map_container, just use CSS to apply the same #map_container height to the first item of ul. The following solution is done using SCSS:
#map_container {
&.fixed {
position: fixed;
top: 0;
& ~ .ul .li:first-child {
margin-top: 210px;
}
}
I have 5 list items, when one is clicked the only method I know is to animate all the elements then reanimate the selected element to the new width. Can anyone advise me how I can cut down this process so only the current active item gets animated and the class removed and then the new item gets animated and the active class added?
JS
var test = $('#test'),
test_li = test.children(),
small = 60,
large = 200;
test_li.on('click', function(e) {
if( !$(this).hasClass('active') ){
test_li.animate({ width: small }, 300).removeClass('active'); //animates every single li every time
$(this).animate({ width: large }, 300).addClass('active');
}
});
Fiddle Here: http://jsfiddle.net/TSNtu/1/
var test = $('#test'),
test_li = test.children(),
small = 60,
large = 200;
test_li.on('click', function(e) {
// if clicked element is active itself then do nothing
if ($(this).hasClass('active')) return;
// remove active from others
$('.active', test).animate({
width: small
}, 300).removeClass('active');
// animate the clicked one
$(this).animate({
width: large
}, 300).addClass('active');
});
DEMO
With a single chain
var test = $('#test'),
test_li = test.children(),
small = 60,
large = 200;
test_li.on('click', function(e) {
// if clicked element is active itself then do nothing
if ($(this).hasClass('active')) return;
$(this) // clicked li
.animate({
width: large
}, 300)
.addClass('active')
.siblings('.active') // other li
.animate({
width: small
}, 300)
.removeClass('active');
});
DEMO
I'm trying to use jcarousel to build a container with multiple rows, I've tried a few things but have had no luck. Can anyone make any suggestions on how to create it?
This is .js code substitutions according to #Sike and a little additional of me, the height was not set dynamically, now it is.
var defaults = {
vertical: false,
rtl: false,
start: 1,
offset: 1,
size: null,
scroll: 3,
visible: null,
animation: 'normal',
easing: 'swing',
auto: 0,
wrap: null,
initCallback: null,
setupCallback: null,
reloadCallback: null,
itemLoadCallback: null,
itemFirstInCallback: null,
itemFirstOutCallback: null,
itemLastInCallback: null,
itemLastOutCallback: null,
itemVisibleInCallback: null,
itemVisibleOutCallback: null,
animationStepCallback: null,
buttonNextHTML: '<div></div>',
buttonPrevHTML: '<div></div>',
buttonNextEvent: 'click',
buttonPrevEvent: 'click',
buttonNextCallback: null,
buttonPrevCallback: null,
moduleWidth: null,
rows: null,
itemFallbackDimension: null
}, windowLoaded = false;
this.clip.addClass(this.className('jcarousel-clip')).css({
position: 'relative',
height: this.options.rows * this.options.moduleWidth
});
this.container.addClass(this.className('jcarousel-container')).css({
position: 'relative',
height: this.options.rows * this.options.moduleWidth
});
if (li.size() > 0) {
var moduleCount = li.size();
var wh = 0, j = this.options.offset;
wh = this.options.moduleWidth * Math.ceil(moduleCount / this.options.rows);
wh = wh + this.options.moduleWidth;
li.each(function() {
self.format(this, j++);
//wh += self.dimension(this, di);
});
this.list.css(this.wh, wh + 'px');
// Only set if not explicitly passed as option
if (!o || o.size === undefined) {
this.options.size = Math.ceil(li.size() / this.options.rows);
}
}
This is the call in using the static_sample.html of the code bundle in the download of jscarousel:
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('#mycarousel').jcarousel( {
scroll: 1,
moduleWidth: 75,
rows:2,
animation: 'slow'
});
});
</script>
In case you need to change the content of the carousel and reload the carousel you need to do this:
// Destroy contents of wrapper
$('.wrapper *').remove();
// Create UL list
$('.wrapper').append('<ul id="carousellist"></ul>')
// Load your items into the carousellist
for (var i = 0; i < 10; i++)
{
$('#carouselist').append('<li>Item ' + i + '</li>');
}
// Now apply carousel to list
jQuery('#carousellist').jcarousel({ // your config });
The carousel html definition needs to be like this:
<div class="wrapper">
<ul id="mycarousel0" class="jcarousel-skin-tango">
...<li></li>
</ul>
</div>
Thanks to Webcidentes
We have had to make a similar modifiaction. We do this by extending the default options, to include a rows value, and the width of each item (we call them modules) then divide the width by the number of rows.
Code added to jCarousel function...
Add to default options:
moduleWidth: null,
rows:null,
Then set when creating jCarousel:
$('.columns2.rows2 .mycarousel').jcarousel( {
scroll: 1,
moduleWidth: 290,
rows:2,
itemLoadCallback: tonyTest,
animation: 'slow'
});
The find and edit the lines in:
$.jcarousel = function(e, o) {
if (li.size() > 0) {
...
moduleCount = li.size();
wh = this.options.moduleWidth * Math.ceil( moduleCount / this.options.rows );
wh = wh + this.options.moduleWidth;
this.list.css(this.wh, wh + 'px');
// Only set if not explicitly passed as option
if (!o || o.size === undefined)
this.options.size = Math.ceil( li.size() / this.options.rows );
Hope this helps,
Tony Dillon
you might want to look at serialScroll or localScroll instead of jcarousel.
I found this post on Google Groups that has a working version for multiple rows. I have used this and it works great. http://groups.google.com/group/jquery-en/browse_thread/thread/2c7c4a86d19cadf9
I tried the above solutions and found changing the original jCarousel code to be troublesome - it introduced buggy behaviour for me because it didn't play nice with some of the features of jCarousel such as the continous looping etc.
I used another approach which works great and I thought others may benefit from it as well. It is the JS code I use to create the li items to support a jCarousel with multiple rows with elegant flow of items, i.e. fill horizontally, then vertically, then scrollpages:
123 | 789
456 | 0AB
It will add (value of var carouselRows) items to a single li and as such allows jCarousel to support multiple rows without modifying the original jCarousel code.
// Populate Album photos with support for multiple rows filling first columns, then rows, then pages
var carouselRows=3; // number of rows in the carousel
var carouselColumns=5 // number of columns per carousel page
var numItems=25; // the total number of items to display in jcarousel
for (var indexpage=0; indexpage<Math.ceil(numItems/(carouselRows*carouselColumns)); indexpage++) // for each carousel page
{
for (var indexcolumn = 0; indexcolumn<carouselColumns; indexcolumn++) // for each column on that carousel page
{
// handle cases with less columns than value of carouselColumns
if (indexcolumn<numItems-(indexpage*carouselRows*carouselColumns))
{
var li = document.createElement('li');
for (var indexrow = 0; indexrow < carouselRows; indexrow++) // for each row in that column
{
var indexitem = (indexpage*carouselRows*carouselColumns)+(indexrow*carouselColumns)+indexcolumn;
// handle cases where there is no item for the row below
if (indexitem<numItems)
{
var div = document.createElement('div'), img = document.createElement('img');
img.src = imagesArray[indexitem]; // replace this by your images source
div.appendChild(img);
li.appendChild(div);
}
}
$ul.append(li); // append to ul in the DOM
}
}
}
After this code has filled the ul with the li items jCarousel should be invoked.
Hope this helps someone.
Jonathan
If you need a quick solution for a fixed or one-off requirement that definitely doesn't involve changing core library code which may be updated from time to time, the following may suit. To turn the following six items into two rows on the carousel:
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
you can use a little JS to wrap the divs into LI groups of two then initialise the carousel. your scenario may allow you to do the grouping on the server isn't always possible. obviously you can extend this to however many rows you need.
var $pArr = $('div.item');
var pArrLen = $pArr.length;
for (var i = 0;i < pArrLen;i+=2){
$pArr.filter(':eq('+i+'),:eq('+(i+1)+')').wrapAll('<li />');
};