How do I make this carousel implementation better?


Tags: javascript,jquery,html,css,carousel

Problem :

You can view the implementation here.

So what this does is automatically detect the window size and resizes the images to be displayed on the fly - the idea being that in all screen resolutions the proportions are the same.

Here are some problems I have found with it, that I would love solutions to make it more elegant and 'smooth':

  • It looks good and functions fine in larger resolutions (say 1280+), but once you try to load it in 1024 or lower, it starts to look and function weird.
  • While scrolling, it doesn't scroll too smoothly.
  • Some of the alignment stuff is off (i.e. when you switch to the '3-up' or '4-up' view, the white border on the right-most image disappears in 1680 resolution).
  • When you go to 4-up and scroll to the far right, it ends weirdly with no images showing.
  • There is repetitive JS, that I know is not DRY and would love a more elegant way to achieve what the current version does for multiple 'views'.
  • Once it loads initially, it takes about 3 seconds to load, and in that time you can actually see the smaller versions, then you see when the resized images are put on the page. That seems a bit 'untidy' to me, so I would love for that to be cleaner.
  • Plus any tips on how I can 'tighten' it up and make it function better generally.

You can either view source on that feedback page, but there is extraneous code there, so here are the relevant parts:

HTML:

<div id="compare_view" align="center">

    <div id="viewbar" class="compv-navbar">
        <a href=""><img src="images/2-up-icon-grey.png" alt="2-up-view" data-id="2"></a> | 
        <a href=""><img src="images/3-up-icon-grey.png" alt="3-up-view" data-id="3"></a> | 
        <a href=""><img src="images/4-up-icon-grey.png" alt="4-up-view" data-id="4"></a> | 
        <span id="viewname" class="view_name">2-up</span>
    </div>  

<div id="slider-code" align="center">
    <a class="buttons prev" href="#"></a>
    <div class="viewport">
        <ul class="overview">           
            <li><img src="images/red-stripe.jpg" /></li>
            <li><img src="images/red-stripe-bw.jpg" /></li>
            <li><img src="images/red-stripe-red.jpg" /></li>            
            <li><img src="images/red-stripe-dark.jpg" /></li>
            <li><img src="images/red-stripe.jpg" /></li>
            <li><img src="images/red-stripe-red.jpg" /></li>
            <li><img src="images/red-stripe-dark.jpg" /></li>           
        </ul>
    </div>
    <a class="buttons next" href="#"></a>
    </div>

    <div id="notice">
        Flip through the images using the <strong> buttons </strong> and your mouse.
    </div>

</div>

Here is the relevant CSS:

#slider-code { 
    height: 125px; 
    overflow:hidden;
    margin: 0 0 0 0;
}

#slider-code .viewport { 
/*  margin-left: auto;    -- With this enabled, the arrows don't work.
    margin-right: auto;  */
    float: left; 
    width: 240px; 
    height: 125px; 
    overflow: hidden; 
    position: relative;

}

#slider-code .viewport .overview img {
    border: 4px solid #f6f6f7;
    -moz-border-radius: 4px;
    -khtml-border-radius: 4px;
    -webkit-border-radius: 4px; 
}

#slider-code .buttons { 
    display: block; 
    margin: 0 0 0 0; /* 10px 10px 0 0;  */
    float: left;
    vertical-align: middle;
}

#slider-code .prev {
    width: 32px;
    height: 32px;
    background: transparent url('../images/left-arrow.png') no-repeat 0 0;
    vertical-align: middle;
    margin: 0 0 0 0; /* top, right, bottom, left */ 
    position: relative;
/*  top: 190.5px;   */
}

#slider-code .next { 
    width: 32px;
    height: 32px;
    background: transparent url('../images/right-arrow.png') no-repeat 0 0;
    margin: 0 0 0 0px;  /* 30px 0 0 10px; */
    vertical-align: middle;
    position: relative;
}

#slider-code .disable { 
     /* for IE */
    filter:alpha(opacity=40);
    /* for everything else */  
    opacity:0.4;
}

