Joshua Waheed Joshua Waheed - 5 months ago 7
Javascript Question

How do I position modules to display like Pinterest?

I'm building a Pinterest type board plugin with jQuery, where I'm having difficulty figuring out how they position their modules.

Below is a snippet of how each element is being placed per their nth-value in the HTML. But this isn't right because Pinterest positions elements that go to the next row underneath the shortest column. Quite like this pen here, http://codepen.io/nikhilkumar80/pen/oxpXVK, but I found it difficult to understand.

function modPosition() {
$this.find(".pinterest-board__mod").each(function( modIndex ) {
$(this).css({
position: "absolute",
left: columnWidth * (modIndex % settings.columns) + "%",
width: columnWidth + "%"
});
// ..........
});
}
modPosition();


Here's my CodePen link, http://codepen.io/joshuawaheed/pen/beeJKq?editors=0010

I'm also having difficulties figuring out how to set the elements top position.

What can I do to make this work? I've put this in a function so that the positioning can run it again on document resize and when a user clicks on a filter option to remove the elements and append the appropriate modules from the appropriate array. The plugin is also set to determine module widths based on the options columns value.

Thank you in advance.

Answer

I've got it working. I solved this by:

  • Creating an array, its lengt equal to the column count.
  • Storing the height value of modules in the first row in the array.
  • Looping through each module.
    • Injecting the smallest array value as css position top for the current module.
    • Adding the height of the current module with the array item containing the smallest value.
    • Setting the position left value by dividing 100% with the index of of the smallest value in the array.

Here is the code I wrote, which you can view and fork by following this link

function modPosition() {

    var columnsHeight = [/* Length equal to column count */], // This will be recreated on window resize.
        columnCount = /* Column count value */;


    /* Set CSS position top and left. */
    function modCssTopLeft() {

        var columnIndex = 0;

        $this.find(".pinterest-board__mod").each(function( modIndex ) {

            var topPos = 0,
                leftPos = 0;

            if ( modIndex >= columnCount) {
                topPos = Math.min.apply( Math, columnsHeight ); // Get smallest value in array.
                leftPos = 100 * columnsHeight.indexOf(topPos) / columnCount; // Set left position based on column count.
                columnsHeight[columnsHeight.indexOf(topPos)] += $(this).outerHeight(); // Change arrays smallest value by adding it with current modules height.
            }
            else {
                leftPos = 100 * (modIndex++) / columnCount; // Positioning for the modules in the first row.
            }

            $(this).css({
                position: "absolute",
                top: topPos + "px",
                left: leftPos + "%"
            });

            $(this).closest(".pinterest-board__content").css({
                height: Math.max.apply( Math, columnsHeight ) // Set height to the modules parent container.
            });

        });
    }
    modCssTopLeft();
}
modPosition();

$(window).resize(function() {
    modPosition();
});