Thank you! Your feedback has been delivered
Thank you! Your feedback has been sent

Isotope liquid layout - Fix mobile crash and simplify code

Hi coders!

I have this project: www.mercatocentrale.it - I have used isotope to generate a liquid masonry with different width and height dimensions for each box.

I have sorted each box with a "sort order" value that i parse with isotope class.

When you click on specific boxes i append a new div to isotope and I want to positionate it in the next row of the grid. Actually the effect works but on mobile the page crashes.

I would like to have my huge script simplified and also to fix the crash on mobile devices.

Just other few info: i am on Wordpress, i generate dynamically all the boxes + i need a working page, please don''t send me Javascript''s frameworks or other stuff, just the working code with the actual contents so i can just edit my file and go go go + all my jQuery code is in the footer of the page.

Thank you so much.

User Gravatar

LenusMedia

Posted May 21 2014 0:03 UTC

$200


  • Assigned To yifeikong
  • Solved
  • jquery
    isotope
    isotope-on-append
  • 1575 Views

22 Replies


Hey,

I've checked out the crashing issue, it doesn't crash neither in emulation nor real device (Nexus 5), it just appends the div to the bottom one.

Do you have steps to reproduce?

Regarding optimization, did you try to minify and uglify the code?

User Gravatar

gmaliar

Posted May 22 2014 7:45 UTC

Hi I've got almost fixed, how would you like your code delivered back to you?

User Gravatar

yifeikong

Posted May 22 2014 7:51 UTC

Hi all,

1) no minify, but there are many part that we can simplify (use functions for example)

2) Send all to emanuele.pisapia@lenus.it or paste here? It should be smaller than now, i think :)

User Gravatar

LenusMedia

Posted May 22 2014 8:32 UTC

Isotope is a generally cool concept but it is buggy and Dave Desandro is not very interested in fixing those bugs. It is naturally responsive so it would fit your mobile app however the biggest problem is the amount of DOM leaking Isotope makes which cause browsers to crash. This link is to that very issue with isotope on Desandro's github repo for isotope https://github.com/metafizzy/isotope/issues/295

My recommendation is either use khiltd's solution or find an alternative to isotope. There are plenty!

Hope that helps!

Cheers!

User Gravatar

michaelmuxica

Posted May 22 2014 9:04 UTC

Thank you for your reply michaeln... (@Codersclan fix this css problem, i can't see the whole username!)

I will check for the solution proposed but i think that at this time i can't use a different solution. @yfei when will you send a simple and less redundant code maybe you could take a look for me at that issue?

PS Desandro told me about this forum :)

User Gravatar

LenusMedia

Posted May 22 2014 9:59 UTC

michaelmuxica is my username!

I figured as much, Lenus. But wouldn't have felt right otherwise. I have played with isotope so much for the desire of using it and learned of all the small issues preventing it from becoming THE GRID of the internet.

Anyways, I wish you all the luck in taming it to your needs :D

User Gravatar

michaelmuxica

Posted May 22 2014 10:14 UTC

Sorry, I'm late. My laptop just stop working last night, I finally got my data out this afternoon, so I was unable to post the modified files here before the deadline.

3 problems solved:

  • The script works much faster than your old one
  • the javascript you mentioned is now well structured and less complicated
  • it works on mobile devices

To use it, just repalce you script at the end of homepage with code below

There are still a lot we can improve about your homepage, like asnyc loading, responsiveness, but that will need more info and time.