#slider-code .overview { 
    list-style: none; 
    position: absolute; 
    padding: 0; 
    margin: 0; 
    left: 0; 
    top: 0; 
}

#slider-code .overview li { 
    float: left; 
    margin: 0 20px 0 0; 
    padding: 1px; 
    height: 121px; 
    border: 1px solid #dcdcdc;
    width: 236px;
}

.view_name {
    font-family: "Helvetica", serif;
    color: #f9f4c0;
    font-style: normal;
    font-weight: bold;
    font-size: 11px;
    word-spacing: 0px;
    letter-spacing: 0px;
    background: #1a1a1a;    
    padding: 1px 3px 1px 3px; /* top, right, bottom, left */        
    -moz-border-radius: 5px;
    -khtml-border-radius: 5px;
    -webkit-border-radius: 5px; 
}

#compare_view .compv-navbar img {
    margin: 3px 3px -4px 3px;   
}

#compare_view .compv-navbar img a.hover {   
    margin: 3px 3px -4px 3px;   
}

Here is the JS:

$(window).load(function() {
// --------------------------- Begin Comparison Code --------------------------------------------------------       
        var win_width = $(window).width();
        var num_of_images = 2; //The number of images expected in view (2 for 2-up, 3 for 3-up, etc.) The default value is 2.

        $("#viewbar img").click(function(e) {                       
            num_of_images = parseInt($(this).attr("data-id"), 10); // This accepts the integer associated with the navbar.          
            $('#viewname').text(num_of_images + '-up');         
            //--- All of this function is a duplicate of the 'default' case which is below. This is not very DRY-like, but it works for now.

            var oImg_height = $('#slider-code .viewport .overview img:eq(1)').height(); //size of original image height
            var oImg_width =  $('#slider-code .viewport .overview img:eq(1)').width(); //size of original image width
            var oImg_ratio = oImg_height / oImg_width; //aspect ratio of original image
            var tImg_width = (win_width * 0.915) / num_of_images; // Target image width = (90% of the window) / 2
            var tImg_height = tImg_width * oImg_ratio; // Target image height, resized according to the original image ratio.
            var sliderCode_w = $('#slider-code').width();
            var sliderCode_h = $('#slider-code').height();
            var ul_width = $('#slider-code .viewport ul').width();

            $('#slider-code .viewport .overview img:lt(26)').css({'width' : tImg_width, 'height' : tImg_height});   //resizes the images

            var rImg_width = $('#slider-code .viewport .overview img:eq(1)').width(); // size of resized image width 
            var rImg_height = $('#slider-code .viewport .overview img:eq(1)').height(); // size of resized image width

            $('#slider-code .next').css({'top' : rImg_height / 2}); //This needs to be resolved for various size windows
            $('#slider-code .prev').css({'top' : rImg_height / 2});     
            $('#slider-code').css({'width': '100%', 'height': rImg_height + 10}); //to accomodate borders, extra padding was added to heights. To make it truly dynamic, a variable (as a percentage) of the width of the window, could be used to be added to the height
            $('#slider-code .viewport').css({'width': win_width * 0.94, 'height': rImg_height + 10});
            $('#slider-code .overview li').css({'width': rImg_width + 5});
            var view_new_w = $('#slider-code .viewport').width();
            var view_new_h = $('#slider-code .viewport').height();
            var li_w = $('#slider-code .overview li').width();
            var rUl_width = $('#slider-code .viewport ul').width();

            $('#slider-code').tinycarousel({ controls: true, animation: true, display: 1 });        

            e.preventDefault();
        }); 

        //This is the default case that executes before a click is done. Because the code has been repeated above, it isn't very DRY-like.

        var oImg_height = $('#slider-code .viewport .overview img:eq(1)').height(); //size of original image height
        var oImg_width =  $('#slider-code .viewport .overview img:eq(1)').width(); //size of original image width
        var oImg_ratio = oImg_height / oImg_width; //aspect ratio of original image
        var tImg_width = (win_width * 0.915) / num_of_images; // Target image width = (90% of the window) / 2
        var tImg_height = tImg_width * oImg_ratio; // Target image height, resized according to the original image ratio.
        var sliderCode_w = $('#slider-code').width();
        var sliderCode_h = $('#slider-code').height();
        var ul_width = $('#slider-code .viewport ul').width();

    //  console.log("Original Image Height: ", oImg_height, " Original Image Width: ", oImg_width, " Original Image Aspect Ratio: ", oImg_ratio, " Slider Code Width: ", sliderCode_w, " Slider Code Height: ", sliderCode_h, " Window Width: ", win_width, " UL Width: ", ul_width, " Target Image Width: ", tImg_width, " Target Image Height: ", tImg_height);

        $('#slider-code .viewport .overview img:lt(26)').css({'width' : tImg_width, 'height' : tImg_height});   //resizes the images

        var rImg_width = $('#slider-code .viewport .overview img:eq(1)').width(); // size of resized image width 
        var rImg_height = $('#slider-code .viewport .overview img:eq(1)').height(); // size of resized image width

        $('#slider-code .next').css({'top' : rImg_height / 2}); //This needs to be resolved for various size windows
        $('#slider-code .prev').css({'top' : rImg_height / 2});     
        $('#slider-code').css({'width': '100%', 'height': rImg_height + 10}); //to accomodate borders, extra padding was added to heights. To make it truly dynamic, a variable (as a percentage) of the width of the window, could be used to be added to the height
        $('#slider-code .viewport').css({'width': win_width * 0.94, 'height': rImg_height + 10});
        $('#slider-code .overview li').css({'width': rImg_width + 5});
        var view_new_w = $('#slider-code .viewport').width();
        var view_new_h = $('#slider-code .viewport').height();
        var li_w = $('#slider-code .overview li').width();
        var rUl_width = $('#slider-code .viewport ul').width();


//      console.log("Viewport New Width: ", view_new_w, view_new_h, " List Item Width: ", li_w, " Resized Image Width: ", rImg_width, " Resized Image Height: ", rImg_height, " Resized UL Width: ", rUl_width);

        $('#slider-code').tinycarousel({ controls: true, animation: true, display: 1 });            

// --------------- End Comparison Code --------------------------------------------------------------------------

})

