Creating polaroids using Flickr API (also how to space rotated elements correctly)




Some might say polaroids are a bit overdone when it comes to displaying your photos, but I’m going to be using the Flickr API to get a selection of images and hang them on a virtual line.

There’s a bit more to this though, as I’ll be showing you how to calculate the actual widths of our hanging polaroids so that we can fit as many on the line as possible without having them overlap. This may sound trivial, but when we’re hanging our pictures at an angle it becomes slightly more complex.

Technologies Used:

Demo

Find the demo here

Libraries used in this demonstration:

Browser support:

Should be supported by all modern browsers. The CSS3 transformations require a modern browser.

Step 1: Set up our container

This is pretty simple, we’re just going to create a div to hold all of our pictures:

<div id="pictures"></div>

We’ll be filling this up later on using jQuery and styling it using CSS.

Step 2: Get some images from Flickr

I’m going to wrap this in a function called ‘getPics’, not very imaginative, but it will allow us to re-call the function on an event later on. The function accepts one argument, the ‘tag’ we wish to search for on Flickr:

var getPics = function (tag) {
var url = "http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?";
$.getJSON( url, {
tags: tag,
tagmode: "any",
format: "json"
})
.done(function( data ) {
// do something with the data
});
}

As you can see, it’s a pretty simple ajax call from jQuery that just returns the JSON data from the Flickr api. All of the photo information is contained in the ‘items’ property of the returned object. So, we can loop over these items to insert them as images into our container:

    // do something with the data
var $container = $('#pictures');
var dim = 200; // The width we want our picture to be
$.each( data.items, function( i, item ) {
var $polaroid = makePicture( item );
$container.append($polaroid);
$polaroid.css('left', dim*i);
});
// ...
// later on in the code
// ...
// item is the item returned from flickr
var makePicture = function (item ) {
// make our image element
var $img = $('<img>').attr('src', item.media.m);
var $imgLink = $("<a class='img' target='_blank' />").attr('href', item.link);
var $polaroid = $("<div class='polaroid' />");
$imgLink.append($img);
$polaroid.append($imgLink);
return $polaroid;
}

Notice I’ve added a function for creating our polaroid objects to help clean up the code a little. Now, with a little styling we could just stop there, but we want our pictures to hang. To get this effect we’ve got to change things a bit. Here are the styles I’m using for the pictures for the moment. Note this is done using LESS to speed up development, but even if you’re not familiar with it you should get the overall jist of it.

@polaroidcolor: #eec;
#pictures {
float: left;
width: 100%;
max-width: 100%;
white-space: nowrap;
position: relative;
.polaroid {
float: left;
border-width: 10px 10px 36px 10px;
border-color: @polaroidcolor;
border-style: solid;
box-shadow: 0 6px 12px rgba(0,0,0,0.7);
overflow: hidden;
background: @polaroidcolor;
.img {
display: block;
overflow: hidden;
box-shadow: 1px 1px 2px rgba(0,0,0,1);
border: 1px solid #999;
}
}
}

One thing we have to fix is that our images are rectangular, but polaroids are square. We’re going to have to pick a new fixed width so that all our polaroids are the same size because thumbnails from Flickr are a complete mix of sizes. For arguments sake I’m just going to pick 200px for the moment, but we’ll be changing this later:

$img.load(function(){
var ratio = $(this).width() / $(this).height();
if(ratio >= 1){
// landscape
$(this).width((dim * ratio)); // note: dim is one of the arguments of the function
$(this).height(dim);
} else {
// portrait
$(this).height((dim / ratio));
$(this).width(dim);
}
$(this).parent().width(dim).height(dim);
// This sets the left offset of each of our polaroids
// to it's outerwidth * the number of polaroids we have,
// meaning we have a row of polaroids
$polaroid.css('left',($polaroid.outerWidth()*i));
});

This should give us some nice square images, like so:

Polaroids in a row

Polaroids in a row

 Step 3: Rotate your polaroids so that they ‘hang’

Now, we’re going to make our polaroids hang by applying a CSS3 transformation. I’m creating a less mixin for the rotations to avoid repeating a load of code, and I’ll create an animation for our polaroids so they ‘swing’ into place and eventually come to rest. I played around with the final angle until it looked natural to me.

So, first I’ll add a class to our polaroid:

$polaroid.addClass('hang');

Simple, now let’s set the styles for this class. This will be the final LESS CSS styling for our polaroids:

.origin(@x, @y) {
transform-origin: @x @y;
-ms-transform-origin: @x @y; /* IE 9 */
-webkit-transform-origin: @x @y; /* Safari and Chrome */
}
.rotate(@ang: 7deg, @scale: 1){
transform:rotate(@ang) scale(@scale);
-ms-transform:rotate(@ang) scale(@scale); /* IE 9 */
-webkit-transform:rotate(@ang) scale(@scale); /* Safari and Chrome */
}
@keyframes hangPics
{
0%   {.rotate(53deg, 2);}
20%  {.rotate(43deg);}
40%  {.rotate(48deg);}
60%  {.rotate(42deg);}
80%  {.rotate(45deg);}
100% {.rotate(43deg);}
}
@-webkit-keyframes hangPics /* Safari and Chrome */
{
0%   {.rotate(53deg, 2);}
20%  {.rotate(43deg);}
40%  {.rotate(48deg);}
60%  {.rotate(42deg);}
80%  {.rotate(45deg);}
100% {.rotate(43deg);}
}
@polaroidcolor: #eec;
#pictures {
float: left;
width: 100%;
max-width: 100%;
white-space: nowrap;
position: relative;
.polaroid {
float: left;
border-width: 10px 10px 36px 10px;
border-color: @polaroidcolor;
border-style: solid;
box-shadow: 0 6px 12px rgba(0,0,0,0.7);
overflow: hidden;
background: @polaroidcolor;
.rotate(45, 1);
.origin(0%,0%);
display:block;
position: absolute;
z-index: 1;
&.hang {
.rotate(43deg);
animation: hangPics 1s;
-webkit-animation: hangPics 1s; /* Safari and Chrome */
}
.img {
display: block;
overflow: hidden;
box-shadow: 1px 1px 2px rgba(0,0,0,1);
border: 1px solid #999;
}
}
}

Lets walk through this quickly. At the top we just have 2 LESS mixins that set the origin for our transformations and set the scale and rotation respectively. After that we have a CSS3 animation that gives a ‘hanging’ effect. It swings a bit right, then a little left, then a tad right, etc.

Now, looking down to our main .polaroid class, we can see that we’ve set the initial rotation to 45 degrees and the scale to 1. This ensures our animation will start with the polaroids already rotated slightly. Immediately after this we set the origin of transformations to the top left corner and add a few other necessities.

Now we have our .hang class. We’ve applied this to our polaroids just after the images inside have loaded. What this class does is set the base rotation for our polaroids to 43 degrees and give them the animation. Notice that 43 degrees is what our animations end at, so that our polaroids won’t suddenly jump to another rotation.

Once we’ve set all this up, our polaroids should animate in from a scale of two to one and rotate a bit before settling at a 43 degree rotation, like so:

Hanging Polaroids

Hanging Polaroids

But…as you may notice, they overlap quite a bit. To explain with a diagram:

Rotation

Now…how to solve this? We can use a bit of math here. What we want is to find out the actual width of our polaroids after rotation.

Step 4: Find our bounding box width

What we want is the width of the bounding box of our rotated rectangles. To do this we’ll use a bit of trigonometry and SOHCAHTOA.

Rotation diagram

Here, we know that \theta is our rotation angle of 43 degrees. We also know the outer width and height of our inner blue rectangle, x and y respectively. Using SOHCAHTOA we can find the width of our bounding box. We know the a is the adjacent to \theta and x and b is opposite to \theta and y. To work out a+b we can do this:

a + b = x \cos \theta + y \sin \theta

And this gives us our true bounding box width. This is easily translated into javascript and jQuery, fortunately, using the Math library built into javascript.

Step 5: Set the proper spacing of our polaroids

Now we can set it so that our polaroids won’t overlap eachother. Using the formula above, instead of setting the left position to our elements outerwidth, we set it as so:

    // This sets the left offset of each of our polaroids
// to it's outerwidth * the number of polaroids we have,
// meaning we have a row of polaroids
var x = $polaroid.outerWidth();
var y = $polaroid.outerHeight();
var angle = 43 * (Math.PI/180);
var actualWidth = Math.abs((y * Math.sin(angle)) + (x * Math.cos(angle)));
// The extra y * sin(angle) is so that our first polaroid doesn't hang off the edge.
$polaroid.css('left',actualWidth * i + Math.abs(y * Math.sin(angle)));

And finally our polaroids should no longer overlap:

Final Polaroids

Final Polaroids

Wonderful! Now our polaroids a nicely spaced apart with no overlap.

Step 6: Extend, extend, extend

I’ve extended my example so that the polaroids overlap slightly but on hover the hovered item gets put to the top, sort of making the past mathematical example completely unnecessary…D’oh! Oh well, it was a good exercise nonetheless and it did help me to find the offset of the first element to stop it from only half appearing. Take a look:

Conclusion

Now we know how to create a simple polaroid element and we’ve also figured out how to find the actual width of our rotated elements using jQuery and javascript. The problem of finding the bounding box for a rotated rectangle is actually fairly simple to work out which is a relief, and I’m sure we’ll find many uses for this simple little formula in the future.

Leave a Reply