jQuery(function($){
// this won't conflict with other js loiarbries using $. no need to call jQuery.noConflict()

// Globals in this file
var $container = $('#main');
var items_per_row; // so basically, 2 means on mobile devices and 7 means on desktop or tablets
var item_width;
var iso_options;
var $current_bollino;
var $bollini = $('.has_content');

function on_window_resize () {
    items_per_row = ($container.width() < 641) ? 2 : 7; // why 641? it's a magic number, try to define it.
    item_width = Math.round($container.width() / items_per_row)
    resize_items (item_width, items_per_row);
    iso_options = gen_iso_options();
    $container.isotope(iso_options);
    console.log(iso_options);
}
function resize_items (item_width, items_per_row){

    var item_height = item_width;

    $('.item').width(item_width);
    $('.item').height(item_height);
    $('.item-horizontal').width(2*item_width);
    $('.item-horizontal').height(item_height);
    $('.item-vertical').width(item_width);
    $('.item-vertical').height(2*item_height);
    $('.item-square').width(2*item_width);
    $('.item-square').height(2*item_height);

    $('.hoverChange').width(2*item_height); // strongly recommend you change the camelCase to css-var-case
    $('.hoverChange').height(2*item_height);   
    $('.hoverChangeBack').width(2*item_height);
    $('.hoverChangeBack').height(2*item_height);

    $('.boxscroll').css('width', 3*item_width + 'px');
    $('.hoverBox').css('height', '100%');

    $('.ballon').width(items_per_row*item_width);
    $('.ballon').css('min-height', 2*item_height);     
    $('.ballon').css('height', 'auto');
}

function replaceAll (str, oldToken, newToken, ignoreCase) {

    if (ignoreCase) {
        return ;// not used in your program
    } else {
        return str.split(oldToken).join(newToken);
    }


}

function gen_iso_options () {

    // get late binding of item_width
    return {
        getSortData : {
          sorting : function ( elem ) {
            return parseInt($(elem).find('.sorting').text(), 10);
          },
          resorting : function ( elem ) {
            return parseInt($(elem).find('.resorting').text(), 10);
          }
        },
        animationOptions: { queue: true, duration: 10000 },
                    sortBy: 'sorting',
                    layoutMode: 'masonry',
        transformsEnabled: false,
        animationEngine: 'best-available',
        masonry: {      
            columnWidth: item_width
        },
        itemSelector: '.elemento',
        itemPositionDataEnabled: true
    };
}

function toggle_bollino ($elemento) {

    if ($current_bollino && ($current_bollino.clicker.is($elemento))){
        hide_bollino();
    } else {
        open_bollino($elemento);
    }
}


function open_bollino ($elemento) {

    if ($current_bollino) {
        hide_bollino();
    }

    var sorting = $elemento.children('p.sorting').text();
    var target_sorting = $elemento.children('p.target_sorting').text();
    if (items_per_row < 7) {
        target_sorting = parseInt(sorting) + 0.5;
    }
    var htmlcontents = $elemento.children('.htmlcontents').html().replace(/(rn|n|t|r)/gm, "");

    if (htmlcontents !== '' && $elemento.hasClass('contenutohtml')) {

        if ($elemento.hasClass('rosa')) {
            var color = 'rose';
        } else if ($elemento.hasClass('verde')) {
            var color = 'verde';
        } else if ($elemento.hasClass('rosso')) {
            var color = 'rosso';
        } else if ($elemento.hasClass('giallo')) {
            var color = 'giallo';
        } else if ($elemento.hasClass('blu')) {
            var color = 'blu';
        } else if ($elemento.hasClass('panna')) {
            var color = 'panna';
        } else if ($elemento.hasClass('aqua')) {
            var color = 'aqua';
        } else if ($elemento.hasClass('pizza')) {
            var color = 'pizza';
        } else if ($elemento.hasClass('paglia')) {
            var color = 'paglia';
        }

        var bollino = {}
        bollino.str = replaceAll('<div class="elemento ballon artigiani has_content_to_display losapevi"><div class="toparrow" "> </div>'+htmlcontents+'<p class="sorting">'+target_sorting+'</p></div>', "[incremento]", "appendend_");
        var $bollino = $(bollino.str);
        $bollino.clicker = $elemento;
        $current_bollino = $bollino;
        $bollino.id = 'appended_to_' + $elemento.id;
        // $bollino.height(item_width);
        $bollino.addClass(color);
        $bollino.addClass('bollino');

        $('.bollino').remove();
        $bollino.appendTo($container)
        $container.isotope('insert', $bollino)

        // nice scroll for lightboxes
        var $boxscroll_active = $('.bollino .boxscroll-active')
        $boxscroll_active.niceScroll({
            cursorcolor:"#000000",
            cursoropacitymin: 1,
            cursoropacitymax: 1,
            cursorwidth: 8,
            cursorborder: '0'
        });
        $boxscroll_active.getNiceScroll().resize();
        $(".bollino").mouseover(function(){
            $boxscroll_active.getNiceScroll().resize();
        })

        $('html, body').animate({
            scrollTop: $bollino.offset().top - item_width - 100
        }, 1000);

    }

};

function hide_bollino () {
    $('.bollino .boxscroll-active').getNiceScroll().hide();
    $container.isotope('remove', $current_bollino).isotope('layout');
    $current_bollino.remove();
    $current_bollino = null;
}

function next_bollino () {
    var next;
    $bollini.each(function (index, bollino) {
        // console.log($(bollino));
        // console.log($current_bollino)
        if ($(bollino).is($current_bollino.clicker)) {
            next = index+1;
            open_bollino($('#'+$bollini[next].id));
            return false;
        }
    });

}

function prev_bollino () {
    var prev;
    $bollini.each(function (index, bollino) {
        // console.log($(bollino));
        // console.log($current_bollino)
        if ($(bollino).is($current_bollino.clicker)) {
            prev = index-1;
            open_bollino($('#'+$bollini[prev].id));
            return false;
        }
    });
}

function open_popup(uri, scrollable){
    var src = uri;
    if (scrollable == 1){
        addcss = 'scrolling="no" style="padding: 5px; border:0; overflow: hidden;"';
    } else {
        addcss = 'scrolling="no" style="padding: 5px; border:0; overflow: hidden;"';
    }
    $.modal('<iframe src="' + src + '"  frameborder="0" width="850" height="450" '+ addcss +'>', {
        closeHTML:"",
        containerCss:{
            backgroundColor:"#fff",
            width:860,
            height:470, 
            padding:0, 
        },
        overlayClose:true
    });
}

window.hide_bollino = hide_bollino;
window.next_bollino = next_bollino;
window.prev_bollino = prev_bollino;
window.open_popup = open_popup;


// run immediately after page loaded

$('#loading').fadeOut(); // I don't see this line working
$('body').css('overflow', 'auto'); // You should write this line into CSS files
on_window_resize(); // init the window

// flippers
$(".flip-container").click(function(){
    $(this).toggleClass('hover');
});

// won't crash on phones
$(".elemento").click(function(){
    toggle_bollino($(this));
});

// recalculate all if window resized
$(window).resize(on_window_resize);
});
User Gravatar

