Draggable Image Boxes Grid

Today we want to create a template with a fullscreen grid of images and content areas. The idea is to have a draggable grid that shows boxes of thumbnails and menu like items. Once clicked, the thumbnail will expand to the full size image and the menu item box will expand to a fullscreen content area.

Draggable Image Boxes Grid

Today we want to create a template with a fullscreen grid of images and content areas. The idea is to have a draggable grid that shows boxes of thumbnails and menu like items. Once clicked, the thumbnail will expand to the full size image and the menu item box will expand to a fullscreen content area.

The main idea for this template and its effects comes from the beautiful Flash-based website of Stephen Hamilton.

To make the grid draggable, we used jQuery.kinetic by Dave Taylor. The jQuery plugin allows smooth drag scrolling and it’s just what we need in our grid.

The beautiful images in the demo are by Ibrahim Iujaz. Check out his Flickr photostream.

So, let’s begin!

The Markup

The main container will be a div with the class and ID ib-main-wrapper. We will add another div element inside since we will need this structure for applying the jQuery.kinetic plugin. Inside of that div which has the class ib-main, we will place two types of link elements: the thumbnail links and the content links. The content links are the menu like boxes that will expand to a fullscreen content area:

<div id="ib-main-wrapper" class="ib-main-wrapper">
	<div class="ib-main">
		<a href="#">
			<img src="images/thumbs/1.jpg" data-largesrc="images/large/1.jpg" alt="image01"/>
			<span>Crabbed Age and Youth</span>
		</a>
		<a href="#">
			<img src="images/thumbs/2.jpg" data-largesrc="images/large/2.jpg" alt="image02"/>
			<span>Cannot live together</span>
		</a>
		<a href="#" class="ib-content">
			<div class="ib-teaser">
				<h2>Welcome <span>Howdy, Stranger</span></h2>
			</div>
			<div class="ib-content-full">
				<!-- Some content -->
			</div>
		</a>
		...
	</div>
</div>

The boxes for the content will have the class ib-content. The path to the large image for the thumbnails will be saved in the data attribute data-largesrc.

For the content and image preview we will use jQuery templates. The template for the large image preview is the following:

<div id="ib-img-preview" class="ib-preview">
	<img src="${src}" alt="" class="ib-preview-img"/>
	<span class="ib-preview-descr" style="display:none;">${description}</span>
	<div class="ib-nav" style="display:none;">
		<span class="ib-nav-prev">Previous</span>
		<span class="ib-nav-next">Next</span>
	</div>
	<span class="ib-close" style="display:none;">Close Preview</span>
	<div class="ib-loading-large" style="display:none;">Loading...</div>
</div>	

We will have the large image, the navigation buttons, a closing cross and a loading element.

The template for the fullscreen content preview looks like this:

<div id="ib-content-preview" class="ib-content-preview">
	<div class="ib-teaser" style="display:none;">{{html teaser}}</div>
	<div class="ib-content-full" style="display:none;">{{html content}}</div>
	<span class="ib-close" style="display:none;">Close Preview</span>
</div>

Now, let’s style the grid.

The CSS

First, we will style the wrapping container. It will occupy all the page’s width and we will set the height dynamically to fit the visible area:

.ib-main-wrapper{
    width: 100%;
    overflow: hidden;
    margin-top: 40px;
    outline: none;
    /*height dynamic*/
}

The main container will have a preset width. We chose this value because we want most visitors to be able to actually drag the grid. If you would set it to less and the user has a larger screen, then the container would be too small:

.ib-main{
    position: relative;
    width: 2546px;
}

Each box element will be floating and have a background image (for the thumbs) that we’ll stretch to be a bit larger than the box. We’ll add a nice transition which will make the background image contract on hover:

.ib-main a{
    float: left;
    width: 210px;
    height: 210px;
    position: relative;
    overflow: hidden;
    margin: 0px 0px 2px 2px;
    cursor: move;
    background: #fff url(../images/thumb_bg.jpg) no-repeat center center;
    background-size: 110% 110%;
    -webkit-transition: all 0.2s ease-in-out;
    -moz-transition: all 0.2s ease-in-out;
    -o-transition: all 0.2s ease-in-out;
    -ms-transition: all 0.2s ease-in-out;
    transition: all 0.2s ease-in-out;
}
.ib-main a:hover{
    background-size: 100% 100%;
}

