Flickr ‘Justified’ Layout in JQuery

Update: I’ve done a updated version, with scrolling, and various input boxes for changing the tags to search for here: http://jsbin.com/upinek/15. Enjoy.

Someone posted recently on Stackoverflow asking how the new Flickr Justified photo pages had been created. i.e. how to create multiple rows of evenly spaced images without cropping the images to fit. It was something I had been wondering about for a while, so I did a bit of investigation.

A similar question had been answered to do with the Google+ photo page, but that uses cropped thumbnails to create the effect, something I thought it would be better to avoid.

I’m not 100% sure that this is indeed how Flickr do it, but it produces such nice results that I thought I would show you what I came up with.

The key to this method is to make the height of the row variable.

The first thing I did was pick an arbitrary height, the maximum you want each row to be. Then get the width of the parent div, in this case a div with class “picrow”. Then keep a copy of all the widths of the photos, scaled to match this height. I also set an margin to be included later at 5 px.

var border = 5;
var h = 320;
var w = $("div.picrow").innerWidth();
var ws = [];
 $.each(photos, function(key, val) {
 var wt = parseInt(val.width_n, 10);
 var ht = parseInt(val.height_n, 10);
 if( ht != h ) { wt = Math.floor(wt * (h / ht)); }
 ws.push(wt);
});

Then I counted the number of photos that are going to appear in the row, along with their accumulated width until I reach the width of the parent div.

// number of images appearing in this row
var c = 0;
// total width of images in this row - including margins
var tw = 0;

// calculate width of images and number of images to view in this row.
while( tw * 1.1 < w)
{
  tw += ws[c++] + border * 2;
}

Then you can calculate the ratio of the actual width of the div to the accumulated width of the photos to include in the row.

Finally, take the images, one at a time, and resize and add to the div. Again, keep track of the actual accumulated width.

// Ratio of actual width of row to total width of images to be used.
var r = w / tw; 

// image number being processed
var i = 0;
// reset total width to be total width of processed images
tw = 0;
// new height is not original height * ratio
var ht = Math.floor(h * r);
while( i < c )
{
  var photo = photos[i];
  // Calculate new width based on ratio
  var wt = Math.floor(ws[i] * r);
  // add to total width with margins
  tw += wt + border * 2;
  // Create image, set src, width, height and margin
  (function() {
    var img = $('<img/>',
     {class: "photo", src: photo.url_n, width: wt, height: ht}).css("margin", border + "px");
    var url = "http://www.flickr.com/photos/" + photo.owner + "/" + photo.id;
    img.click(function() { location.href = url; });
    $("div.picrow").append(img);
  })();
  i++;
}

That is the basics. In the full code I have added multiple rows, and support for refreshing on resizing of the window, and making it easy to change the tag searched for.

 

You can view the full code on JSBin here: http://jsbin.com/upinek/3/edit#javascript,html and you can see it running here: http://jsbin.com/upinek/3

There is certainly room for scope for adding other features, such as dynamically creating new rows where there is more content, and adding overlays to show photo titles etc., but hopefully this gives you a place to start. There is also an issue if one of the images it especially wide which I haven’t tracked down yet, so its not perfect by any means.

