Thursday, September 26, 2013

How to create your own image gallery plugin with JQuery

Hey guys,
Today I want to try to create an image gallery plugin with you. We have already covered how to create a lightbox plugin, so you get a nice pop-up dialog with your image adjusted in size to your screen resolution.
My next question was how to position multiple thumbnails images on my screen so they would take all space available width-wise and images in each row would have the same height. So when I have images on page with different sizes like this:

I want them to be displayed like this:

So where to begin? I don’t want to just give you my final solution, but would rather walk you through the thinking process I had.
First thing I decided to define is the minimum height and width of the image. Let’s say by default I would try to resize all images so they have height of 200px. Then I need to know the width of the container so I can do the math to see how many images I can fit into one row. And then I also want to have a little gap between my images, within the row and between rows.
So here are our plugin options:
Margin – defines the gap between images, I would put default value of 8px,
MinHeight – minimum height of the image
MinWidth – minimum width of the image (in future I would also like to prevent images to get resized to anything what would cause their width to be less than minimum width).
Okay, so we have those parameters, now what? Let’s say we have a container with width of 1000 pixels and we have 10 images in our gallery, all the same size 300x200. So how many of them can I fit in one row? Three! That’s right, but we still have extra 100 pixels left in the row. At this point we have to resize our images so they would take all the space in the row. So total allocated width would be 300pixels times 3 = 900 pixels. These 900 pixels should be converted into 1000 pixels. Our height is 200 pixels (since every image is 200 pixels high). These 200 pixels will be converted into our new height value. So new height will be equal to 200 * 1000 / 900. And the result is 222.22 pixels. So that would be our new height. And in theory since we might have different width for the images in the row (but we would always bring them to the same height) we have to re-calculate new width for every image. Same way new image width equals to original width * new image height / original height. In our case new width for each image in a row would be 300 * 222.22 / 200 = 333.33.
So the idea is clear, right? We loop through all the images in our collection, resize each to minimum height, stack up until their total width would reach our container width, adjust sizes of images in the row, and continue with the next row.
Let’s begin. Create a new project, add a folder for images (I created 8 colorful blocks of different sizes). Create new page, put your images onto the page into a div, enclose each image with a hyperlink (remember we still want to use it with our lightbox plugin eventually). This is what I have so far:
    <div id="gallery"class="gallery">
        <a href="img/1.jpg">
        <imgsrc="img/1.jpg" border="0" /></a><a href="img/2.jpg">
        <imgsrc="img/2.jpg" border="0" /></a><a href="img/3.jpg">
        <imgsrc="img/3.jpg" border="0" /></a><a href="img/4.jpg">
        <imgsrc="img/4.jpg" border="0" /></a><a href="img/5.jpg">
        <imgsrc="img/5.jpg" border="0" /></a><a href="img/6.jpg">
        <imgsrc="img/6.jpg" border="0" /></a><a href="img/7.jpg">
        <imgsrc="img/7.jpg" border="0" /></a><a href="img/8.jpg">
        <imgsrc="img/8.jpg" border="0" /></a><a href="img/3.jpg">
        <imgsrc="img/3.jpg" border="0" /></a><a href="img/4.jpg">
        <imgsrc="img/4.jpg" border="0" /></a><a href="img/5.jpg">
        <imgsrc="img/5.jpg" border="0" /></a><a href="img/6.jpg">
        <imgsrc="img/6.jpg" border="0" /></a><a href="img/1.jpg">
        <imgsrc="img/1.jpg" border="0" /></a><a href="img/2.jpg">
        <imgsrc="img/2.jpg" border="0" /></a><a href="img/3.jpg">
        <imgsrc="img/3.jpg" border="0" /></a><a href="img/4.jpg">
        <imgsrc="img/4.jpg" border="0" /></a><a href="img/5.jpg">
        <imgsrc="img/5.jpg" border="0" /></a><a href="img/6.jpg">
        <imgsrc="img/6.jpg" border="0" /></a><a href="img/7.jpg">
        <imgsrc="img/7.jpg" border="0" /></a><a href="img/8.jpg">
        <imgsrc="img/8.jpg" border="0" /></a>
    </div>
As you can see I have copied some images multiple times so the gallery looks more full.
Now add link to jquery library:
<script language="javascript" type="text/javascript" src="/Scripts/jquery-1.9.0.js"></script>

Now create two new files: gallery.js (I also add prefix to all my plugins so I don’t get confused if this is my plugin I’m using or someone’s from the web, so I called my file pass.gallery.gs) and gallery.css (pass.gallery.css in my case).
This is the body of our jquery plugin:
/// <reference path="jquery-1.9.0.js" />

(function ($) {
    $.fn.gallery = function (options) {
        options = $.extend({}, $.fn.gallery.defaultOptions, options);

        // our code here
    };

    $.fn.gallery.defaultOptions = {
        minwidth: 100,
        minheight: 200,
        margin: 8
    };
})(jQuery);