The thumbnail will be slightly transparent so that we can see the background image (which is a thick border). We’ll also add some CSS3 transition here to animate the opacity on hover:

.ib-main a img{
    opacity: 0.95;
    -webkit-transition: all 0.2s ease-in-out;
    -moz-transition: all 0.2s ease-in-out;
    -o-transition: all 0.2s ease-in-out;
    -ms-transition: all 0.2s ease-in-out;
    transition: all 0.2s ease-in-out;
}
.ib-main a:hover img{
    opacity: 0.8;
}

The description will be positioned absolutely and we’ll place it out of the box. Then, on hover, we will make it slide in:

.ib-main > a > span{
    display: block;
    position: absolute;
    width: 100%;
    height: 20px;
    line-height: 22px;
    text-align: center;
    font-size: 11px;
    bottom: -20px;
    left: 0px;
    text-shadow: 1px 1px 1px rgba(0,0,0,0.4);
    -webkit-transition: all 0.2s ease-in-out;
    -moz-transition: all 0.2s ease-in-out;
    -o-transition: all 0.2s ease-in-out;
    -ms-transition: all 0.2s ease-in-out;
    transition: all 0.2s ease-in-out;
}
.ib-main a:hover > span{
    bottom: 0px;
}

When we click on the thumbnail box, we’ll change the background image in order to show the loading image:

.ib-main a.ib-loading,
.ib-main a.ib-loading:hover{
    background: #fff url(../images/ajax-loader.gif) no-repeat center center;
    background-size: 31px 31px;
}
.ib-main a.ib-loading img,
.ib-main a.ib-loading:hover img{
    opacity: 0.5;
}

When the thumbnail is in the loading state, we don’t want to show the description:

.ib-main > a.ib-loading > span,
.ib-main a.ib-loading > span{
    display: none;
}

Now we’ll style the content boxes. The background is going to be dark:

.ib-content{
    background: #f9f9f9;
}

The teaser is the text we’ll be showing in each content box. On hover we want to animate the background color:

.ib-content .ib-teaser{
    text-align: center;
    background: #333;
    width: 100%;
    height: 100%;
    -webkit-transition: all 0.2s ease-in-out;
    -moz-transition: all 0.2s ease-in-out;
    -o-transition: all 0.2s ease-in-out;
    -ms-transition: all 0.2s ease-in-out;
    transition: all 0.2s ease-in-out;
}
.ib-content .ib-teaser:hover{
    background: #000;
}

The headline and the subline will have the following style:

.ib-teaser h2{
    color: #fff;
    font-size: 26px;
    line-height: 26px;
    padding-top: 40%;
    text-shadow: 1px 0px 2px rgba(0,0,0,0.2);
}
.ib-teaser h2 span{
    text-transform: none;
    font-size: 16px;
    font-family: Georgia, serif;
    font-style: italic;
    display: block;
}

When the content area gets expanded, we will show the preview container and it will have an absolute position and a dynamic height:

.ib-content-preview{
    position: absolute;
    top: 44px;
    left: 0px;
    background: #000;
    width: 100%;
    /* height dynamic*/
    display: none;
}

The text elements will get some styling:

.ib-content-preview .ib-teaser h2{
    font-size: 50px;
    padding: 85px 40px 20px 40px;
}
.ib-content-preview .ib-teaser span{
    padding: 20px 0px 0px 5px;
    font-size: 22px;
}
.ib-content-full{
    font-family:'Oswald', serif;
    text-transform: none;
    line-height: 26px;
    margin: 0px 40px;
    border-top: 1px solid #333;
    padding: 20px 0px;
	font-size: 16px;
}
.ib-content-full p{
	padding: 5px 0px;
}

The large preview for the thumbnails will also be of absolute position

.ib-preview{
    overflow: hidden;
    position: absolute;
    top: 40px;
    display: none;
}

The description for the large image will be placed in the bottom left corner. We want big letters:

.ib-preview-descr{
    position: absolute;
    bottom: 30px;
    left: 10px;
    z-index: 999;
    font-size: 50px;
    text-shadow: 1px 0px 2px rgba(0,0,0,0.2);
}

The image itself will be absolute and the width and height will be set dynamically in the JavaScript:

.ib-preview img{
	position: absolute;
}

The navigation for the images will be placed on the left and the right side of the screen:

.ib-nav span{
	width: 53px;
	height: 87px;
	position: absolute;
	top: 50%;
	margin-top: -43px;
	cursor: pointer;
    text-indent: -9000px;
	opacity: 0.6;
	z-index: 999;
    background: transparent url(../images/nav.png) no-repeat top right;
	right: 10px;
	-webkit-user-select: none;
	-khtml-user-select: none;
	-moz-user-select: none;
	-o-user-select: none;
	user-select: none;
}
.ib-nav span.ib-nav-prev{
	background-position: top left;
	left: 10px;
    right: auto;
}

The closing element will be at the top right corner:

.ib-close{
	top: 7px;
	right: 7px;
	background: transparent url(../images/close.png) no-repeat center center;
	position: absolute;
	width: 24px;
	height: 24px;
	cursor: pointer;
	opacity: 0.2;
	z-index: 999;
    text-indent: -9000px;
}
.ib-nav span:hover, .ib-close:hover{
	opacity: 1;
}

Last, but not least, we’ll style the loading element for the large image. We’ll place it in the center of the screen with our 50% and negative margin trick and give it some rounded borders:

.ib-loading-large{
    text-indent: -9000px;
    width: 60px;
    height: 60px;
    background: #fff url(../images/ajax-loader.gif) no-repeat center center;
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -30px 0 0 -30px;
    z-index: 999;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px 10px 10px 10px;
    opacity: 0.9;
}

And that was all the style. Now, let’s take a look at the JavaScript.

The JavaScript

Let’s define our template function:

var $ibWrapper	= $('#ib-main-wrapper'),
 
	Template	= (function() {
		...
})();

Template.init();

First, we will set some variables and cache some elements:

var kinetic_moving				= false,
	// current index of the opened item
	current						= -1,
	// true if the item is being opened / closed
	isAnimating					= false,
	// items on the grid
	$ibItems					= $ibWrapper.find('div.ib-main > a'),
	// image items on the grid
	$ibImgItems					= $ibItems.not('.ib-content'),
	// total image items on the grid
	imgItemsCount				= $ibImgItems.length,

The init function will add a class to all the image items and call the jQuery.kinetic plugin and initialize our main events:

init						= function() {
		
		// add a class ib-image to the image items
		$ibImgItems.addClass('ib-image');
		// apply the kinetic plugin to the wrapper
		loadKinetic();
		// load some events
		initEvents();

	},

loadKinetic will set the size of the main wrapper and apply the jQuery.kinetic plugin:

loadKinetic					= function() {
	
	setWrapperSize();
	
	$ibWrapper.kinetic({
		moved	: function() {
			
			kinetic_moving = true;
			
		},
		stopped	: function() {
			
			kinetic_moving = false;
			
		}
	});
	
},

setWrapperSize will set the height of the main wrapper by taking the window height and removing the top bar and the bottom bar (which is our demo header actually):

setWrapperSize				= function() {
	
	var containerMargins	= $('#ib-top').outerHeight(true) + $('#header').outerHeight(true) + parseFloat( $ibItems.css('margin-top') );
	$ibWrapper.css( 'height', $(window).height() - containerMargins )
	
},

initEvents calls the openItem function when we click on a box (unless we are dragging) and takes care of the resizing when we change the window size:

initEvents					= function() {

	// open the item only if not dragging the container
	$ibItems.bind('click.ibTemplate', function( event ) {
		
		if( !kinetic_moving )
			openItem( $(this) );
	
		return false;	
	
	});
	
	// on window resize, set the wrapper and preview size accordingly
	$(window).bind('resize.ibTemplate', function( event ) {
		
		setWrapperSize();
		
		$('#ib-img-preview, #ib-content-preview').css({
			width	: $(window).width(),
			height	: $(window).height()
		})
		
	});

},

When we click on an item, depending on which item we clicked, we’ll load a full image or a content area:

openItem					= function( $item ) {
	
	if( isAnimating ) return false;
	
	// if content item
	if( $item.hasClass('ib-content') ) {
		
		isAnimating	= true;
		current	= $item.index('.ib-content');
		loadContentItem( $item, function() { isAnimating = false; } );
		
	}
	// if image item
	else {
	
		isAnimating	= true;
		current	= $item.index('.ib-image');
		loadImgPreview( $item, function() { isAnimating = false; } );
		
	}
	
},

If we click on a thumbnail, we’ll load and expand to the respective large image. We will use the jQuery template for the large image preview and set it to the same position like the currently clicked item. Initially having the same size, it will then expand first in width to fit the window and then in height:

loadImgPreview				= function( $item, callback ) {
	
	var largeSrc		= $item.children('img').data('largesrc'),
		description		= $item.children('span').text(),
		largeImageData	= {
			src			: largeSrc,
			description	: description
		};
	
	// preload large image
	$item.addClass('ib-loading');
	
	preloadImage( largeSrc, function() {
		
		$item.removeClass('ib-loading');
		
		var hasImgPreview	= ( $('#ib-img-preview').length > 0 );
		
		if( !hasImgPreview )
			$('#previewTmpl').tmpl( largeImageData ).insertAfter( $ibWrapper );
		else
			$('#ib-img-preview').children('img.ib-preview-img').attr( 'src', largeSrc );
			
		//get dimentions for the image, based on the windows size
		var	dim	= getImageDim( largeSrc );
		
		$item.removeClass('ib-img-loading');
		
		//set the returned values and show/animate preview
		$('#ib-img-preview').css({
			width	: $item.width(),
			height	: $item.height(),
			left	: $item.offset().left,
			top		: $item.offset().top
		}).children('img.ib-preview-img').hide().css({
			width	: dim.width,
			height	: dim.height,
			left	: dim.left,
			top		: dim.top
		}).fadeIn( 400 ).end().show().animate({
			width	: $(window).width(),
			left	: 0
		}, 500, 'easeOutExpo', function() {
		
			$(this).animate({
				height	: $(window).height(),
				top		: 0
			}, 400, function() {
			
				var $this	= $(this);
				$this.find('span.ib-preview-descr, span.ib-close').show()
				if( imgItemsCount > 1 )
					$this.find('div.ib-nav').show();
					
				if( callback ) callback.call();
			
			});
		
		});
		
		if( !hasImgPreview )
			initImgPreviewEvents();
		
	} );
	
},

With the same effect of expanding, we’ll open a content area, too. Here we have to take care of the text elements:

loadContentItem				= function( $item, callback ) {
	
	var hasContentPreview	= ( $('#ib-content-preview').length > 0 ),
		teaser				= $item.children('div.ib-teaser').html(),
		content				= $item.children('div.ib-content-full').html(),
		contentData			= {
			teaser		: teaser,
			content		: content
		};
		
	if( !hasContentPreview )
		$('#contentTmpl').tmpl( contentData ).insertAfter( $ibWrapper );
		
	//set the returned values and show/animate preview
	$('#ib-content-preview').css({
		width	: $item.width(),
		height	: $item.height(),
		left	: $item.offset().left,
		top		: $item.offset().top
	}).show().animate({
		width	: $(window).width(),
		left	: 0
	}, 500, 'easeOutExpo', function() {
	
		$(this).animate({
			height	: $(window).height(),
			top		: 0
		}, 400, function() {
			
			var $this	= $(this),
				$teaser	= $this.find('div.ib-teaser'),
				$content= $this.find('div.ib-content-full'),
				$close	= $this.find('span.ib-close');
				
			if( hasContentPreview ) {
				$teaser.html( teaser )
				$content.html( content )
			}
		
			$teaser.show();
			$content.show();
			$close.show();
			
			if( callback ) callback.call();
		
		});
	
	});
	
	if( !hasContentPreview )
		initContentPreviewEvents();	
	
},

A little helper function for preloading images:

// preloads an image
preloadImage				= function( src, callback ) {

	$('<img/>').load(function(){
	
		if( callback ) callback.call();
	
	}).attr( 'src', src );

},

