Jan 04, 2013

Creating a Pinterest Like Layout in ASP.NET

Pinterest is currently the world’s fastest growing social networking site and famous for the best functioning visual design. Do you love the look and feel of Pinterest? This post explains how to implement the same masonry dynamic layout with infinite scroll in ASP.NET.

techbrij pinterest

Here are the steps to implement it:

1. Download and add jQuery Masonry plugin. It is a dynamic grid layout plugin which arranges elements vertically, positioning each element in the next open spot in the grid and minimizes vertical gaps between elements of varying height.

2. We are going to display product with description in each tile. Here is the structure of Product and ProductRepository class.


public class Product {
    public string Url { get; set; }
    public string Description { get; set; }
}

public static class ProductRepository
{
    static List<Product> objList;
    public static IEnumerable<Product> GetData(int pageIndex, int pageSize)
    {
       int startAt = (pageIndex-1) * pageSize;
        objList =new List<Product>();
        Product obj;
        Random r = new Random();
        int n = r.Next(1, 7);    
        for (int i = startAt; i < startAt + pageSize; i++)
        {
            n = r.Next(1, 7);
            obj = new Product();
            obj.Url = String.Format("http://dummyimage.com/150x{1}/{0}{0}{0}/fff.png&text={2}", n, n * 50,i+1);
            obj.Description = "Description of product " + (i+1).ToString();
            objList.Add(obj);
        }
        return objList;
    }
}

In ProductRepository, GetData method takes pageIndex and pageSize parameters and generates dummy data and images of random heights.

HTML Structure:

3. In the aspx page, the head tag structure is as follows:


<head id="Head1" runat="server">
    <title>Pinterest Like Layout</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <!--[if lt IE 9]><script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
    <style type="text/css">
        body
        {
            background-color:#EEEEEE;
        }
        #imgLoad
        {
        	position:fixed;
            bottom:0;	
            left:40%;
            display:none;
        }
        .box
        {
            margin: 5px;
            padding: 10px;
            background-color:#FFFFFF;
            box-shadow: 0 1px 3px rgba(34, 25, 25, 0.4);
        }
    </style>
    <script src="Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.masonry.min.js" type="text/javascript"></script>
</head>

4. To display products, we use Repeater control:


 <div id="container" class="transitions-enabled infinite-scroll clearfix">
        <asp:Repeater ID="Repeater1" runat="server">
            <ItemTemplate>
                <div class="box">
                    <img src="<%# Eval("Url") %>" />
                    <p><%# Eval("Description") %></p>
                </div>
            </ItemTemplate>
        </asp:Repeater>
    </div>
    <div id="imgLoad">
        <img src="http://i.imgur.com/6RMhx.gif" />
    </div>

Dynamic Grid Layout:

5. To bind repeater on Page_Load:


        Repeater1.DataSource = ProductRepository.GetData(1, 25); 
        Repeater1.DataBind(); 

Now, the product is displayed in normal order. If there is variance in each tile height then there is unnecessary blank space between rows. For dynamic grid layout, the following javascript code is used:


			var $container = $('#container');

            $container.imagesLoaded(function () {
                $container.masonry({
                    itemSelector: '.box',
                    columnWidth: 100,
                    isAnimated: true
                });
            });

You can see the products are reordered to minimize vertical spacing.

Infinite Scrolling:

6. To implement infinite scrolling, lets create a webmethod on aspx side:


 [WebMethod]
    public static IEnumerable<Product> GetData(int pageNo, int pageSize)
    {
       
        return ProductRepository.GetData(pageNo, pageSize); 
    }

We call this method using jQuery ajax on scrolling, add products dynamically and reorder products


 var pageNo = 1,pageSize = 25;
  $(window).scroll(function () {
                if ($(window).scrollTop() == $(document).height() - $(window).height() && !($('#imgLoad').is(':visible'))) {
                    loadMore();
                }
            });

            function loadMore() {
                $('#imgLoad').show();
                $.ajax({
                    type: "POST",
                    url: "Default.aspx/GetData",
                    data: JSON.stringify({ pageNo: pageNo + 1, pageSize: pageSize }),
                    dataType: "json",
                    contentType: "application/json",
                    complete: function (response) {                       
                        $('#imgLoad').hide();
                    },
                    success: function (response) {
                        if (response.d.length > 0) {
                            var ctrls = [];
                            for (var i = 0; i < response.d.length; i++) {
                                ctrls.push('<div class="box"> <img src="' + response.d[i].Url + '" /><p>' + response.d[i].Description + '</p></div>');
                            }
                            var $newElems = $(ctrls.join(''));
                            $container.append($newElems);
                            $newElems.css({ opacity: 0 });
                            $newElems.imagesLoaded(function () {
                                // show elems now they're ready
                                $newElems.css({ opacity: 1 });
                                $container.masonry('appended', $newElems, true);
                            }); 
                            pageNo++;
                        }
                    }
                });
 

Output:

Hope, you enjoy it.