Making an Interactive Wall of Images With jQuery

February 2, 2012 at 5:48 pm By
Download Demo

Interactive jQuery Wall

This is a little jQuery experiment I put together, just for kicks! Here is a list of things I wanted the wall to do, and things you’ll be learning to do:

  1. Simple HTML without need for much editing
  2. Group these divs depending on the width of the page, into divs that change as you resize the window
  3. When resizing the window the image rows should change to display the maximum number of images, so it’ll work on the maximum number of screens.
  4. On hover they should expand and become bigger, they might also be linked. (possibly optional depending on your needs)
  5. If a row is incomplete, images should be added to the end to fill a row, so it looks like a continuous block.

Doesn’t sound too hard!

You’d be surprised. It actually turned out to be more difficult than I assumed! First things first, lets set up what our image holder is going to look like. So what I did was create a bunch of s each with an ID (its important you get these in the right order!), with a linked image inside.

Some simple HTML

</pre>
<div id="images"><span id="i1"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-1.jpg" alt="image-1" /></a></span>
 <span id="i2"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-2.jpg" alt="image-2" /></a></span>
 <span id="i3"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-3.jpg" alt="image-3" /></a></span>
 <span id="i4"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-4.jpg" alt="image-4" /></a></span>
 <span id="i5"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-5.jpg" alt="image-5" /></a></span>
 <span id="i6"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-6.jpg" alt="image-6" /></a></span>
 <span id="i7"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-7.jpg" alt="image-7" /></a></span>
 <span id="i8"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-8.jpg" alt="image-8" /></a></span>
 <span id="i9"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-3.jpg" alt="image-3" /></a></span>
 <span id="i10"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-1.jpg" alt="image-1" /></a></span>
 <span id="i11"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-2.jpg" alt="image-2" /></a></span>
 <span id="i12"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-12.jpg" alt="image-12" /></a></span>
 <span id="i13"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-4.jpg" alt="image-4" /></a></span>
 <span id="i14"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-3.jpg" alt="image-3" /></a></span>
 <span id="i15"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-5.jpg" alt="image-5" /></a></span>
 <span id="i16"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-6.jpg" alt="image-6" /></a></span>
 <span id="i17"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-5.jpg" alt="image-5" /></a></span>
 <span id="i18"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-8.jpg" alt="image-8" /></a></span>
 <span id="i19"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-6.jpg" alt="image-6" /></a></span>
 <span id="i20"><a href="http://www.html5canvastutorials.com/blog/"><img src="image-10.jpg" alt="image-10" /></a></span></div>
<pre>

Thats really it for the HTML. I wanted to keep it as simple as possible incase you wanted to add more images, or take some away. Next we need to add a tiny amount of CSS just to make everything look right at the end. If you were getting images from a database, this is where you’d pull the images to.

.. and a little CSS

body {
	margin: 0; padding: 0;
	font-family: Arial, Helvetica, sans-serif;
}

#images {
	white-space: nowrap;
	overflow: hidden;
	font-size: 0;
	line-height: 0;
}

#images span img {
	margin: 0;
	font-size: 15px;
	width: inherit;
	position: absolute;
	height: inherit;
	width: 100%;
	height: 100%;
}

#images span {
	display: inline-block;
	position: relative;
}

a img {
	border: 0;
}

#images span img:hover {
	box-shadow: 0px 0px 40px rgba(0,0,0,1);
}

Pretty basic stuff! Lets move onto the jQuery, where things get a little more tricky.

The jQuery

The skeleton of the code looks like this:

$(document).ready(function() {

	var imageWidth = 200;
	var imageHeight = 200;

	$('#images span').css({'width' : imageWidth, 'height' : imageHeight}); /* Set image width in JS so its easier */

	function imageNumber() { /* The function that does most of the work */

	}

	function hovering() { /* The hovering function */

	}

	/* So the initial wall looks right, run on launch */
	imageNumber();
	hovering();

	$(window).resize(function() { /* run functions on resize as well! */
		imageNumber();
		hovering();
	});

});

Lets take a look at the imageNumber() function first. To start, lets define some variables.

	var windowWidth = $(window).width();  /* The current width of the window */
	var numberOfImages = ($("#images span").length); /* The total number of images */
	var imagesPerRow = Math.ceil(windowWidth / imageWidth); /* The number of images that should be on each row */

