Building a Google Plus inspired image gallery

I recently built a Google Plus inspired image Gallery as an extension for the Alfresco ECM product which won first place in Alfresco developer challenge. Now I’d like to share my insights, explain how I built it and give you a starting point to build your own galleries based on the great G+ gallery design.

Screenshot of Alfresco Gallery Plus extension

The G+ image grid disected

The main focus of this article will be on the image grid. Let’s start with a look on the features of the original G+ image grid to find out what it takes to recreate it. To illustrate the features I am using Thomas Hawk’s G+ gallery which has some amazing images (check it out).

  1. Justifed alignment: All images are displayed in rows and aligned to left and right borders. 
  2. Even spacing: All Images are evenly spaced (6px spacing, i.e. 3px margin around each image).  
  3. Natural order: Images don’t have a special ordering to better fit in the grid. I first thought the perfect alignment was solved with some sort of bin packing algorithm, but that is not the case und is not needed. Images are usually sorted by date from latest to oldest.
  4. Cropped thumbnails: To achieve the justified layout some portions of the images are hidden (cropped). When I first checked out the G+ gallery I saw most of the cropping done with HTML but now it looks like Google generates thumbnails in any arbitrary resolution or cropping on the server-side.
      
    Both images have a similar URL which only differs in a part which specifies the resolution. The left image contains the path /w300-h150-n-k/ whereas the right image contains the path /w150-h150-n-k/ and therefore is cropped differently on the server side.
  5. Big title image: There is a “title” image or (album cover image) which spans two rows.  
  6. Comment badges: The number of comments is displayed on each image thumbnail. 
  7. Dynamic resolution: The size of the images depends on the width of the browser window. G+ uses small images for smaller browser windows and larger images for wider browser windows, i.e. the image resolution adapts to the screen size. This is espacially useful for mobile devices which have lower resultion than desktop browsers.  
  8. Window resize: The image sizes change and the grid images are re-aligned dynamically when the browser window is resized.  
  9. Dynamic row height: This is a really subtle feature: Depending on the dimensions of the images in one row (e.g. if a lot of images in portrait format) some rows are rendered bigger in height than others. This helps portrait shots not to become too small.
  10. Popup Preview: When you hover over an image an animated popup appears and displays the image in a larger rendition.
  11. Infinite scroll: When you scroll to the bottom of the page more images are loaded automatically.

As far I have seen G+ servers generate different sizes of thumbnails that are used for the window specific thumbnail size, dynamic row height and the preview popup. At times your browser will load 10-20 differently sized thumbnails of an image.

I bet the feature list above is not even complete but it shows the design and engineering effort that went into this seemingly simple gallery grid.

What if you don’t have Google’s infrastructure and manpower?

For my one man competition contribution I couldn’t possibly implement all those features. I axed the double-row-spanning title image, different thumbnail sizes and the preview popup:

  • Only one thumbnail size (120 pixel height, width depending on image aspect ratio)
  • No server side cropping, only a single static thumbnail for each image. 

Still I came pretty close to the original with all the other features.

How does the cropping in the Browser work?

To better understand how the G+ image grid worked I studied the HTML source, which basically looks like this:

The main insight I took from this is they way the images can be cropped: using a DIV with overflow:hidden and changing margin-left of the image to define the x-offset.

How to align the images?

Once I started experimenting I realized that the image alignment is not that hard to do. Let’s say we have three images and are using a fixed thumbnail height of 120 pixel.

image 1: 200x120
image 2: 180x120
image 3: 120x120

Let’s also assume we want to fit these images in a row with a given width of 460 pixels.

I started to build rows of images by adding image by image until the window width is met or surpassed.

1 image: 200 OK (<460)
2 images: 200 + 180 = 380 OK (<460)
3 images: 380 + 120 = 500 surpassed (break >460, 40 pixels too long)

So putting all three images in a row would make it 40 pixel too long. The only thing that needs to be done now is to crop all the images by overall 40 pixels to perfectly align them with the window width.

My naive approach was to simply devide the excess pixels, so 40 pixel / 3 images = 13 pixels/image You have to be careful with the integer division though. To perfectly distribute the 40 pixels you need to crop one additional pixel from one of the images:

cropped image 1: 200 - 14 = 186x120
cropped image 2: 180 - 13 = 167x120
cropped image 3: 120 - 13 = 107x120

If you sum up the witdh now you get exactly 460 pixel. Combining these values with the cropping method from the previous section we get the following HTML code for the three images.

<div style="overflow:hidden; width:186px; height:120px;">
  <img src="image1.jpg" style="width:200px; height:120px";
      margin-left:-7px"/>