The next function takes care of loading the events for the large image preview : navigation, close button, and window resize:

initImgPreviewEvents		= function() {

	var $preview	= $('#ib-img-preview');
	
	$preview.find('span.ib-nav-prev').bind('click.ibTemplate', function( event ) {
		
		navigate( 'prev' );
		
	}).end().find('span.ib-nav-next').bind('click.ibTemplate', function( event ) {
		
		navigate( 'next' );
		
	}).end().find('span.ib-close').bind('click.ibTemplate', function( event ) {
		
		closeImgPreview();
		
	});
	
	//resizing the window resizes the preview image
	$(window).bind('resize.ibTemplate', function( event ) {
		
		var $largeImg	= $preview.children('img.ib-preview-img'),
			dim			= getImageDim( $largeImg.attr('src') );
		
		$largeImg.css({
			width	: dim.width,
			height	: dim.height,
			left	: dim.left,
			top		: dim.top
		})
		
	});
	
},

For the content preview we’ll also have to load the event for the closing functionality:

initContentPreviewEvents	= function() {

	$('#ib-content-preview').find('span.ib-close').bind('click.ibTemplate', function( event ) {
		
		closeContentPreview();
		
	});
	
},

Next, we’ll define the function that takes care of navigating through the large images in fullscreen:

// navigate the image items in fullscreen mode
navigate					= function( dir ) {
	
	if( isAnimating ) return false;
	
	isAnimating		= true;
	
	var $preview	= $('#ib-img-preview'),
		$loading	= $preview.find('div.ib-loading-large');
	
	$loading.show();
	
	if( dir === 'next' ) {
		
		( current === imgItemsCount - 1 ) ? current	= 0 : ++current;
		
	}
	else if( dir === 'prev' ) {
		
		( current === 0 ) ? current	= imgItemsCount - 1 : --current;
		
	}
	
	var $item		= $ibImgItems.eq( current ),
		largeSrc	= $item.children('img').data('largesrc'),
		description	= $item.children('span').text();
		
	preloadImage( largeSrc, function() {
		
		$loading.hide();
		
		//get dimentions for the image, based on the windows size
		var	dim	= getImageDim( largeSrc );
		
		$preview.children('img.ib-preview-img')
						.attr( 'src', largeSrc )
						.css({
			width	: dim.width,
			height	: dim.height,
			left	: dim.left,
			top		: dim.top
						})
						.end()
						.find('span.ib-preview-descr')
						.text( description );
		
		$ibWrapper.scrollTop( $item.offset().top )
				  .scrollLeft( $item.offset().left );
		
		isAnimating	= false;
		
	});
	
},

The following function is for closing the fullscreen image preview:


closeImgPreview				= function() {

	if( isAnimating ) return false;
	
	isAnimating	= true;
	
	var $item	= $ibImgItems.eq( current );
	
	$('#ib-img-preview').find('span.ib-preview-descr, div.ib-nav, span.ib-close')
					.hide()
					.end()
					.animate({
						height	: $item.height(),
						top		: $item.offset().top
						}, 500, 'easeOutExpo', function() {
						
						$(this).animate({
							width	: $item.width(),
							left	: $item.offset().left
							}, 400, function() {
							
								$(this).fadeOut(function() {isAnimating	= false;});
							
						} );
					
					});

},

For the content preview we will also need such a function:

// closes the fullscreen content item
closeContentPreview			= function() {
	
	if( isAnimating ) return false;
	
	isAnimating	= true;
	
	var $item	= $ibItems.not('.ib-image').eq( current );
	
	$('#ib-content-preview').find('div.ib-teaser, div.ib-content-full, span.ib-close')
							.hide()
							.end()
							.animate({
								height	: $item.height(),
								top		: $item.offset().top
							}, 500, 'easeOutExpo', function() {
								
								$(this).animate({
									width	: $item.width(),
									left	: $item.offset().left
								}, 400, function() {
									
									$(this).fadeOut(function() {isAnimating	= false;});
									
								} );
							
							});

},

getImageDim will get the size of an image and make it centered in fullscreen:

getImageDim					= function( src ) {
	
	var img     	= new Image();
	img.src     	= src;
	
	var w_w	= $(window).width(),
		w_h	= $(window).height(),
		r_w	= w_h / w_w,
		i_w	= img.width,
		i_h	= img.height,
		r_i	= i_h / i_w,
		new_w, new_h,
		new_left, new_top;
	
	if( r_w > r_i ) {
	
		new_h	= w_h;
		new_w	= w_h / r_i;
	
	}	
	else {
	
		new_h	= w_w * r_i;
		new_w	= w_w;
	
	}
	
	return {
		width	: new_w,
		height	: new_h,
		left	: (w_w - new_w) / 2,
		top		: (w_h - new_h) / 2
	};

};

And that’s it! I hope you enjoyed making this template with me and find it useful!

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 93

Comments are closed.
  1. Mary Lou, such a great work, I´m graphic designer and since some months getting into html, and your work is just GREAT

    Luca, sorry for asking again about adding a link, how do you do this? every thime I try to add a link all the following image boxes move and the text I wrotte on the code is visible…
    thank you for your help !

  2. Anyone figured out, how to open the images at their original size instead of making them full-screen ?

  3. Hello !

    That’s a very nice work ! Congratulations !

    But there are problems with IE7 & IE8 (drags, loaders,etc…), can I fixe it ?

  4. Mary Lou, great as always!! Thank you for this gorgeous gallery!! I currently use your slider gallery but your great ideas make it really hard to decide on the layout ;-). And today I found this one…awesome!

    Ok, figured out how to open images in original size:

    – Go to the section getImageDim in the index.html
    – in the if-statement replace new_h and new_w by the orig.values:

    if( r_w > r_i ) {

    new_h = 680;
    new_w = 1024;
    }
    else {
    new_h = 680;
    new_w = 1024;
    }

    leave the rest as it is since we want the image to be centered on the screen.

    Dont know how it’ll work on ipad, IE7/8 only tested on FF8 on Ubuntu.

    However the titles are still on left edge of the screen…I’m working on that as well as on a nice dimmed blackground when opening the image. Will post it here when I found a solution.

    Cheers

  5. awesome tut as usual.

    Is there a way to display the whole image when it is opened? Actually, the images are cut off! It would be nice to have the possibility for the pic to slide with ease on top when the cursor goes up and vice versa when down.

    Anyone has overcome this?

  6. Very Nice work!!!

    I need some help. I have tested on Ipad and Firefox the drag movement is not very smooth. What can I do to fix it?

    Congratulation

    Thanks for the tutorial!

  7. @Ben one way to do it is set image container overflow to scroll, doesn’t look so good but people can scroll to se the entire image….

  8. hihi

    how can i set an images when finish load become grayscale, mouseover will become color…

    is that i can use Grayscale w canvas method ?

    after i having some try. grayscale is work fine. but fullscreen function is disappear. please help on this cases.

    thx.

  9. anyone found out how to inactiv some link without the loading script bloc the website ?
    like one square open in big and the other you can’t clic on it ?
    thanks anyway

  10. @Luca, @everybody
    Please can you show me how exactly you can place links inside the content area?
    thanks a lot

  11. Hi,
    I’m looking for a way to incorporate a videoplayer into this. Something that will play vimeo and youtube video’s in the same way as the large images are shown. Any ideas or suggestions?
    thanks!
    Very beautiful plugin by the way!

  12. Gridfolio update to ver. 1.1.
    problem with links inside content area fixed.
    problem with linked images in content area fixed.
    minor bugs fixed.
    now working on jquery scroll content area,
    and add video’s support inside content area
    more info: http://kbdesign.bdl.pl/?p=3606

  13. can this script be modified to scroll with the mouse ? or integrate a navigation scroll bar ? would be pretty useful

  14. great job I love,
    I just have one question,
    how to correctly display vertical images?

  15. I would like to use the images in original sizes. I don’t want to fit them into the screen. Because the effects of vertical and horrizontal images are different.

    How can I do that? Thank you for your helping…

  16. I have a problem: how to install a video as an image?
    It’s really interesting this system and even more with video.
    Thank you for your help.

  17. This is great! I’m a 2D/3D game artist and will use this for my portfolio site.
    It would be really wicked awesome if there was a way to display video as well 😀
    Any ideas anyone?!

  18. hey, im having a problem making the images go full screen when clicked for some reason, instead of going full screen it seems to load inside the thumbnail.

    its probably a rooky error but i can’t see any difference in the working code to the code used in my site…its driving me crazy!
    please help

    thanks
    Gemma

  19. Using this awesomeness on my photography website.

    http://www.theartofmoore.com/

    PS I’m not terribly experienced with JS/jQuery. How can I make the large image modal close when the photo itself is clicked (versus having to hit the X)?

    Thanks!

  20. Thank you so much for the brilliant idea!!
    I applied this to my project. http://shrewd-design.com/photography/

    I took advantage of “a href” attribute instead of data attribute to take care of the case when JavaScript disable.

    I tried to change the positioning from absolute to fixed while expanding pop-up window.
    I guess it’s still not an elegant way though; I need to take care of that awkward transition.

    And I wish I could accomodate the height within the visible area instead of monitor’s height
    while keeping the ratio, like css3 “background-size: contain” instead of “cover”.

    I’m gonna try to do it somehow. Thanks again!!

  21. How do I go about adding a 2nd line of info (that differs from photo to photo) to the large image preview? I’ve been messing with it, I can get it to display, but not dynamically update based on photo (2nd line value just stays the same for all photos). TIA

    • Hey Matt,

      You’ll need to modify: 1) the variables the plugin pulls from the grid page and, 2) the jquery-tmpl scripts to use the new variables. Be sure to update it for both “opening” and “navigating” functions, and you should have it in no time. This is also the part of the plugin that needs to be updated to allow for html content to be included in the photo captions.

  22. Hi Mary Lou! I’m using a hybrid between your build and Krzyho’s WordPress theme. I’m trying to work out how to include “deep linking” similar to swfaddress/hashchange, where an external link can go directly to the page and load that particular box. I’ve worked out a way to give each box its own #hash, but I can’t work out the linking part! Any clues or pointers would be AWESOME, please! Or if/when I work it out I’ll post back too. Thank you for your fantastic and inspiring work~

    • We worked out a solution using jquery swfaddress. Thank you again for this framework!

  23. Hey everyone! Using some algebra I found a way to display all images correctly regardless of size or proportion. In the script section scroll to the section that defines the window height, width, etc. (w_w, w_h, all that code) and use this instead:

    if( r_w > r_i ) {

    new_h = (w_h – 40);
    new_w = (i_w * (w_h – 40)) / i_h;

    }
    else {

    new_h = (w_h – 40);
    new_w = (i_w * (w_h – 40)) / i_h;

    Brief explanation: the top bar height is 40px, so we subtract that from the window height to get the proper height of the image, then from there I used a proportion to come up with the formula you see for new_w that correctly sets the width according to the height.

    And yet I still cannot figure out how to put links in the content areas. :p

    • Hi Josh!

      Links in the content areas is a quick fix. There are three areas that will need to be updated: the markup, the CSS, and the jquery. The problem is how the markup is structured – each “box” is created with an anchor tag, originally. Referencing the “Markup” box above:

      Original:
      <a href=”#” rel=”nofollow”>

      Welcome Howdy, Stranger

      <!– Some content –>

      </a>

      What you need to change it to:

      Welcome Howdy, Stranger

      <!– Some content –>

      Naturally you’ll need to update your CSS to reference this change. Use the new class you should’ve added.

      Finally, you need to update the jQuery framework, too:

      Original:
      $ibItems = $ibWrapper.find(‘div.ib-main > a’),

      Updated:
      $ibItems = $ibWrapper.find(‘div.ib-main > .givethisboxasecondclassforcssmcloving’),

      That should do the trick! Good luck!

    • this does not work for me, asside that you left out a } at the end of else, dragging just stops for me in chrome. any ideas?

  24. Draggable Image Boxes Grid drag not working in latest firefox 59.0.2 (64-bit)

    and chrome Version 65.0.3325.181 (Official Build) (64-bit) any solution. Please help

  25. This no longer seems to work on touch devices. Tried on iPhone Safari/Chrome and Android Chrome. Boxes will drag but images never open.