31 thoughts on “Flickr ‘Justified’ Layout in JQuery”

  1. Hi! I wrote the code on flickr.com. That is the right algorithm, or at least it is the one we used. A lot of random special cases came up and those were the bulk of the work (you already noticed the wide image issue). At some point I will try to write up what we did.

    1. Pagination is left as ‘homework’ for you to think about :)

      Ideally you’d want some form of infinite scroll feature like google image search, but I don’t know how you’d do that.

      Don’t forget, as a third party app you’re not meant to display more than 30 photos at a time as well, something I hadn’t considered initially.

  2. Thanks for the reply.
    Yeah, i want something similar to Google or Twitter. I have done it before, but never loading pictures with Javascript on the fly.

    What do you mean about loading more than 30 pictures?
    Thanks again.

  3. Hi Sam,
    first of all, big ups for your solution. it’s great!
    i tried to list instead my public photos and changed the following lines:

    method: "flickr.photos.search",
    api_key: "dbb49a0e2dcc3958834f1b92c072be62",
    tags: tags,
    tag_mode: "all",
    sort: sort,

    to:

    method: "flickr.people.getPublicPhotos",
    user_id: "[userid]"

    everything works fine, the array i get back has the same structure, and the html is appended correctly but i saw no images.
    that made me look into the code where i found out that my photoArray’s photo items don’t have any properties
    like “url_n” or “height_n” or “width_n” which you use for calculating the image’s dimension and url.
    in my array there are only _l, _m and _z versions of the photo, although i still have
    extras: "url_n,url_m,url_z,url_l" in my json call.

    do you have any idea why i can’t get any _n versions of my public photos?
    thanks!
    martin

    1. It is possible that url_n is only returned by flickr.photos.search. You can add user_id to the flickr.photos.search call as well and that should work fine.

  4. Hey Sam this is great, thanks for posting it!

    I’m having an issue though, in your example on jsbin the first two picrow divs contain nothing so there are only every two rows of images. I have checked it in firefox and chrome on a mac and chrome on windows 7. Any idea of what is going wrong?

    1. Thanks. There is a bug in the ‘3’ version which is fixed in the ’15’ version. The first two photos returned by Flickr don’t have a url_n size, so no width is returned and the calculation produces an invalid value, which means the first two rows are being skipped. Hope that helps.

  5. I think there is error in code. I tested a lot and found out that if there are, lets say, 11 results, only 8 photos will be shown (Flickr search “bonto” -> interesting photos). In my example JSON return 27 results, but only 25 photos was shown.

  6. Very nice post !!!! I wanted to create a gallery with this layout and your post is helping me lot. I think there is little tricky problem at the code that makes the photos wrap sometimes.

    You calculate a ratio (r) and you use this to downsize the images but you have to do the downsizing at the border too or downsize the image+borders using r and then use that result-(2*border) for image width , else the total width may be larger than the container div width.

    Thanks a lot for sharing ! Your code rocks !

  7. hi,
    I want to create a different gallery for some albums I have in my computer. I want to organize the view of the gallery in this way. how can I do that?
    If I’m not wrong you take the images directly from Flickr…
    and…is it possible to incorporate such code in WordPress? or create a an external link to such created pages of galleries?

    thank so much!!

  8. I also need this for a gallery website I am making. I see that the row sometimes breaks and there is a small img tag without a src inside the code. Is this because of flickr? Would it work with my own pictures?

  9. Hi there,
    I stumbled upon this page looking for possible layouts for a gallery website, really a neat idea.
    Just two questions about you code (sorry, if I got that wrong):
    – you resize the pictures by the ratio r calculated to fit your original row
    into you container; however the margin around the images is fixed.
    doesn’t this produce a slight error, if there’s a different number of
    images per line (probably it’s just a few pixels)?
    – in the last loop, you stress to “keep track of the actual accumulated
    width” (tw). however, that variable is never read, so i don’t really see
    why you’re doing this..

    cheers, and thanx for your post, Christoph

    1. The ‘border’ variable is added per image, to compensate for the margin added to each image.

      The ‘tw’ variable is used in plenty of places, so not quite sure about your comment – see the updated version 15 link at the start of the page.

  10. Hey Sam,
    Incredible work.
    Was wondering if there was a way to get this working from a regular directory on a web server. I have most of my photos spread across some subdirectories and would like to display all of them in this way. I guess I know how to get it working with PHP, but purely jQuery would be awesome!!

    1. The problem with that is that the code replies on there being different sized images available, as we don’t really want to have to scale images too much. I’m sure it could be done, but it would involve a pretty significant re-write.

  11. Hi Sam,

    Incredible work.
    If I’m not wrong you take the images directly from Flickr.com
    and…is it possible to incorporate such code for my own photo gallery I have create a image array in javascript & image having different height and width . What pieces of code i have to change. Plz… Help. I have to implement it tomorrow.

Leave a Reply