views:

123

answers:

2

I have just finished my new portfolio site visible at http://www.pepkarsten.com/artdirection.

It is a single page that loads images (with loader animation, preloading and keyboard shortcuts).

Here is the JavaScript code (using jQuery). How can it be optimized?

$(document).ready(function() {
    function page(slide,width,height,color) {
        this.slide=slide;
        this.width=width;
        this.height=height;
        this.color=color;
    };

    var pages=[
        new page('alutech1',900,675,'1d486b'),
        new page('alutech2',900,675,'00ea00'),
        new page('mane3',675,900,'74878e'),
        new page('mane4',675,900,'74878e'),
        new page('mane1',900,675,'6ecb00'),
        new page('topfit_zen',900,675,'203400'),
        new page('topfit_muscu',900,675,'01acb3'),
        new page('topfit_stval',900,675,'525962'),
        new page('arles_1',636,900,'fb926d'),
        new page('arles_2',636,900,'c12f2f'),
        new page('arles_3',636,900,'cdc6b4'),
        new page('topsol',900,633,'f7e700'),
        new page('wak',900,675,'78f900')
    ];
    var imgDir='img/';
    var slidePrefix='pepkarsten_';
    var slideExt='.jpg';
    $.autoMouseOver();
    $.blurLinks();

    function prevPageNumber() {
        return currentPage>0?currentPage-1:pages.length-1;
    };

    function nextPageNumber() {
        return currentPage<pages.length-1?currentPage+1:0;
    };

    function displayPage(n) {
        $('#nav-top')
            .css('background-color','#'+pages[n].color);
        $('#slide')
            .addClass('loading')
            .find('img')
            .css('visibility','hidden')
            .css('width',pages[n].width)
            .css('height',pages[n].height)
            .unbind('load')
            .load(function() {
                $(this)
                    .css('visibility','visible');
                $('#slide')
                    .removeClass('loading');
                $.preloadImg(imgDir+slidePrefix+pages[nextPageNumber()].slide+slideExt,imgDir+slidePrefix+pages[prevPageNumber()].slide+slideExt);
            })
            .attr('src',imgDir+slidePrefix+pages[n].slide+slideExt);
        currentPage=n;
    };

    function homePage() {
        displayPage(0);
    };

    function nextPage() {
        displayPage(nextPageNumber());
    };

    function prevPage() {
        displayPage(prevPageNumber());
    };

    homePage();
    $('#home')
        .onclick(homePage)
        .shortcut('up');
    $('#next')
        .onclick(nextPage)
        .shortcut('right');
    $('#prev')
        .onclick(prevPage)
        .shortcut('left');
    $('#slide')
        .onclick(nextPage);
    $('#contact')
        .email('info','pepkarsten.com')
        .hover(
            function() {$('#tip-contact').slideDown(200)},
            function() {$('#tip-contact').stop(true,true).hide()});
    $('#linkedin')
        .onclick(function() {
            window.open('http://www.linkedin.com/in/pepkarsten');
        })
        .hover(
            function() {$('#tip-linkedin').slideDown(200)},
            function() {$('#tip-linkedin').stop(true,true).hide()});
});

(function($){
    var imgCache=new Array();
    $.preloadImg=function() {
        for(var i=0; i<arguments.length; i++) {
            var img=new Image();
            img.src=arguments[i];
            imgCache[img.src]=img;
        }
    };
    $.autoMouseOver=function(outStr,overStr) {
        if(!overStr) var outStr='-out.', overStr='-over.';
        $('img[src*='+ outStr +']')
            .each(function() {$.preloadImg($(this).attr("src").replace(outStr,overStr))})
            .hover(
                function() {$(this).attr("src",$(this).attr("src").replace(outStr,overStr))},
                function() {$(this).attr("src",$(this).attr("src").replace(overStr,outStr))});
    };
    $.blurLinks=function() {
        $("a").focusin(function() {
            this.blur();
        });
    };
    $.fn.onclick=function(f) {
        $(this).click(function() {
            f();
            return false;
        });
        return this;
    };
    $.address=function(u,d) {
        return u+'@'+d;
    };
    $.fn.email=function(u,d,s,b) {
            var l='mailto:'+$.address(u,d);
            if(s||b) {
                l+='?';
                if(s) {
                    l+='subject='+s;
                    if(b) l+='&';
                };
                if(b) l+='body='+b;
            };
        $(this).click(function() {
            window.open(l);
            return false;
        });
        return this;
    };
    $.fn.shortcut=function(key) {
        var code={'left':37,'up':38,'right':39,'down':40};
        var $this=$(this);
        $(document).keydown(function(e) {
            if(e.keyCode==code[key]) {
                $this.click();
                return false;
            };
        });
        window.focus();
        return this;
    };
})(jQuery);
+4  A: 