yifeikong

Posted May 23 2014 6:21 UTC

Hi there yifeikong, we have made a little implementation to the code in another task...could you check for the little updates on open_bollino(), close_bollino(), next_bollino(), prev_bollino()?


Actually we have few troubles to fix:

www.mercatocentrale.it (it's live). But it seems to be broken on my Firefox at the first load: www.mercatocentrale.it/first_load.gif and I have to resize to have the right effect.

Or sometimes under "stress" the niceScroll effect ...doesn't work properly www.mercatocentrale.it/bar.gif

If I try to load just one kind of boxes like here: http://www.mercatocentrale.it/gli-artigiani-gusto/ it seems to not work properly...


User Gravatar

LenusMedia

Posted May 23 2014 6:41 UTC

@Lenus I've checked your updated version. It seems better but broken on my firefox, too. And it's still not working on mobile phones.

My version works on desktop and do not crash on phones (This is the problems you stated in this ticket).

If you wish to use fix your problems in your last reply. Here are 2 things you can do:

  • call the resize function in jQuery.ready(), which makes you don't have to mannully resize the window to make it right in firefox.
  • add $('.bollino .boxscroll-active').getNiceScroll().hide(); in your hide_bollino function, which hide the scrollbar generated by niceScroll.

But this is still a quick and dirty fix, you should tweak the dynamically generated boxes and use javascript generate the boxes dynamically rather than store the data in html to get better results. Hope it helps :).