Next we want to work out if every row has the same number of images. If they don’t we want to add some images to the end. So we start by checking if there’s a remainder when we divide the number of images by the number of images that should be on each row.

	if(numberOfImages % imagesPerRow != 0) {

Then we want to set two variables. One will be the number of images we need to add, and the other will be a variable for using in a while loop. Then we’ll run the while loop and clone the images until we’ve filled the row. The math for numberOnRow looks pretty complicated, but all we’re doing is getting the remainder, which is the percent we have, then taking it away from 1 to get the percent we need, and then multiplying it by the images in each row. Then we round it, because there’s no guarantee it’ll be an even number.


		var numberOnRow = Math.round((1 - (numberOfImages/imagesPerRow % 1)) * imagesPerRow);
		var number = 0;

		while(numberThe cloning was set to true so hover will work on new elements. We also added an appended class, so we can target these elements! So lets create two more variables, so we can add an ID to each of the new appended elements.
 		var nuAppended = $('.appended').length; 		var nextA = parseFloat(numberOfImages)+1; 		while(nuAppended > 0) {
			$('.appended').each(function() {
				$(this).attr('id', 'i'+nextA);
				++nextA;
				--nuAppended;
			});
		}
  	}
}

This gets the last image ID (i21 or something) and adds one to it. Then for each appended item we add a new ID to each.

