Interactive Gallery Photo Desk With jQuery & CSS3


In this little experiment we created an interactive photo desk that provides some “realistic” interaction possibilities for the user. The idea is to have some photos on a surface that can be dragged and dropped, stacked and deleted, each action resembling the real world act.

For example, if we drag a picture, it get’s “picked up” first, making it appear a little bit bigger, since it would be closer to us. Dropping it results in the picture being “thrown back” to the table, in a random rotation. Viewing all photos mirrors the action of collecting all images into a pile and viewing the first one in a none rotated way. Clicking to see the next one then, makes the previous one being thrown back to the surface. Deleting an image will make it appear as a crumpled paper ball.
When using the shuffle function, the photos get rotated and spread over the desk randomly.

You can download the source code of this and experiment with it, there are many more possibilities to discover and integrate.

We are using two important jQuery plugins: 2D Transform for animating rotations and Shadow Animation for animating the box shadow.

The images are taken from the amazing photostream of tibchris on Flickr.
The rotation did not work well with IE (although in principle it should) so we don’t rotate when IE is used.

We hope you enjoy this little experiment!!

CSS::

#gallerybox {width:700px;height:500px;margin:0 auto;position:relative;border:1px solid #fff;box-shadow:0px 0px 5px #eee;-moz-box-shadow:0px 0px 5px #eee;-webkit-box-shadow:0px 0px 5px #eee;}
a.pd_next_photo,
a.pd_loading{z-index:999999;cursor:pointer;border:1px solid #aaa;width:50px;height:50px;position:absolute;top:50%;left:50%;opacity:0.8;margin:-25px 0px 0px -25px;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px;}
a.pd_loading{display:none;background:#f6f6f6 url(http://tympanus.net/Development/PhotoDesk/images/loading.gif) no-repeat 50% 50%;}
a.pd_next_photo{background:#B8B8B8 url(http://tympanus.net/Development/PhotoDesk/images/next.png) no-repeat 50% 50%;}
a.pd_next_photo:hover,
a.pd_loading:hover{opacity:1.0;}
.pd_options_bar a.viewall,
.pd_options_bar a.shuffle,
.pd_options_bar a.backdesk
{outline:none;padding:0px 15px 0px 50px;line-height:47px;text-decoration:none;font-size:24px;color:#333;text-shadow:1px 1px 1px #f0f0f0;height:50px;float:right;margin:5px 10px 0px 0px;-moz-box-shadow:1px 1px 2px #666;-webkit-box-shadow:1px 1px 2px #666;box-shadow:1px 1px 2px #666;opacity:0.8;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px;}
.pd_options_bar a.viewall{background:#f6f6f6 url(http://tympanus.net/Development/PhotoDesk/images/viewall.png) no-repeat 10px 50%;}
.pd_options_bar a.shuffle{background:#f6f6f6 url(http://tympanus.net/Development/PhotoDesk/images/shuffle.png) no-repeat 10px 50%;}
.pd_options_bar a.backdesk{background:#f6f6f6 url(http://tympanus.net/Development/PhotoDesk/images/backdesk.png) no-repeat 10px 50%;}
.pd_options_bar a.viewall:hover,
.pd_options_bar a.shuffle:hover,
.pd_options_bar a.backdesk:hover
{opacity:1.0;text-shadow:1px 1px 1px #fff;-moz-box-shadow:1px 1px 2px #fff;-webkit-box-shadow:1px 1px 2px #fff;box-shadow:1px 1px 2px #fff;}
.pd_container{position:absolute;top:30px;bottom:30px;right:30px;left:30px;}
.pd_photo{position:absolute;z-index:10;border:7px solid #f6f6f6;border-bottom:28px solid #f6f6f6;width:180px;height:180px;top:0px;left:0px;display:none;-moz-box-shadow:1px 1px 5px #555;-webkit-box-shadow:1px 1px 5px #555;box-shadow:1px 1px 5px #555;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;}
.pd_photo img, #gallerybox img{width:180px;height:180px;}
.pd_photo span.delete{position:absolute;width:16px;height:16px;right:-16px;top:2px;cursor:pointer;background:#fff url(http://tympanus.net/Development/PhotoDesk/images/close.png) no-repeat center center;-moz-border-radius:0px 8px 8px 0px;-webkit-border-top-right-radius:8px;-webkit-border-bottom-right-radius:8px;border-top-right-radius:8px;border-bottom-right-radius:8px;-moz-box-shadow:1px 1px 5px #555;-webkit-box-shadow:1px 1px 5px #555;box-shadow:1px 1px 5px #555;}
.pd_paperball{background:transparent url(http://tympanus.net/Development/PhotoDesk/images/paperball.png) no-repeat center center;
position:absolute;}

SCRIPT::

<!-- The JavaScript -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js"></script>

<script src="http://tympanus.net/Development/PhotoDesk/jquery.transform-0.6.2.min.js"></script>
<script src="http://tympanus.net/Development/PhotoDesk/jquery.animate-shadow-min.js"></script>

<script type="text/javascript">
$(function(){var idx,idxLarge=-1;var mouseup=false;var photoW=184;var photoH=205;var $container=$('#pd_container');var $options=$('#pd_options_bar');var photosSize=$container.find('.pd_photo').length;var navPage=0;var ie=false;if($.browser.msie){ie=true}start();function start(){$('#pd_loading').show();var tableW=$container.width();var tableH=$container.height();var horizontalMax=tableW-photoW;var verticalMax=tableH-photoH;$('<img />').attr('src','images/paperball.png');var cntPhotos=0;$container.find('.pd_photo').each(function(i){var $photo=$(this);$('<img />').load(function(){++cntPhotos;var $image=$(this);var r=Math.floor(Math.random()*201)-100;var maxzidx=parseInt(findHighestZIndex())+1;var param={'top':Math.floor(Math.random()*verticalMax)+'px','left':Math.floor(Math.random()*horizontalMax)+'px','z-index':maxzidx};$photo.css(param);if(!ie)$photo.transform({'rotate':r+'deg'});$photo.show();if(cntPhotos==photosSize){bindEvents();$('#pd_loading').hide()}}).attr('src',$photo.find('img').attr('src'))})}function mouseDown($photo){mouseup=true;idx=$photo.index()+1;var maxzidx=parseInt(findHighestZIndex())+1;$photo.css('z-index',maxzidx);if(ie)var param={'width':'+=40px','height':'+=40px'};else var param={'width':'+=40px','height':'+=40px','rotate':'0deg','shadow':'5px 5px 15px #222'};$photo.stop(true,true).animate(param,100).find('img').stop(true,true).animate({'width':'+=40px','height':'+=40px'},100)}$(document).bind('mouseup',function(e){if(mouseup){mouseup=false;var $photo=$container.find('.pd_photo:nth-child('+idx+')');var r=Math.floor(Math.random()*101)-50;var $photoT=parseFloat($photo.css('top'),10);var $photoL=parseFloat($photo.css('left'),10);var newTop=$photoT+r;var newLeft=$photoL+r;if(ie)var param={'width':'-=40px','height':'-=40px','top':newTop+'px','left':newLeft+'px'};else var param={'width':'-=40px','height':'-=40px','top':newTop+'px','left':newLeft+'px','rotate':r+'deg','shadow':'0 0 5px #000'};$photo.stop(true,true).animate(param,200).find('img').stop(true,true).animate({'width':'-=40px','height':'-=40px'},200)}e.preventDefault()});$container.find('.delete').bind('click',function(){var $photo=$(this).parent();var $photoT=parseFloat($photo.css('top'),10);var $photoL=parseFloat($photo.css('left'),10);var $photoZIndex=$photo.css('z-index');var $trash=$('<div />',{'className':'pd_paperball','style':'top:'+parseInt($photoT+photoH/2)+'px;left:'+parseInt($photoL+photoW/2)+'px;width:0px;height:0px;z-index:'+$photoZIndex}).appendTo($container);$trash.animate({'width':photoW+'px','height':photoH+'px','top':$photoT+'px','left':$photoL+'px'},100,function(){var $this=$(this);setTimeout(function(){$this.remove()},800)});$photo.animate({'width':'0px','height':'0px','top':$photoT+photoH/2+'px','left':$photoL+photoW/2+'px'},200,function(){--photosSize;$(this).remove()})});function stack(){navPage=0;var cnt_photos=0;var windowsW=$(window).width();var windowsH=$(window).height();$container.find('.pd_photo').each(function(i){var $photo=$(this);$photo.css('z-index',parseInt(findHighestZIndex())+1000+i).stop(true).animate({'top':parseInt((windowsH-100)/2-photoH/2)+'px','left':parseInt((windowsW-100)/2-photoW/2)+'px'},800,function(){$options.find('.backdesk').show();var $photo=$(this);$photo.unbind('mousemove');++cnt_photos;var $nav=$('<a class="pd_next_photo" style="display:none;"></a>');$nav.bind('click',function(){$(this).remove();navigate()});$photo.prepend($nav);$photo.draggable('destroy').find('.delete').hide().andSelf().find('.pd_hold').unbind('mousedown').bind('mousedown',function(){return false});$options.find('.shuffle,.viewall').unbind('click');if(cnt_photos==photosSize)enlarge(findElementHighestZIndex())})})}function enlarge($photo){var windowsW=$(window).width();var windowsH=$(window).height();if(ie)var param={'width':'+=200px','height':'+=200px','top':parseInt((windowsH-100)/2-(photoH+200)/2)+'px','left':parseInt((windowsW-100)/2-(photoW+200)/2)+'px'};else var param={'width':'+=200px','height':'+=200px','top':parseInt((windowsH-100)/2-(photoH+200)/2)+'px','left':parseInt((windowsW-100)/2-(photoW+200)/2)+'px','rotate':'0deg','shadow':'5px 5px 15px #222'};$photo.animate(param,500,function(){idxLarge=$(this).index();var $photo=$(this);$photo.unbind('mousemove').bind('mousemove',function(){$(this).find('.pd_next_photo').show()}).unbind('mouseleave').bind('mouseleave',function(){$(this).find('.pd_next_photo').hide()})}).find('img').animate({'width':'+=200px','height':'+=200px'},500)}function disperse(){var windowsW=$(window).width();var windowsH=$(window).height();$container.find('.pd_photo').each(function(i){var $photo=$(this);if($photo.index()==idxLarge){if(ie)var param={'top':parseInt((windowsH-100)/2-photoH/2)+'px','left':parseInt((windowsW-100)/2-photoW/2)+'px','width':'170px','height':'170px'};else var param={'top':parseInt((windowsH-100)/2-photoH/2)+'px','left':parseInt((windowsW-100)/2-photoW/2)+'px','width':'170px','height':'170px','shadow':'1px 1px 5px #555'};$photo.stop(true).animate(param,500,function(){shuffle();$options.find('.viewall').show()}).find('img').animate({'width':'170px','height':'170px'},500)}});$container.find('.pd_next_photo').remove();bindEvents()}function bindEvents(){$options.find('.shuffle').unbind('click').bind('click',function(e){if(photosSize==0)return;shuffle();e.preventDefault()}).andSelf().find('.viewall').unbind('click').bind('click',function(e){var $this=$(this);if(photosSize==0)return;stack();$this.hide();e.preventDefault()}).andSelf().find('.backdesk').unbind('click').bind('click',function(e){var $this=$(this);if(photosSize==0)return;disperse();$this.hide();e.preventDefault()});$container.find('.pd_photo').each(function(i){var $photo=$(this);$photo.draggable({containment:'#pd_container'}).find('.delete').show()}).find('.pd_hold').unbind('mousedown').bind('mousedown',function(e){var $photo=$(this).parent();mouseDown($photo);e.preventDefault()})}function navigate(){if(photosSize==0)return;var tableW=$container.width();var tableH=$container.height();var horizontalMax=tableW-photoW;var verticalMax=tableH-photoH;var $photo=$container.find('.pd_photo:nth-child('+parseInt(idxLarge+1)+')');var r=Math.floor(Math.random()*201)-100;if(ie)var param={'top':Math.floor(Math.random()*verticalMax)+'px','left':Math.floor(Math.random()*horizontalMax)+'px','width':'170px','height':'170px'};else var param={'top':Math.floor(Math.random()*verticalMax)+'px','left':Math.floor(Math.random()*horizontalMax)+'px','width':'170px','height':'170px','rotate':r+'deg','shadow':'1px 1px 5px #555'};$photo.stop(true).animate(param,500,function(){++navPage;var $photo=$(this);$container.append($photo.css('z-index',1));if(navPage<photosSize)enlarge(findElementHighestZIndex());else{$options.find('.backdesk').hide();$options.find('.viewall').show();bindEvents()}}).find('img').animate({'width':'170px','height':'170px'},500)}function shuffle(){var tableW=$container.width();var tableH=$container.height();var horizontalMax=tableW-photoW;var verticalMax=tableH-photoH;$container.find('.pd_photo').each(function(i){var $photo=$(this);var r=Math.floor(Math.random()*301)-100;if(ie)var param={'top':Math.floor(Math.random()*verticalMax)+'px','left':Math.floor(Math.random()*horizontalMax)+'px'};else var param={'top':Math.floor(Math.random()*verticalMax)+'px','left':Math.floor(Math.random()*horizontalMax)+'px','rotate':r+'deg'};$photo.animate(param,800)})}function findHighestZIndex(){var photos=$container.find('.pd_photo');var highest=0;photos.each(function(){var $photo=$(this);var zindex=$photo.css('z-index');if(parseInt(zindex)>highest){highest=zindex}});return highest}function findElementHighestZIndex(){var photos=$container.find('.pd_photo');var highest=0;var $elem;photos.each(function(){var $photo=$(this);var zindex=$photo.css('z-index');if(parseInt(zindex)>highest){highest=zindex;$elem=$photo}});return $elem}Array.prototype.remove=function(from,to){var rest=this.slice((to||from)+1||this.length);this.length=from<0?this.length+from:from;return this.push.apply(this,rest)}});
</script>

HTML::

<div id='gallerybox'>
<div><a id="pd_loading" href="#" class="pd_loading"></a></div>
<div id="pd_options_bar" class="pd_options_bar">
<a href="" class="shuffle">Shuffle</a>
<a href="" class="backdesk" style="display:none;">Back to Desk</a>
<a href="" class="viewall">View All</a>
</div>
<div id="pd_container" class="pd_container">

<div class="pd_photo">
<div class="pd_hold">
<img src="http://favim.com/orig/201105/17/baby-baby-girl-beautiful-child-cute-girl-Favim.com-48227.jpg" alt=""/>
</div>
<span class="delete"></span>
</div>

<div class="pd_photo">
<div class="pd_hold">
<img src="http://data.whicdn.com/images/35398355/face-cute-girl-nina-dobrev-hair-look-photos_large.jpg" alt=""/>
</div>
<span class="delete"></span>
</div>

<div class="pd_photo">
<div class="pd_hold">
<img src="http://s2.favim.com/orig/35/asian-asian-girl-cute-free-girl-Favim.com-281584.jpg" alt=""/>
</div>
<span class="delete"></span>
</div>

<div class="pd_photo">
<div class="pd_hold">
<img src="http://parttimebkk2556.files.wordpress.com/2012/12/cute-korean-girls02.jpg" alt=""/>
</div>
<span class="delete"></span>
</div>

<div class="pd_photo">
<div class="pd_hold">
<img src="http://25.media.tumblr.com/tumblr_m41qspMUvL1rphuipo4_1280.jpg" alt=""/>
</div>
<span class="delete"></span>
</div>

<div class="pd_photo">
<div class="pd_hold">
<img src="http://happy.ap.teacup.com/yukarisuketetu/timg/middle_1338987463.jpg" alt=""/>
</div>
<span class="delete"></span>
</div>

<div class="pd_photo">
<div class="pd_hold">
<img src="http://img01.taobaocdn.com/bao/uploaded/i1/T1zaS3Xb4rXXXI.Zo9_102633.jpg" alt=""/>
</div>
<span class="delete"></span>
</div>

</div>
</div>

Example Interactive Gallery Photo Desk With jQuery & CSS3.!