Btw, I put the JS in the window.load function because when I put it in document ready it wasn't working properly, because the code had to detect the window size before resizing the images - and if the window hadn't loaded it would just stall and not load the carousel with the correct images.

I know the task seems daunting, but I REALLY hope the community can come through for me.

Thanks.

Edit: No one brave enough to take a stab?

Edit 2: I have made the changes suggested by JonP, but I am having some new issues now that I am trying to work through. Anyone have any suggestions on how I can get it back to normal? Reload the above link to see the new version.



Solution :

Completely untested and a stab in the dark as I am not overly familiar with tiny carosel.

This might help DRY you out a bit and provide a small performance improvement through caching some repeated selectors.

It wont help with your 4-up issue though

    //Go Global with our varibles
    var oImg, sliderCode, sliderViewPort,sliderOverViewImg , win_width;
    var oImg_height, oImg_width, oImg_ratio, tImg_width, tImg_height, sliderCode_w, sliderCode_h, ul_width;
    var rImg_width, rImg_height, view_new_w, view_new_h, li_w, rUl_width;

    function setUp(numImages) {
        oImg_height = oImg.height(); //size of original image height 
        oImg_width = oImg.width(); //size of original image width 
        oImg_ratio = oImg_height / oImg_width; //aspect ratio of original image 
        tImg_width = (win_width * 0.915) / num_of_images; // Target image width = (90% of the window) / 2 
        tImg_height = tImg_width * oImg_ratio; // Target image height, resized according to the original image ratio. 
        sliderCode_w = sliderCode.width();
        sliderCode_h = sliderCode.height();
        var ul_width = $('#slider-code .viewport ul').width();

        //  console.log("Original Image Height: ", oImg_height, " Original Image Width: ", oImg_width, " Original Image Aspect Ratio: ", oImg_ratio, " Slider Code Width: ", sliderCode_w, " Slider Code Height: ", sliderCode_h, " Window Width: ", win_width, " UL Width: ", ul_width, " Target Image Width: ", tImg_width, " Target Image Height: ", tImg_height); 

        $('#slider-code .viewport .overview img:lt(26)').css({ 'width': tImg_width, 'height': tImg_height });   //resizes the images

        rImg_width = sliderOverViewImg.width(); // size of resized image width  
        rImg_height = sliderOverViewImg.height(); // size of resized image width 

        $('#slider-code .next').css({ 'top': rImg_height / 2 }); //This needs to be resolved for various size windows 
        $('#slider-code .prev').css({ 'top': rImg_height / 2 });
        sliderCode.css({ 'width': '100%', 'height': rImg_height + 10 }); //to accomodate borders, extra padding was added to heights. To make it truly dynamic, a variable (as a percentage) of the width of the window, could be used to be added to the height 
        sliderViewport.css({ 'width': win_width * 0.94, 'height': rImg_height + 10 });
        $('#slider-code .overview li').css({ 'width': rImg_width + 5 });
        view_new_w = sliderViewPort.width();
        view_new_h = sliderViewPort.height();
        li_w = $('#slider-code .overview li').width();
        rUl_width = $('#slider-code .viewport ul').width();

        //      console.log("Viewport New Width: ", view_new_w, view_new_h, " List Item Width: ", li_w, " Resized Image Width: ", rImg_width, " Resized Image Height: ", rImg_height, " Resized UL Width: ", rUl_width); 

        sliderCode.tinycarousel({ controls: true, animation: true, display: 1 });

    }

    $(window).load(function() {
        //Cache Some Common Elements
        oImg = $('#slider-code .viewport .overview img:eq(1)');
        sliderCode = $('#slider-code');
        sliderViewPort = $('#slider-code .viewport');
        sliderOverViewImg = $('#slider-code .viewport .overview img:eq(1)')

        // --------------------------- Begin Comparison Code --------------------------------------------------------        
        win_width = $(window).width();
        num_of_images = 2; //The number of images expected in view (2 for 2-up, 3 for 3-up, etc.) The default value is 2. 

        $("#viewbar img").click(function(e) {
            num_of_images = parseInt($(this).attr("data-id"), 10); // This accepts the integer associated with the navbar.           
            $('#viewname').text(num_of_images + '-up');

            setUp(num_of_images);

            e.preventDefault();
        });

        //Default set up
        setUp(num_of_images);


        // --------------- End Comparison Code -------------------------------------------------------------------------- 

    }) 

