Making a Photoshoot Effect With jQuery & CSS

Making a Photoshoot Effect With jQuery & CSS

Often, in your design or development tasks, you are presented with challenges that require a different approach than just plunging head over heels in coding. Research and experiments are a vital part of this process.

This is why this week’s tutorial is structured in a slightly different manner than usual. First we are presented with the main problems faced and their solutions, and after this we get round to building upon it.

We are creating a photo shoot effect with our just-released PhotoShoot jQuery plug-in. With it you can convert a regular div on the page into a photo shooting stage simulating a camera-like feel. Using this plug-in, we give visitors the ability to take shots of the background image.

Before starting with the tutorial, I would suggest you download the zip archive from the buttons above.

Problem 1 – Blurring the image

JavaScript does not support blurring an image directly. For example, there is no such thing as document.getElemetById(‘image’).style.blur=2, no matter how useful it would’ve been.

The technique I’ve used and incorporated into the plug-in is actually quite simple – it just stacks up a bunch of divs, each holding the image as a background and whose opacity is lowered, one on top of the other. Those divs’ positions are off by a few pixels at random, so you end up with a blurred effect.

There is however a newer alternative to this technique, which I hope to implement in a future version of the plugin. It is achieved via the canvas HTML5 element, which allows low-level modifications of an image inside of the canvas. Unfortunately, canvas is not yet supported by a large portion of the currently used browsers, so a combination of the techniques would have to be used.

Problem 2 – Hiding the cursor

CSS does not provide a way for hiding the cursor from view. E.g. you cannot specify a CSS rule like cursor : none. There is a neat workaround though. CSS gives you the ability to specify a custom cursor in a .cur file with the css:url() rule. These files support transparency, so you just need to make a completely transparent cursor and assign it to the area in which you wish the cursor to be hidden.

Unfortunately Google Chrome has issues with completely blank cursors, so a special version has to be tailored which contains one white pixel (still better than nothing).

Another trouble maker is Opera, which does not support custom cursors altogether. There are no workarounds. It is not that much of a big deal though, everything else runs fine in Opera.

Problem 3 – No support for masks

A solution to this problem is to use the background property of the viewfinder div to display the original image. By specifying a negative top and left margin and updating it on every mouse move, we can give users  the impression that the viewfinder clears up the blurring of the scenery below.

Masking is the process in which only a part of an image or shape is shown, with the rest clipped away. In the case of this tutorial, a mask would’ve given us the ability to have a regular version of the image above the blurred one, and mask it, so that only the part that intersects with the viewfinder is shown and thus giving us the impression that it un-blurs the image below.

The solutions to these problems are implemented in the plug-in for us, which lifts a lot of the development burden and we can start building upon it.

Step 1 – XHTML

As most of the work is handled by the PhotoShoot jQuery plug-in, our work is reduced to only provide a div that is going to be transformed into a photo shooting stage (we still have to pass a configuration object holding the image we want displayed, along with a few other options though).

demo.html

<div id="main">

<!-- The plugin automatically inserts the needed markup here -->

</div>

You can have this div anywhere on your page. You’ll need to specify a fixed width and height in the stylesheet in order for this to work properly. After the page loads and the plug-in is initialized, additional code is inserted into this div.

demo.html

<div id="main">

<div class="blur" style="......"></div>
<div class="blur" style="......"></div>
<!--  8 more blur divs -->

<div class="overlay" style="opacity: 0.2;"></div>

<div style="......" class="viewFinder">
<img src="photoShoot/viewfinder.png" width="300" height="200">
</div>

<!-- Additional html for the shots is inserted here. Not part of the plug-in.  -->

</div>

A whole lot has changed here. As mentioned earlier, the blur effect is achieved by stacking transparent divs on top of each other – the blur divs. After this is the overlay div, which darkens the layers below it, according to the opacity option passed to the plug-in.

Finally we have the viewfinder, which follows the mouse movements on the area and has the non-blurred version of the image as its background.

To ensure maximum flexibility, the plug-in provides a way to execute a user-defined function when a click occurs. This is exactly what we use to simulate a camera flash and to insert a new shot in the album div, which is not part of the plug-in.

A PhotoShoot Effect With Pure jQuery & CSS

A PhotoShoot Effect With Pure jQuery & CSS

Step 2 – CSS

The plug-in comes with its own stylesheet (photoShoot/jquery.photoShoot-1.0.css in the demo files) which defines the look of the photo shoot components, so we are only left with styling the rest of the page.

styles.css

#main{
	/* This div is converted to a photoShoot stage by the Photo Shoot plug-in */
	margin:0 auto;
	width:960px;
	height:600px;
}