User Gravatar

yifeikong

Posted May 24 2014 0:19 UTC

Hi there! I prefer to use you incredible compact script of your previous comment.

Could you (take your time, it's saturday!) Take the new functions (they allow me to open bollinos in the next avaible row (it seems to work) and do the wonderful clean up to have it fast, readable and awsome (without crashes and mobile-ready?)

Lenus

User Gravatar

LenusMedia

Posted May 24 2014 1:05 UTC

Hi yifeikong,

could you update your smart script with the updated version live on www.mercatocentrale.it?

Thank you for your support.

User Gravatar

LenusMedia

Posted May 25 2014 23:32 UTC

Hi, LenusMedia

I didn't notice your last 2 replies until now, I'll post it here as soon as I finish it.

User Gravatar

yifeikong

Posted May 26 2014 3:16 UTC

thank you very much.

User Gravatar

LenusMedia

Posted May 26 2014 3:25 UTC

Excuse me, but did you mean the script live on your website or uploaded by another user in your previous ticket? they are not the same one.

Regards

User Gravatar

yifeikong

Posted May 26 2014 5:06 UTC

Sorry, I mean the new one that you can find here:

http://dev.lenuslab.com/mcf

Emanuele

User Gravatar

LenusMedia

Posted May 27 2014 9:01 UTC

Hi, LenusMedia

It's done and working on mobile, scroll-bar issue also fixed.

jQuery.noConflict();

var $main = jQuery('#main');

String.prototype.replaceAll = function(token, newToken, ignoreCase) {
    var _token;
    var str = this + "";
    var i = -1;

    if (typeof token === "string") {

        if ( ignoreCase ) {

            _token = token.toLowerCase();

            while((i = str.toLowerCase().indexOf(token, i >= 0 ? i + newToken.length : 0)) !== -1) {
                str = str.substring( 0, i ) + newToken + str.substring( i + token.length );
            }

        } else {
            return this.split(token).join(newToken);
        }

    }
    return str;
};

function scroll_and_select (id){
    jQuery('body, html').scrollTo( jQuery('#' + id) , 800);
    jQuery('ul.sort-by li').removeClass('selected');
    jQuery('ul.sort-by li#link_' + id).addClass('selected');  
}

function recall () {
    var main_width      =   $main.width();
    var main_offset     =   $main.offset();

    if (main_offset.top == 0){
        $main.css('marginTop', jQuery('#top').height() + 'px');
    }
    var num         =   7;
    if (main_width < 641){
        num             =   2;
    }
    var item_width      =   Math.round(main_width / num);

    // *
    // * correggiamo la larghezza della barra a sx
    // *
    var full_width      =   item_width * num;
    var diff            =   full_width - main_width;
    if (diff > 0){
        item_width      =   item_width - 1;
    }
    calculate_dimensions(item_width, num);

    var isoOptions  =   {
        getSortData : {
          sorting : function ( elem ) {
            return parseInt(jQuery(elem).find('.sorting').text(), 10);
          },
          resorting : function ( elem ) {
            return parseInt(jQuery(elem).find('.resorting').text(), 10);
          }
        },
        animationOptions: { queue: true, duration: 10000 },
                    sortBy: 'sorting',
                    layoutMode: 'masonry',
        transformsEnabled: false,
        animationEngine: 'best-available',
        masonry: {      
            columnWidth: item_width
        },
        itemSelector: '.elemento',
        itemPositionDataEnabled: true
    };



    $main.isotope( isoOptions );      
}

function open_bollino (id) {
    var $ = jQuery;
    var $bollino = $('#bollino');
    if ($bollino) {
        var activeItem = $bollino.data('item-id');

        hide_bollino();

        if (activeItem == id) return;
    }

    var elem = $('#'+id);

    if (!elem.hasClass('contenutohtml')) return;

    var main_width = $main.width();
    var num = (main_width < 641) ? 2 : 7;
    var item_width = Math.floor(main_width / num);

    calculate_dimensions(item_width, num);

    var htmlcontents = elem.children('.htmlcontents').html().replace(/(rn|n|t|r)/gm, "");

    if (htmlcontents != '') {
        var valid_colore = [  'rosa', 'verde', 'rosso', 'giallo', 'blu', 'panna', 'aqua', 'pizza', 'paglia' ];
        var colore = '';
        for (c in valid_colore) {
            if (elem.hasClass(c)) { 
                colore = c;
            }
        }

        var sorting = 9999;
        var isoElems = $main.isotope('getItemElements');
        var hunt = false;
        for (var i=0;i <isoElems.length;i++) {
            if (id == isoElems[i].id) {
                hunt = true;
                continue;
            }

            if (hunt == true && isoElems[i].offsetLeft == 0) {

                if (isoElems[i+1].offsetLeft == 0) {
                    i++;
                }
                sorting = $('#' + isoElems[i].id).children('.sorting').text() - 0.5;
                break;
            }
        }

        // fix mobile issue
        if (num < 7) {
            sorting = parseInt(elem.children('p.sorting').text()) + 0.5;
        }

        var marginesx       =   elem.offset().left + (elem.width() / 2) - 7 - $('#mainmenu').width();
        var newItem         =   $('<div id="bollino" data-item-id="'+ id + '" class="elemento ballon artigiani has_content_to_display losapevi"><div class="toparrow '+colore+'" style="margin-left: '+marginesx+'px">&nbsp;</div>'+htmlcontents+'<p class="sorting">'+sorting+'</p></div>');

        // calcoliamo la posizione della pagina.
        var body_pos    =   $('#top').offset();

        // generiamo il nuovo
        $main.append( newItem ).isotope('insert', newItem).isotope({ sortBy: 'sorting' });

        elem.children('.hoverBox').addClass('hovered');
        if (num < 7){

        } else { //$("#appended_to_"+id+" .boxscroll-active").niceScroll({
            $("#bollino .boxscroll-active").niceScroll({
                cursorcolor:"#000000",
                cursoropacitymin: 1,
                cursoropacitymax: 1,
                cursorwidth: 8,
                cursorborder: '0'
            });
            $("#bollino .boxscroll-active").getNiceScroll().resize();
            $("#bollino").mouseover(function(){
                $("#bollino .boxscroll-active").getNiceScroll().resize();
            })

            // definiamo lo scorrimento 
            setTimeout(function() {
                dest    =   $('#bollino').offset().top;
                $('body, html').scrollTo(dest, 300);
            }, 500);
        }       
    }
}

// fixed
function hide_bollino () {
    var $bollino = jQuery('#bollino');
    if ($bollino) {
        var activeItem = $bollino.data('item-id');
        jQuery('.bollino .boxscroll-active').getNiceScroll().hide();
        jQuery('.nicescroll-rails').remove(); // bug in nice scroll
        jQuery('#'+activeItem + ' .hoverBox').removeClass('hovered');
        $main.isotope('remove', $bollino).isotope('layout');
        $bollino.remove();
        $bollino = null;
    }
}

// fixed
function next_bollino () {
    var $bollino = jQuery('#bollino');
    if ($bollino){
        var activeItem = $bollino.data('item-id');

        var $bollini = jQuery('.has_content');
        for (i=0; i < $bollini.length; i++){
            if ($bollini[i].id == activeItem){
                var $nextBollino = $bollini[i+1];
            }
        }
    }
    if ($nextBollino){
        open_bollino($nextBollino.id);
    }
}

// fixed
function prev_bollino () {
    var $bollino = jQuery('#bollino');
    if ($bollino){
        var activeItem = $bollino.data('item-id');

        var $bollini = jQuery('.has_content');
        for (i=0; i < $bollini.length; i++){
            if ($bollini[i].id == activeItem){
                var $prevBollino = $bollini[i-1];
            }
        }
    }
    if ($prevBollino){
        open_bollino($prevBollino.id);
    }
}  

function filter (className) {
    $main.isotope({ filter: '.' + className });
} 

function destroy_isotope (){
    $main.isotope( isoOptions );
}

function rebuild_isotope( isoOptions ){
    $main.isotope( isoOptions );
}

function calculate_dimensions(item_width, num){
    var item_height     =   (item_width);
    jQuery('.item').width(item_width).height(item_height);
    jQuery('.item-horizontal').width(2*item_width).height(item_height);
    jQuery('.item-vertical').width(item_width).height(2*item_height);
    jQuery('.item-square').width(2*item_width).height(2*item_height);

    jQuery('.hoverChange').width(2*item_height).height(2*item_height);   
    jQuery('.hoverChangeBack').width(2*item_height).height(2*item_height);

    jQuery('.boxscroll').css('width', 3*item_width + 'px');
    jQuery('.hoverBox').css('height', '100%');

    jQuery('.ballon').width(num*item_width).css('min-height', 2*item_height).css('height', 'auto');
}

function open_popup(uri, scrollable){
    var src = uri;
    if (scrollable == 1){
        addcss = 'scrolling="no" style="padding: 5px; border:0; overflow: hidden;"';
    } else {
        addcss = 'scrolling="no" style="padding: 5px; border:0; overflow: hidden;"';
    }
    jQuery.modal('<iframe src="' + src + '"  frameborder="0" width="850" height="450" '+ addcss +'>', {
        closeHTML:"",
        containerCss:{
            backgroundColor:"#fff",
            width:860,
            height:470, 
            padding:0, 
        },
        overlayClose:true
    });
}

function fade_home_top(){
    if (jQuery(window).width() > 800) {
        window_scroll = jQuery(this).scrollTop();
        jQuery(".fadeafterscrolling").css({
            'opacity' : 1-(window_scroll/300)
        });
    }
}


jQuery(function ($) { // all function wrapped in jQuery so it wont confilct with other libs

    // when page loaded
    recall();
    $('#loading').fadeOut();
    $('body').css('overflow', 'auto');

    // register listeners
    $(".elemento").click(function(){
        open_bollino(this.id);
    }); 

    $(".flip-container").click( function( event ){
        $(this).toggleClass('hover');
    });

    $(window).scroll(fade_home_top).resize(function(){
        $('#main').isotope();
        recall();
    });

    $('.parallax').parallax({
        speed : 0.10
    });

});
User Gravatar

yifeikong

Posted May 29 2014 2:07 UTC

Hi yifeikong,

http://www.mercatocentrale.it/homepage-alternativa/

-

1) first load (see this attach: http://www.mercatocentrale.it/home.gif)

2) Click on box and css trouble: http://www.mercatocentrale.it/css.gif

