Search code examples
jquerycsspositioningjquery-masonry

The simplest script like masonry block


I prepare code like masonry.

Rules are simple: - 4 columns always - each element has the same width

My script for positioning elements looks like below (onload):

var line = 0;
var row = 0;
var heights = [];

// Count elements on one line
$('img').each(function() {
    if ($(this).prev().length > 0) {
        if ($(this).position().top != $(this).prev().position().top) {
            return false;
        }

        line++;
    } else {
        line++;
    }
});

for (i = 0; i < $('img').length; i++) {
    if (i % line == 0 && i > 0) {
        row++;
    }

    // Set position in first row
    $('img:eq(' + i + ')').css({
        'position': 'absolute',
        'top': '0px',
        'left': $('img:first').outerWidth(true) * i
    });

    // Set position for next rows
    if (row > 0) {
        $('img:eq(' + i + ')').css({
            'top': parseFloat($('img:eq(' + (i - line) + ')').offset().top + $('img:eq(' + (i - line) + ')').outerHeight(true) - $('img:first').offset().top),
            'left': parseFloat($('img:eq(' + (i - line) + ')').css('left'))
        });
    }
}

And function to remove element on click

$('img').on('click', function() {
    $('img').css({
        'transition': 'all 3s'
    });

    $(this).remove();

    $(window).trigger('load');    
});

I would like to ask two questions:

  1. How to set height of div wrapper?
  2. Why when I remove an element (by click) do elements become not correctly positioned? I run method again by trigger.

All code on jsfiddle: http://jsfiddle.net/n8v3X/3/


Solution

  • (1) div wont get height, because its children are position absolute elements, height can be set via javascript.

    >> Calculate total img height in each column

    >> Find which column of images have greater height and set to wrap div

    /* Logic to Calculate Height */
    var wrap_height = 0;
    var column_array = [0, 0, 0, 0];
    for (i = 0; i <= row; i++) {
        var temp_height = 0;
        for (j = 0; j < line; j++) {
            //curr element in a row :  j+ ( i * line );
            var curr_height = $('img:eq(' + (j + (i * line)) + ')').outerHeight(true);
    
            column_array[j % line] += curr_height;
    
        }
    }
    for (i = 0; i < column_array.length; i++) {
        if (column_array[i] > wrap_height) {
            wrap_height = column_array[i];
        }
    }
    
    $('#wrap').css({
        height: wrap_height + 'px'
    });
    

    (b) Not properly positioned because,

    the new position of prev element cant be calculated properly in loop.

    $('img:eq(' + (i - line) + ')') >> top & left value get from below code, was before it get set to new position.

    if (row > 0) {
                $('img:eq(' + i + ')').css({
                    'top': parseFloat($('img:eq(' + (i - line) + ')').offset().top + $('img:eq(' + (i - line) + ')').outerHeight(true) - $('img:first').offset().top),
                    'left': parseFloat($('img:eq(' + (i - line) + ')').css('left'))
                });
            }
        }
    

    i used data attribute of html5 to fix this issue.

    Fiddle: http://jsfiddle.net/aslancods/n8v3X/152/