.shot{
	/* These contain a scaled down version of the background image: */

	border:3px solid #FCFCFC;
	float:right;
	position:relative;
	margin-left:10px;
	overflow:hidden;

	/* Adding a CSS3 shadow below the shots: */

	-moz-box-shadow:0 0 2px black;
	-webkit-box-shadow:0 0 2px black;
	box-shadow:0 0 2px black;
}

.shot img{
	display:block;
}

.album{
	/* This div holds the shots */
	bottom:50px;
	height:110px;
	overflow:hidden;
	position:absolute;
	right:20px;
	width:490px;
}

.album .slide{
	/* The slide div is contained in album  */
	width:700px;
	height:110px;
	position:relative;
	left:-210px;
}

Each shot is dynamically inserted by our own custom shoot function when a click event occurs (as you will see in the next step of the tutorial). The shots are basically a scaled down version of the background image (this means that the image is downloaded once and used multiple times), which are offset to the top and bottom, according to the position of the viewfinder in the moment the event occurred.

The album and slide divs are added by our own jQuery script (not by the plug-in). The principle here is that the slide div is larger than its parent, the album div, and the shot is slid to the left when inserted, but more on that in a moment.

The shots

The shots

Step 3 – jQuery

The photoShoot plug-in itself will not be discussed here as you can read more about it on its official page. We do need, however, some additional jQuery code which:

  • Inserts the .album to the #main div;
  • Chooses a random flickr image from an array to be fed to the plug-in;
  • Creates the options object;
  • Defines a custom shot function which is called on mouse click by the plug-in;
  • Calls the plug-in with the .photoshoot() method.

script.js

$(document).ready(function(){

	// This code is executed after the DOM has been completely loaded

	// Assigning the jQuery object to a variable for speed:
	var main = $('#main');

	// Setting the width of the photoshoot area to
	// 1024 px or the width of the document - whichever is smallest:

	main.width(Math.min(1024,$(document).width()));

	// Creating an array with four possible backgrounds and their sizes:
	var pics = new Array(
				{ url:'http://farm4.static.flickr.com/3595/3405361333_77f2a5e731_b.jpg', size:{x:1024,y:677}},
				{ url:'http://farm4.static.flickr.com/3028/2753126743_4249a4e948_b.jpg', size:{x:1024,y:768}},
				{ url:'http://farm4.static.flickr.com/3641/3595250019_5a1237899a_b.jpg', size:{x:1024,y:768}},
				{ url:'http://farm3.static.flickr.com/2592/4018062274_1f7f23597d_o.jpg', size:{x:1158,y:756}}
	);

	// Choosing a random picture to be passed to the PhotoShoot jQuery plug-in:
	var bg = pics[parseInt(Math.random()*4)];

	// Creating an options object (try tweeking the variables):
	var opts = {
		image		:	bg.url,
		onClick		:	shoot,
		opacity		:	0.8,
		blurLevel	:	4
	}

	// Calling the photoShoot plug-in and converting the #main div to a photo shoot stage:
	main.photoShoot(opts);

	// Adding the album holder to the stage:
	$('<div class="album">').html('<div class="slide" />').appendTo(main);

	// Our own shoot function (it is passed as onClick to the options array above):
	function shoot(position){
		// This function is called by the plug-in when the button is pressed

		// Setting the overlay's div to white will create the illusion of a camera flash:
		main.find('.overlay').css('background-color','white');

		// The flash will last for 100 milliseconds (a tenth of the second):
		setTimeout(function(){main.find('.overlay').css('background-color','')},100);

		// Creating a new shot image:
		var newShot = $('<div class="shot">').width(150).height(100);
		newShot.append( $('<img src="'+bg.url+'" width="'+(bg.size.x/2)+'" height="'+(bg.size.y/2)+'" />').css('margin',-position.top*0.5+'px 0 0 -'+position.left*0.5+'px') );

		// Removing the fourth shot (the count starts from 0):
		$('.shot').eq(3).remove();

		// Adding the newly created shot to the album div, but moved 160px to the right.
		// We start an animation to slide it in view:

		newShot.css('margin-right',-160).prependTo('.album .slide').animate({marginRight:0},'slow');
	}
});

Each time you click the area, a new shot is added to the slide div with a negative margin to the right. After this an animation starts, which slides it in view and pushes the other shots to the left, hiding the leftmost one.

It is important to remove the shots that are not visible with the remove() method. This way we prevent cluttering of the DOM with unneeded elements.

The jQuery Animation

The jQuery Animation

With this our Photoshoot effect is complete!

Conclusion

Today we used a problem solving approach to create photo shoot effect with pure CSS and JavaScript. You can freely use the techniques demonstrated here and build upon the code. There are many possible uses especially in navigation systems and promotional sites.

If you liked this tutorial, be sure to follow us on twitter for the latest web development news and links.

A big thanks goes to haglundc for the landscape photo used throughout this tutorial.

What do you think? How would you use it?

Join our newsletter and get our PSDs!19,614 people learn about HTML5, JS and more. Join them!