Practical answer: No need for optimization, you have got smooth working preloading that minimize the effect of connection slowness. The impact of any speed-imperfections in the code is negligible, the network optimization is done correctly, that is what matters in this case.

Theoretical answer: If you truly worry about performance then don't use jQuery, you simply don't have the low level control required for making truly optimized JavaScript, and you generally end up with a lot of obfuscated overhead since what seems like a simple jQuery function may actually have a complex implementation and thus cost a lot of time.

For the record, I'd say you are the first designer I have met who can code. Of course there are others who can stick together some commands, but it seems like you actually know what you are doing. A piece of advice for the road, since I think you are the type who can manage it: Whatever people tell you, question it, try to find proof for the opposite and do your own research if necessary.

Edit: About jQuery vs. JavaScript
As I see it, the biggest advantage of jQuery is that it fixes a lot of browser differences so you don't have to worry whether the code will work in all browsers. jQuery also does a lot of "magic" which may make coding easier, but the magic typically cost a lot speed-wise, how much depends a lot on which functions you use, and how you use them. You easily toss a factor 10 on script execution, but most code continue to be limited by DOM manipulation, and jQuery does not slow that down.
I'm no fan of jQuery syntax, it is very much in line with a current trend of convoluting everything using closures and using the keyword this as much as possible. That is of course not to say that you have to write such unreadable code if you use jQuery, but it is hard not to drag in that direction. If you write something big I would prefer JavaScript, since readability is then a much bigger issue.

eBusiness
+1 Pep, the code looks fine, like anything it could get better but might not be immediately necessary!
Trufa
Thank you my friends. @ eBusiness : Very interesting points of view. I am new to jQuery and indeed still questionning myself about it versus hardcore javascript (as i used to do with my previous personal websites)...
Pep
A: 

Only a few minor things jumped out at me. Overall, it looks smooth in Chrome.

Before I get to those I'd like to suggest that you comment your code. It'll make it much easier on you a year from now when you go back and try to make a change! Also you might want to think about ordering your functions in some sensible manner (alphabetically for example, or whatever else you can think of that makes sense... they don't seem to be in any order that I can tell)

One thing I noticed is that you try to optimize your code by only creating the $(this) jQuery object once for each instance using var $this = $(this);. You use this even when $(this) is only used once, which is fine but unnecessary, but you forgot to do it in a few instances.

For example you have:

.....hover(function() { 
               $(this).attr("src",$(this).attr("src").replace(outStr,overStr))},
           function() {
               $(this).attr("src",$(this).attr("src").replace(overStr,outStr))});

This could be:

.....hover(function() { 
               var $this = $(this);
               $this.attr("src",$this.attr("src").replace(outStr,overStr))},
           function() {
               var $this = $(this);
               $this.attr("src",$this.attr("src").replace(overStr,outStr))});
Peter Ajtai
`blur` is also a native JavaScript method, it is what is used, and that is perfectly legit. The `$this = $(this)` trick is as far as I can tell used for the purpose of passing the created jQuery object from one scope to another, but you are right that it could also be used for a slight performance enhancement in a few situations.
eBusiness
Thanks, i corrected the $this trick. However as i told to eBusiness i am wondering about Jquery versus hardcore javascript then i kept this.blur() and corrected the hover function with pure JS : this.src=this.src.replace(outStr,overStr). Do you think it is better to rely on jQuery even when it is as simple to write a line in pure JS ?
Pep
@Pep - Sorry, you're right. `.blur()` is a JS method. It's always better to use native JS than jQuery (as long as it's x-browser compatible).
Peter Ajtai
@eBusiness - Yeah. Didn't realize `.blur()` was a JS method. `var $this = $(this)` is used so you only have to build the same jQuery object once... for that slight performance advantage..... You're right in that the same trick can be used to pass the context, but in that case it'd make more sense to not call it `$this`... maybe `var $that = $(this);` is you want to pass the context to another scope.
Peter Ajtai