Search code examples
jqueryoptimizationoffset

Speed up setting a lot of span positions


I span every character of a paragraph with jQuery to animate it later.

// span each character
$('#testText p').children().andSelf().contents().each(function(){
    if (this.nodeType == 3) {
        var $this = $(this);
        $this.replaceWith($this.text().replace(/(\w)/g, "<span>$&</span>"));
    }
});

// store each span
$spanCharacters = $('#testText p span');

I have around 800 characters. It goes very slow... I wondered if there is any way to get it faster.

Like now it creates a style for every span:

<span style="position: relative; top: 8.763065797205456px; left: 0px;">i</span>

Is it possible to change the position directly?

Here is the complete code, notice i have the draw method off!

If you turn it on, be aware things go slowly.

var TWO_PI = 6.2831855;

var frameCount = 0;

var $spanCharacters = new Array();

$(document).ready(function() {   

    // span each character
    $('#testText p').children().andSelf().contents().each(function(){
        if (this.nodeType == 3) {
            var $this = $(this);
            $this.replaceWith($this.text().replace(/(\w)/g, "<span>$&</span>"));
        }
    });

    // store each span
    $spanCharacters = $('#testText p span');

    //var handle = setInterval(draw, 80);
    draw();

});



function draw() {
    frameCount++;

    var width = 500;


    $spanCharacters.each(function() {

        var offsetLeft = $(this).offset().left;
        var offsetTop = $(this).offset().top;

       var posLeft = $(this).position().left;

       var a = map(posLeft+frameCount, 0, width/5, 0, TWO_PI);
       var c = Math.cos(a);

        var addOffset = c*10;
        //console.log(addOffset);

       $(this).offset({ top: offsetTop+addOffset, left: offsetLeft });

    });
}

function map(value, istart, istop, ostart, ostop) {
    return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
 }

So in short, how can this be sped up?

http://jsfiddle.net/LwD42/4/


Solution

  • $.offset() does a lot of checks you probably don't need. You should also cache your jQuery objects instead of constantly recreating them. For example:

    Replace $(this) with var self = $(this) and just make calls to self. Everytime you use the $() function jQuery creates another object.

    You could do the following which would be much faster:

    $spanCharacters.each(function() {
       var a = map(this.offsetLeft + frameCount, 0, width/5, 0, TWO_PI);
       var c = Math.cos(a);
    
       var addOffset = c * 10;
    
       this.style.position = "relative";
       this.style.top = addOffset + "px";
    });
    

    http://jsfiddle.net/LwD42/9/

    Here is a performance test comparing the two: http://jsperf.com/span-position-speed-test/ This version is roughly twice as fast in my browser. It is still relatively slow but this always will be as you are editing such a large number of DOM elements.