As you can see I already added our options there and gave them their default values. Now let’s replace our comment with actual code to make whole thing work. Let’s declare variables we will need:
        var images = []; // array of images on the page
        varimgSizes = []; // array of images' sizes which we have to calculate and then apply to our images
        varwindowWidth = $(this).width(); // container width
        var margin = options['margin']; // gap between out images
        varminwidth = options['minwidth']; // minimum width
        varminheight = options['minheight']; // minimum height
        varimagesCount = 0; // image counter

Now we need to loop through all the images in the container and get their sizes:
        $(this).children().each(function () {
            images.push($(this).children()[0]); // add image to the images array
            varimageSize = []; // define an array to hold image width and height
            imageSize.push($($(this).children()[0]).width()); // add image width
            imageSize.push($($(this).children()[0]).height()); // add image height
            imgSizes.push(imageSize); // add image size to the imgSizes array
            imagesCount++; // increment image counter
        });

Now we would also need to declare another array where we would store indexes of images we added  to each row, remaining width of the row, and index of the image in the row (to see how many images we have in the row):
        var rowArray = []; // will contain images indexes which were added to the row
        varremainingWidth = windowWidth; // remaining width of the row, be default equals to container width
        varrowIndex = 0; // number of images added to the row

Now let’s loop through all images, resize them, place into one row until we maxed out the width:
        for (var i = 0; i < imagesCount; i++) {
            var image = images[i]; // gt current image
            varimageHeight = $(image).height(); // get image height
            varimageWidth = $(image).width(); // get image width
            varnw = minheight * imageWidth / imageHeight; // new image width scaled according to minimum height
            if (nw<= remainingWidth - margin) { // check if there is enough room in the row to place the image
                remainingWidth = remainingWidth - (nw + margin); // deduct from remaining width current image width and margin
                rowArray.push(i); // add image index to array of indexes added to the row
                imgSizes[i][0] = nw; // update image size with new width
                imgSizes[i][1] = minheight; // update image size with new height
                rowIndex++; // increment image index in the row
            }
            else { // if not enough room for the image
                if (rowIndex > 0) { // check if it was the first image added, if not
                    i--; // decrement image counter so we don't skip any images
                    AdjustRowSize(rowArray); // call a function where we need to re-calculate images sizes in current row
                }
                else { // if it was first image and its' size is already greater than container width
                    nw = windowWidth - margin; // calculate new width based on container width minus margin
                    imgSizes[i][0] = nw; // update image size with new width
                    imgSizes[i][1] = nw * imageHeight / imageWidth; // calculate new height based on scaled width and update image height
                }
                rowIndex = 0; // reset rowindex
                remainingWidth = windowWidth; // reset remaining width
                rowArray = null; // reset array
                rowArray = [];
            }
        }

Alright, almost there. So now we have to implement our function AdjustRowSize to scale images up to fill the row:
        function AdjustRowSize(imgIndexes) {
            varnum = imgIndexes.length; // get number of images in the row
            vartotalWidth = 0; // declare total width variable
            for (var i = 0; i < num; i++) { // loop through all images to calculate total width
                totalWidth += imgSizes[imgIndexes[i]][0];
            }
            // calculate new row height
            varnh = (windowWidth - num * margin) * minheight / totalWidth;
            // loop through images adjusting their widths according to our new height
            for (var i = 0; i < num; i++) {
                varnw = nh * imgSizes[imgIndexes[i]][0] / imgSizes[imgIndexes[i]][1];
                imgSizes[imgIndexes[i]][0] = nw;
                imgSizes[imgIndexes[i]][1] = nh;
            }
        }

Now we still need to go back, loop through all the images in our collection and change their sizes and add margin:
        var counter = 0; // image counter
        $(this).children().each(function () {
            $($(this).children()[0]).width(imgSizes[counter][0]); // set image width
            $($(this).children()[0]).height(imgSizes[counter][1]); // set image height
            $($(this).children()[0]).css('margin', margin / 2 + 'px'); // add margin
            counter++;
        });
And our plugin is ready. Let’s add some styles to gallery.css:
.gallery
{
    display: table;
    width: 100%;
    padding: 0;
    margin: 0;
}
.gallery a
{
    margin: 0;
    padding: 0;
}
.gallery aimg
{
    margin: 0;
    padding: 0;
    float: left;
}

and now it is time to call our plugin from the page:
$(document).ready(function () {
    $('#gallery').gallery(); // call plugin

    // when window is resized we want to reposition our images as well
    $(window).resize(function () {
        $('#gallery').gallery();
    });
});

And open your page in the browser now:

Resize browser’s window:
Works as expected J
I hope you enjoyed this tutorial and if you have any questions, comments, suggestions please feel free to write a comment, we would really appreciate your input.
Cheers,
Your GPTeam

0 comments:

Post a Comment