Good Luck.


    CSS Howto..

    How can I split a text in 2 color vertically?

    How to reset a css animation class using jquery?

    bootstrap dropdown on mouse over the menu item should show edit/delete icon on right side

    How to delete first pseudo after

    how to force page break between absolutely positioned elements in css

    css animation how to get the ball to bounce

    How to make a site have a built in user-friendly editor?

    How to make vertical text change into horizontal text in css?

    How does Materialize icons work? [duplicate]

    How to replace css using jquery after user agent detection

    How to center [image + text] of unknown width?

    Intellij IDEA 11: how can I compile .css from .less?

    How HTML Inheritance works with conflicting styles rules in CSS?

    How to Display text in Middle of table cell Horizontally and vertically in html css?

    How do I convert scss to css

    CSS image rollover map and jQuery : how to use a second li list?

    How to position hidden speech bubbles

    How to get a frame off animated png using CSS?

    How to force or bring vertical scroll bar to front in html css

    How to change image size when nested in

    tag

    How do I make this sticky footer stick to the bottom of the layout when the sidebar exceeds screenheight?

    Toggle radio button on javascript hide/show of div

    How remove space on around content (css)?

    jquery mobile data-filter css styling--how to?

    How to have CSS animation NOT consume one's entire CPU?

    How can I select every other element that does not have a specific class?

    How can i get rid of the open space between the topside of my website and my navigation bar (bootstrap)

    How to add a specific class to select2 drop element?

    How to vertically center in yui-pure-css?

    How to make divs appear and disapear on hover in css?