Now that each of the divs have an ID we can add a wrapper round each row, using the number of images per row variable we added earlier.


  	var slices = $("#images span");
  	for(var i = 0; i < slices .length; i+=imagesPerRow) {
		slices .slice(i, i+imagesPerRow).wrapAll("</pre>
<div class="wrapper"></div>
<pre>
");
  	}

Now we have a problem! On resize its going to keep adding all of this stuff, and your computer is gonna freeze. So how do we fix this? The easiest way is to remove everything we’ve added at the start. So go back to the very start of the function and add this:


	$('.appended').remove();
	$('#images span').removeClass();

	$('.wrapper').each(function() {

		var wrapperContent = $(this).html();
		$(this).replaceWith(wrapperContent);

	});

This unwraps all the wrappers, and removes any classes or spans that we’ve added. The next bit is simple!

Hover function

This is just a bunch of simple hover functions selecting different images so that the images look correct when they expand. So your hover function will look this:

function hovering() {
	$('#images .wrapper span img').hover(function() {
		$(this).css({
			'width' : '150%',
			'height' : '150%',
			'z-index' : '7000'
		});
	}, function() {
		$(this).css({
			'height' : '100%',
			'width' : '100%',
			'box-shadow' : 'inset 0px 0px 20px rgba(0,0,0,0.8)',
			'z-index' : '2000'
		});
	});

	$('#images .wrapper:not(:first, :last) span:not(:first-child) img').hover(function() {
		$(this).css({
			'right' : '-25%',
			'bottom' : '-25%'
		});
	}, function() {
		$(this).css({
			'z-index' : '2000',
			'right' : '0',
			'bottom' : '0'
		});
	});

	$('#images .wrapper:first span:not(:first) img').hover(function() {
		$(this).css({
			'right' : '-25%',
			'top' : '0'
		});
	}, function() {
		$(this).css({
			'z-index' : '2000',
			'right' : '0',
			'bottom' : '0'
		});
	});

	$('#images .wrapper:first span:first-child img').hover(function() {
		$(this).css({
			'left' : '0',
			'top' : '0'
		});
	}, function() {
		$(this).css({
			'left' : '0',
			'top' : '0'
		});
	});

	$('#images .wrapper:not(:first, :last) span:first-child img').hover(function() {
		$(this).css({
			'left' : '0',
			'top' : '-25%'
		});
	}, function() {
		$(this).css({
			'left' : '0',
			'top' : '0'
		});
	});

	$('#images .wrapper:last span img:not(:first)').hover(function() {
		$(this).css({
			'left' : '-25%',
			'top' : '-50%'
		});
	}, function() {
		$(this).css({
			'left' : '0',
			'top' : '0',
		});
	});
	$('#images .wrapper:last span:first img').hover(function() {
		$(this).css({
			'left' : '0',
			'top' : '-50%'
		});
	}, function() {
		$(this).css({
			'left' : '0',
			'top' : '0'
		});
	});
}

Final jQuery

$(document).ready(function() {

	var imageWidth = 200;
	var imageHeight = 200;

	$('#images span').css({'width' : imageWidth, 'height' : imageHeight});

	function imageNumber() {

		$('.appended').remove();
		$('#images span').removeClass();

		$('.wrapper').each(function() {

			var wrapperContent = $(this).html();
			$(this).replaceWith(wrapperContent);

		});

		var windowWidth = $(window).width();
		var numberOfImages = ($("#images span").length);
		var imagesPerRow = Math.ceil(windowWidth / imageWidth);

		if(numberOfImages % imagesPerRow != 0) {

			var numberOnRow = Math.round((1 - (numberOfImages/imagesPerRow % 1)) * imagesPerRow);
			var number = 0;

			while(number  0) {
				$('.appended').each(function() {
					$(this).attr('id', 'i'+nextA);
					++nextA;
					--nuAppended;
				});
			}
  		}

  		var slices = $("#images span");
  		for(var i = 0; i < slices .length; i+=imagesPerRow) {
  			slices .slice(i, i+imagesPerRow).wrapAll("</pre>
<div class="wrapper"></div>
<pre>
");
  		}

	}

	function hovering() {
		$('#images .wrapper span img').hover(function() {
			$(this).css({
				'width' : '150%',
				'height' : '150%',
				'z-index' : '7000'
			});
		}, function() {
			$(this).css({
				'height' : '100%',
				'width' : '100%',
				'box-shadow' : 'inset 0px 0px 20px rgba(0,0,0,0.8)',
				'z-index' : '2000'
			});
		});

		$('#images .wrapper:not(:first, :last) span:not(:first-child) img').hover(function() {
			$(this).css({
				'right' : '-25%',
				'bottom' : '-25%'
			});
		}, function() {
			$(this).css({
				'z-index' : '2000',
				'right' : '0',
				'bottom' : '0'
			});
		});

		$('#images .wrapper:first span:not(:first) img').hover(function() {
			$(this).css({
				'right' : '-25%',
				'top' : '0'
			});
		}, function() {
			$(this).css({
				'z-index' : '2000',
				'right' : '0',
				'bottom' : '0'
			});
		});

		$('#images .wrapper:first span:first-child img').hover(function() {
			$(this).css({
				'left' : '0',
				'top' : '0'
			});
		}, function() {
			$(this).css({
				'left' : '0',
				'top' : '0'
			});
		});

		$('#images .wrapper:not(:first, :last) span:first-child img').hover(function() {
			$(this).css({
				'left' : '0',
				'top' : '-25%'
			});
		}, function() {
			$(this).css({
				'left' : '0',
				'top' : '0'
			});
		});

		$('#images .wrapper:last span img:not(:first)').hover(function() {
			$(this).css({
				'left' : '-25%',
				'top' : '-50%'
			});
		}, function() {
			$(this).css({
				'left' : '0',
				'top' : '0',
			});
		});

		$('#images .wrapper:last span:first img').hover(function() {
			$(this).css({
				'left' : '0',
				'top' : '-50%'
			});
		}, function() {
			$(this).css({
				'left' : '0',
				'top' : '0'
			});
		});
	}
	/* So the initial wall looks right */
	imageNumber();
	hovering();

	$(window).resize(function() {
		imageNumber();
		hovering();
	});

});

Now just include the file in the head of your document, with the jquery file:

<script type="text/javascript" src="jquery.js"></script><script type="text/javascript" src="jscript.js"></script>

And voila! That’s it. I also added some black bars to the top and bottom, just to tie everything together:

#bars {
	background: #000;
	width: 100%;
	color: #fff;
	font-weight: bold;
	position: relative;
	padding: 30px 0 30px 0 ;
	z-index: 10000;
	box-shadow: 0px 0px 40px rgba(0,0,0,1);
	font-size: 56px;
	text-align: center;
	font-family: 'Myriad Pro', Helvetica, Arial, sans-serif;
}

Go and download, tweet and check out the demo, to help us out!