by Martin Angelov

Martin is a web developer with an eye for design from Bulgaria. He founded Tutorialzine in 2009 and it still is his favorite side project.

40 Comments

  1. Chocksy says:

    This one is great man. I don't know i guess i would use it for cropping avatars or photos for profiles.

  2. DesignLovr says:

    This is simply amazing!
    I would have never guessed that you can achieve such amazing results with jquery only :)

    Great work!

  3. Groningen says:

    You are to good for this world, this are tuts, wich are +tuts at nettuts.
    Tnx, from the Groningen the Netherlands

  4. Marco says:

    That's freakin' amazing man - I love it! Very well done :D!

  5. Janko says:

    This is really amazing effect, nice usage of jQuery.

  6. Simply amazing what is being done with jQuery.

    Hopefully at some point in the future I can find a use for this code.

  7. Eric S says:

    WOW! I am completely amazed. I have seen some great effects and inspirations, but the uses with this are endless

  8. Really COOL... but can anything be done with the captured images like saving them or e-mailing them? Otherwise it's just some eye candy...

  9. Michael says:

    Absolutely beautiful, I love the break-down of everything. The effect is absolutely stunning. I could see this being really cool for stuff like cropping pictures, or maybe even games like a JS-driven FPS almost, or even better, a puzzle game like ISpy or Where's Waldo!!!
    Looks like I found a new summer project. ;)

  10. Same question as steve, can you save the snapped images?

  11. Soh Tanaka says:

    Very clever and cool!! :-)

  12. dlv says:

    amazing... stunning !

    my congratulation for this !!!!

  13. Tino says:

    WOW - there are some brilliant ideas combined in this Tutorial. I haven't ever thought about blurring an image with multiple semitransparent copy's of it.
    The way you crop the shots is simple and elegant.

    This was inspiring to read. Best of the week if not the month.
    Thanks a lot!

  14. Rafael Vale says:

    Congrats man! What a nice work =)

  15. Michael says:

    @Steve Yakoban

    If you send the coordinates of the position to a server-side script, such as PHP, using AJAX, then you can crop the picture accordingly and then email it or save it; not too hard to implement really.

  16. Martin Angelov says:

    Thanks for the great comments fellas!

    Glad you like it.

  17. NetKit says:

    This is a fantastic effect! I love it :)

  18. Lucifix says:

    If there would be chance to add zoom this effect would be perfect ;)

  19. Fortyseven says:

    This is really clever stuff. Good job. :)

  20. Anis says:

    Hi
    This is a great plugin,
    Is there an option for the user to resize the size of the snapshot?

  21. SM says:

    Great solution. Thanks

  22. graffiti says:

    my contrib to get pos of the thumb created

    alert('Top: '+position.top+'px, Left:'+position.left+'px');

  23. Magnus says:

    I sure like this plugin, the authors did a good job. When i tested it i hade the same quesion as others, is it possible to save the snapped images? yes it is.

    What i did was a fast test, i wrote a simple WCF service , some ajax calls and the thing worked. i shared the stuff at http://bit.ly/dulsPF , in swedish but you can always Goggle Translate it to get a clue.

  24. Armine says:

    Really!!! Thanks

  25. Thats awesome!

    Its runs realy smoothly. I wonder if someone could use this in a website, would be pretty cool.

  26. Eric V says:

    Amazing ! PHP code to get those snapshots for another tutorial ? ;)

  27. woipad says:

    so cool!very nice!
    I'LL use it of my website!
    thanks!

  28. rahul says:

    wow Amazing !

  29. Beben says:

    so amazing...clever clever

  30. J.Nik says:

    This is an amazing idea. It works smoothly even in IE!

  31. Derek says:

    Actually, you can use cursor: none in CSS3. See here: http://www.w3.org/TR/css3-ui/#cursor
    Anyway, this demo is very awesome. :D

  32. Una says:

    Fab, I would love to try this with a few of my photos.
    Do the images have to come from Flckr? Or can they be from anywhere?
    thanks,

  33. Mircea says:

    Thank you so much, beautiful design.

  34. XeBii says:

    Very Nice Effect Martin
    <3 Love it!!!

  35. Nasir Zia says:

    Can we have Zoom in / Zoom Out effect upon mouse scrolling up/down while capturing a shot?
    BTW Nice plugin with amazing idea :D

  36. Is this plugin only designed to snapshot images? I would like to use it to take a snapshot of ANY area of a full webpage. Example: The user clicks somewhere in the footer or header of a website and a snapshot is created.

    Is this possible with your plugin?

  37. Srdjan says:

    Did anyone have extension of this plugin with possibility of saving thumbs?

Add Comment

Add a Reply

HTML is escaped automatically. Surround code blocks with <pre></pre> for readability.
Perks:   **bold**   __italics__   [some text](http://example.com) for links