</div>
<div style="overflow:hidden; width:167px; height:120px;">
  <img src="image2.jpg" style="width:180px; height:120px";
      margin-left:-6px"/>
</div>
<div style="overflow:hidden; width:107px; height:120px;">
  <img src="image3.jpg" style="width:120px; height:120px";
      margin-left:-6px"/>
</div>

As you can see the negative margin-left is used to center the cropped area horizontally. On thing I left out here is the spacing between images. We have 6 pixels of spacing between each image that have to be added in the inital sum.

This naive approch worked pretty well even with only a single thumbnail size (120 pixels height). In a later iteration I changed the distribution of the crop-pixels though, because when equally distributing the excess pixels, portrait images tend to get too small in width. That’s why I based the crop amount on the image width, with the result that wider images are cropped more than narrow ones.

The server side

As you see above the image layout algorithm needs the widths of the individual images to do it’s mojo. In my Alfresco extension I leveraged the metadata extraction capabilties to get to the thumbnail resolution. The resulting JSON data that is finally generated on the server side is a simple array with all the image data (here is a single image as an example):

{ "thumbs" : [
  {
    "thumbUrl" : "api/node/workspace/SpacesStore/c2f5e06f-ee15-4b0f-9e6c-1f734b4db45f/content/thumbnails/galpThumb120",
    "title" : "2010-05-02, 2 images, IMG_2173 - IMG_2174 - 5096x2320 - SCUL-Smartblend.jpg",
    "twidth" : 300,
    "theight" : 120,
    "description" : "",
    "author" : "Administrator",
    "nodeRef" : "workspace://SpacesStore/c2f5e06f-ee15-4b0f-9e6c-1f734b4db45f",
    "name" : "2010-05-02, 2 images, IMG_2173 - IMG_2174 - 5096x2320 - SCUL-Smartblend.jpg"
  }
]}

The most important information here are the thumbnail dimensions and the thumbUrl that are used for the gallery grid. If you are interested in the details of the server side code in my Gallery+ extension you can have a look in the webscript.

Standalone JQuery demo version

To demonstrate the grid rendering independently of the full the Alfresco extension I moved the grid generation code to a standalone website with the Javascript logic based on jQuery (the original extension is based on YUI). You can see the example in action at the following URL: http://fmaul.de/gallery-grid-example/

If you try it out, make sure to resize your browser to see the dynamic resizing in action. This is not a full jQuery gallery component, sorry – it is just meant to demonstrate the rendering but you are welcome to further extend the code to a full blown jQuery gallery.

Note that the example gallery is not backed by a REST or thumbnail server, it uses this static JSON file as image source for the purpose of demonstration. The page is built using html5 boilerplate and therefore my complete implementation can be found in the scripts.js file.

 