Could you have a look?

Emanuele

User Gravatar

LenusMedia

Posted May 29 2014 4:07 UTC

Yeah, I see it's broken on your site. But it's fine on my local computer. based on http://dev.lenuslab.com/mcf, I created http://yifeikong.pancakeapps.com/italy/index.html you could check it out here.

There might be some mis-configurations.

yifeikong

User Gravatar

yifeikong

Posted May 29 2014 5:57 UTC

Solution

This didn't solve your task? Get your own custom solution.

Ambigue... could you have a look? I won the prizem obviousely :)

User Gravatar

LenusMedia

Posted May 29 2014 6:31 UTC

Hi, LenusMedia

Here is the file I used. The html file is downloaded from http://dev.lenuslab.com/mcf , the only change I've made is deleting the old script at the bottom of the page and adding my own script, which is the fixed2.js file. I'm looking into your file meanwhile.

http://yifeikong.pancakeapps.com/italy/italy.zip

User Gravatar

yifeikong

Posted May 29 2014 6:40 UTC

Thank you yfeikong. If you find something i will always glad for your great support.

User Gravatar

LenusMedia

Posted May 29 2014 9:32 UTC

Hi yifeikong, let me know if u will find a solution, thanks!

User Gravatar

LenusMedia

Posted May 31 2014 6:26 UTC

Add a reply

By posting a reply on CodersClan you agree to our Terms & Conditions