29 thoughts on “Building a Google Plus inspired image gallery

  1. Thank you for taking the time to figure this out and posting. Seems like you’re the only one so far that’s been able to crack how Google did their’s and is willing to share the secret.

  2. What is the logic on wrapping to next line? I see that you split the excess into the pictures on that line. Is it just that once you have hit the page width and/or exceeded, it’ll wrap?

  3. Hi Johnie, yes I let the browser wrap the images automatically. They are basically all in one long row but the image widths are calculated in such a way that the images wrap at a specific point.

  4. I love the script but there’s a small change I would make: When resizing the browser the images flicker because their width is constantly being recalculated.
    I think it’s better to (like G+) only recalculate the images when resizing is complete. So I replaced the window resize event handler:
    var resizeTO = false,
    $imgarea = $(‘#imagearea’);
    $(window).resize(function(){
    $imgarea.width($imgarea.width());
    if(resizeTO !== false)
    clearTimeout(resizeTO);
    resizeTO = setTimeout(function() {
    $(‘#imagearea’).css(‘width’, ”)
    // layout the images with new width
    GPlusGallery.showImages($imgarea, items);
    }, 200); //200 is time in miliseconds
    });

    Maybe you could put the code on github?

  5. Pingback: Flickr ‘Justified’ Layout in JQuery | Wackylabs.net

  6. Good job. So I understand there really aren’t any other alternatives? I’ve copied pretty much everything over so I can test it: http://www.mirelmasic.nl/troep/gallery, but the images.json file is beyond my understanding (which isn’t big btw).

    I don’t understand how the thumburl links to a folder and not a jpg, same for noderef. I don’t even know what noderef means.

    How did you create the json file? Did you create the thumbnails manually? And why the popup when clicking on an image?

    cheers, Mirel

  7. Hi Mirel, I generated the JSON file with an Alfresco Server which was the original platform I developed this on. Don’t be confused by the URLs of the thumbnails. Originally it is a server side script which provided the images but it could simply be image files in a directory. You only need to have a relative URL in the JSON file pointing to the thumbnail image.

  8. Hello,

    Back in October 2011, I also wrote a Google+ like photo gallery using jQuery. I called it jGlance and can be found here : http://moewashere.com/jglance/ . It included a demo, docs, and instructions. It also features the hover states.

    I found it interesting that another fellow developer did the same thing. Good work! :)

  9. Pingback: Google Plus Image Gallery | Moe Was Here

  10. Thanks for this article! You said Google crops images and when I look at your demo gallery I see that you also crop all images.
    I analyzed Google’s gallery layout too and I think Google crops just a small number of images: The big title image and images that are extremely wide or extremely high. All other images are in their original ratio. Maybe you want to improve your work :-)

  11. Google image resizer is free to use if you have your photos on Google+! You can access your photos like this: https://www.googleapis.com/plus/v1/activities/z12ixpgiewebzln5m04chfsyalasjjnwulo0k?alt=json&fields=object(attachments(fullImage(height%2Curl%2Cwidth)))&key=AIzaSyAHKz9oRYV7zZr-Qd9g2IgJeOHiKmoAjJM
    (not sure if this will work with your IP and my API key, but if you register your key, you’ll get it) and request to photo like this:

    https://lh4.googleusercontent.com/-6vJ4jekctNw/T75andEs9MI/AAAAAAAAAMs/KrDtPpEaKAg/w561-h372-n-k/DSC_4810.jpg

    /w561-h372-n-k does all the speedy magic!

  12. Could you please show how we could add a larger image at the start of the stack, maybe covering the height of 2 lines of thumbnails

    ive tried, but spacing seems to break

  13. I am using the jQuery plugin by Pedro Botelho, however I would like to add the 2 row initial image capability. If anyone has some suggestions how that can be done, I would love to get the code.

    Todd

  14. Great piece of code!

    I had one concern. When adding more items it seems to break the alignment on the right side.

    Can duplicate/test by just calling you images.json .getJSON twice.

  15. Pingback: Crafting The Perfect Photo and Video Viewing Experience | Trovebox | Photo Management for Organizations

  16. Thanks , I have just been looking forr information about this subject for a long time and
    yours is the best I have came upon till now. But, what in regards to the conclusion?
    Are you sure about the source?

    Haave a look aat my site – cpatalking.com; Louann,

  17. The popularity of Android is increasing due to the availability of Android
    phones and tablets in less cost. My old man has told me that Alipip
    was almost a part of the family at this point, and there’s nothing wrong with that.
    Revolutionary technologies are expected in the coming years.

  18. I’ve been browsing online more than three hours
    today, yet I never found any interesting article like yours.
    It’s pretty worth enough for me. Personally, if all site owners and bloggers made good
    content as you did, the net will be a lot more useful than ever before.|
    I could not refrain from commenting. Well written!|
    I will right away clutch your rss feed as I can not to find your email
    subscription hyperlink or e-newsletter service. Do you’ve any?

    Please permit me understand so that I could subscribe. Thanks.|
    It is appropriate time to make some plans for the future and
    it is time to be happy. I’ve read this post and if I could I wish to suggest
    you some interesting things or suggestions. Perhaps you could write next articles referring
    to this article. I wish to read even more things about it!|
    It is appropriate time to make some plans for the long
    run and it’s time to be happy. I’ve learn this put up and if
    I may I want to suggest you few interesting things or suggestions.
    Perhaps you could write subsequent articles regarding this article.
    I desire to read more things approximately it!|
    I’ve been browsing online greater than three hours nowadays, but
    I never discovered any interesting article like yours.
    It is pretty price sufficient for me. Personally, if all web owners
    and bloggers made just right content as you did, the net will be much more helpful than
    ever before.|
    Ahaa, its good dialogue concerning this piece of writing here at this website, I have
    read all that, so at this time me also commenting
    here.|
    I am sure this post has touched all the
    internet visitors, its really really pleasant article on building up new web site.|
    Wow, this post is nice, my sister is analyzing such things,
    thus I am going to convey her.|
    Saved as a favorite, I really like your web site!|
    Way cool! Some very valid points! I appreciate you
    writing this article plus the rest of the website is also very good.|
    Hi, I do think this is an excellent blog. I stumbledupon it ;) I am going to come back once again since I book marked it.
    Money and freedom is the greatest way to change, may you be rich and continue to help others.|
    Woah! I’m really loving the template/theme of this blog. It’s simple, yet effective.
    A lot of times it’s hard to get that “perfect balance” between user friendliness
    and visual appearance. I must say you’ve done a amazing job with this.
    Also, the blog loads very quick for me on Safari. Outstanding Blog!|
    These are actually enormous ideas in regarding blogging.
    You have touched some pleasant points here. Any way
    keep up wrinting.|
    I really like what you guys are up too. Such clever work and coverage!
    Keep up the awesome works guys I’ve added you guys to blogroll.|
    Howdy! Someone in my Myspace group shared this site with
    us so I came to take a look. I’m definitely loving the information.

    I’m bookmarking and will be tweeting this to my followers!
    Fantastic blog and excellent design and style.|
    I like what you guys are usually up too. This sort of clever work and coverage!

    Keep up the terrific works guys I’ve included you guys to my own blogroll.|
    Hello would you mind stating which blog platform you’re
    working with? I’m looking to start my own blog in the near future
    but I’m having a tough time deciding between BlogEngine/Wordpress/B2evolution and Drupal.
    The reason I ask is because your design seems different
    then most blogs and I’m looking for something completely unique.
    P.S Apologies for getting off-topic but I had to ask!|
    Howdy would you mind letting me know which hosting company you’re utilizing?

    I’ve loaded your blog in 3 different web browsers
    and I must say this blog loads a lot quicker then
    most. Can you recommend a good hosting provider at a honest
    price? Thanks, I appreciate it!|
    Everyone loves it when individuals get together
    and share opinions. Great site, keep it up!|
    Thank you for the auspicious writeup. It in fact was a amusement account it.
    Look advanced to more added agreeable from you! By the way,
    how could we communicate?|
    Hey just wanted to give you a quick heads
    up. The words in your article seem to be running off the screen
    in Ie. I’m not sure if this is a format issue or something to do with browser compatibility but I figured I’d post
    to let you know. The design and style look great though!
    Hope you get the problem resolved soon. Cheers|
    This is a topic that’s close to my heart… Take care!
    Where are your contact details though?|
    It’s very simple to find out any matter on web as compared to textbooks, as I
    found this post at this web page.|
    Does your website have a contact page? I’m having problems locating it but, I’d
    like to shoot you an email. I’ve got some creative ideas for your blog you might be interested in hearing.

    Either way, great website and I look forward to seeing it develop over time.|
    Greetings! I’ve been following your website for a while now and finally got the courage to go ahead
    and give you a shout out from Austin Texas!
    Just wanted to tell you keep up the excellent work!|
    Greetings from Ohio! I’m bored to death at work so I decided
    to check out your website on my iphone during lunch break.
    I really like the information you present here and can’t wait to
    take a look when I get home. I’m amazed at how fast your blog loaded on
    my cell phone .. I’m not even using WIFI, just 3G ..
    Anyhow, awesome site!|
    Its like you read my thoughts! You appear to grasp a lot approximately this, like you
    wrote the e book in it or something. I believe that you
    just could do with a few % to power the message home a little
    bit, but instead of that, that is magnificent blog.
    An excellent read. I’ll certainly be back.|
    I visited various blogs but the audio feature for audio songs existing at this site is actually excellent.|
    Howdy, i read your blog occasionally and i own a similar one and i
    was just wondering if you get a lot of spam feedback?
    If so how do you prevent it, any plugin or anything you can suggest?
    I get so much lately it’s driving me crazy so any assistance is very much appreciated.|
    Greetings! Very useful advice in this particular post! It is
    the little changes that make the most important changes.

    Thanks for sharing!|
    I seriously love your website.. Pleasant colors & theme.
    Did you make this site yourself? Please reply back as I’m wanting to create my own blog and would like to
    find out where you got this from or exactly what the theme is called.

    Thanks!|
    Howdy! This post could not be written much better! Going through this
    article reminds me of my previous roommate! He constantly kept talking about this.
    I am going to forward this article to him.
    Fairly certain he will have a very good read.
    Many thanks for sharing!|
    Whoa! This blog looks just like my old one! It’s on a completely different subject but it has pretty much the same page layout and design.

    Great choice of colors!|
    There’s certainly a lot to know about this subject.

    I like all of the points you’ve made.|
    You have made some decent points there. I checked on the
    net to find out more about the issue and found most people will go along
    with your views on this web site.|
    Hi there, I log on to your blog daily. Your writing style is awesome,
    keep it up!|
    I simply could not go away your website prior to suggesting that I really enjoyed
    the standard info an individual supply on your guests?
    Is gonna be again often to inspect new posts|
    I needed to thank you for this very good read!!

    I definitely enjoyed every bit of it. I have got you bookmarked to look at new things you post…|
    Hi there, just wanted to say, I liked this article.
    It was practical. Keep on posting!|
    I drop a comment whenever I especially enjoy a article on
    a site or if I have something to contribute to the discussion.
    Usually it’s triggered by the fire communicated in the article I looked at.
    And after this article Building a Google Plus inspired image gallery | techbits.de.
    I was actually moved enough to create a commenta response ;) I do have 2 questions
    for you if you tend not to mind. Could it be
    only me or does it appear like a few of these remarks appear as if they are left by brain dead people?
    :-P And, if you are writing on other online sites, I’d like to
    follow you. Would you list every one of your shared sites like your Facebook page,
    twitter feed, or linkedin profile?|
    Hi there, I enjoy reading through your article. I wanted to write a little comment to support you.|
    I constantly spent my half an hour to read this webpage’s posts daily along with a mug of coffee.|
    I every time emailed this website post page to all my associates, since if like to read it next my links will too.|
    My programmer is trying to persuade me to move to .net from PHP.

    I have always disliked the idea because of the expenses.
    But he’s tryiong none the less. I’ve been using WordPress on
    several websites for about a year and am nervous about switching
    to another platform. I have heard great things about
    blogengine.net. Is there a way I can transfer all my wordpress posts into it?
    Any kind of help would be really appreciated!|
    Hi there! I could have sworn I’ve been to
    this site before but after browsing through many of the articles I realized it’s new
    to me. Nonetheless, I’m definitely pleased I found it and I’ll be bookmarking it and checking back often!|
    Terrific article! That is the kind of info that are supposed to be shared
    across the web. Shame on Google for now not
    positioning this put up higher! Come on over and discuss with my web site .

    Thank you =)|
    Heya i’m for the first time here. I found this board and I find
    It truly useful & it helped me out a lot. I hope to
    give something back and help others like you aided me.|
    Hi there, There’s no doubt that your website could be having internet browser compatibility
    problems. Whenever I look at your blog in Safari, it looks fine however, if opening in I.E., it’s got some overlapping issues.
    I simply wanted to provide you with a quick heads up!
    Aside from that, fantastic blog!|
    Somebody essentially assist to make seriously articles I’d state.
    This is the very first time I frequented your web page and so far?
    I surprised with the research you made to create this particular publish incredible.

    Wonderful process!|
    Heya i am for the first time here. I came across this
    board and I to find It really useful & it helped me out
    a lot. I am hoping to give something again and help others such as you helped me.|
    Hey there! I just would like to give you a huge thumbs up for the great information you have got
    here on this post. I will be coming back to your blog for more soon.|
    I always used to study paragraph in news papers but now as I am a user of internet thus from now I am using net for articles
    or reviews, thanks to web.|
    Your means of telling all in this post is in fact pleasant, every one can effortlessly be aware of it,
    Thanks a lot.|
    Hi there, I found your website by way of Google at
    the same time as searching for a similar subject, your website got here up, it appears great.
    I’ve bookmarked it in my google bookmarks.
    Hello there, just was aware of your weblog through Google, and located that it’s truly informative.
    I am gonna watch out for brussels. I will be grateful for those who proceed this in future.
    Numerous folks will be benefited from your writing.
    Cheers!|
    I’m curious to find out what blog system you’re using? I’m having some small
    security problems with my latest blog and I’d like to find something more safe.
    Do you have any recommendations?|
    I am extremely impressed with your writing skills as well as with the layout on your
    weblog. Is this a paid theme or did you customize it yourself?

    Either way keep up the nice quality writing, it’s rare to see a nice blog like
    this one these days.|
    I am really inspired with your writing talents and also with the layout in
    your weblog. Is this a paid subject matter or did you customize it your
    self? Anyway stay up the nice high quality
    writing, it is rare to see a great blog like this one
    these days..|
    Hello, Neat post. There is a problem along with your web
    site in internet explorer, could test this? IE still is the
    marketplace leader and a large component of people will omit your wonderful writing
    because of this problem.|
    I am not sure where you are getting your info, but good topic.
    I needs to spend some time learning much more or understanding more.
    Thanks for wonderful info I was looking for this
    info for my mission.|
    Hello, i think that i saw you visited my blog thus i came to “return the favor”.I am trying to
    find things to enhance my website!I suppose its ok to use some of
    your ideas!!\

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>