views:

46

answers:

3

Hi,

I'm having a text scaled and moved via JavaScript / jQuery. I can't use jQuerys animate() because it has to fade in and out and has to be repeated and with more elements (end result: "flying" from the background, moving in different directions and fading out).

My problem: It's not running smoothly and causes quite the cpu-usage. Here's a stripped down version:

<!DOCTYPE html>
<html>
<head>
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"&gt;&lt;/script&gt;
<meta charset=utf-8 />
<title>JS Bin</title>
<!--[if IE]>
  <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"&gt;&lt;/script&gt;
<![endif]-->
<script type="text/javascript">

    var steps = 300; // steps from start to finish

    // the final css values
    var endValueTop = 300;
    var endValueLeft = 300;
    var endValueFontSize = 100;

    // the current css values (get encreased in doAnimation())
    var currentValueTop = 100;
    var currentValueLeft = 100;
    var currentValueFontSize = 0;

    // the added values in each step
    var stepsTop = (endValueTop - currentValueTop) / steps;
    var stepsLeft = (endValueLeft - currentValueLeft) / steps;
    var stepsFontSize = (endValueFontSize - currentValueFontSize) / steps;

    function doAnimation() {

        // increase current values
        currentValueTop += stepsTop;
        currentValueLeft += stepsLeft;
        currentValueFontSize += stepsFontSize;

        // apply them
        $("#hello").css({
            top: currentValueTop,
            left: currentValueLeft,
            fontSize: currentValueFontSize
        });

        // restart if there are steps left
        if (steps--) {
            window.setTimeout(function(){
                doAnimation();
            }, 50);

        }

    }

    // start the first time
    doAnimation();

</script>

<style>
  article, aside, figure, footer, header, hgroup,
  menu, nav, section { display: block; }
  body { position: relative; }
  p#hello { position: absolute; top: 100px; left: 100px; font-size: 0px; }
</style>
</head>
<body>
  <p id="hello">Hello World</p>
</body>
</html>

Running example on JS BIN.

Any suggestions? Bonus: How to reduce the cpu load? Thanks a lot!

Steffen

A: 

I've used this library some years ago quite successfully on cellphones, maybe it has little enough overhead to make it fast enough for you:

http://dev.opera.com/libraries/animation/

nicomen
Should have the same drawbacks as jQuerys animate().
Steffen Wenzel
A: 

jQuery wasn't really designed for long animations (that's why "slow" is less than 1 second) so high CPU load isn't really going to go away.

One thing you could do is to use the animate function http://api.jquery.com/animate/

That already does a lot of what you had programmed there.

Maletor
Yeah, that would have brought down this code to three lines. But I also have to deal with increasing AND decreasing opacity in one animation. And using one interval for the five or so elements I'm moving parallel seems faster to me.
Steffen Wenzel
+1  A: 

Well first off, absolutely do not use jQuery within a 50ms timer. If anything is causing high CPU usage it is that. Use something like this instead

var hello = $('#hello')[0].style;

function doAnimation() {

  //code...

  hello.top = curentValueTop + 'px';
  hello.left = currentValueLeft + 'px';
  hello.fontSize = currentValueFontSize + 'px';

  //rest of code...

}

However, smoothly and consistently scaling of fonts is something most browsers do not handle well. Since 99% of the time the text on a web page is not flying into your face, we do not notice this. You might have more luck with an image of the text rendered at the maximum font size you need.

Also, 50ms ~= 20fps which is not a particularly smooth frame rate for animations that traverse half of the screen. If not using jQuery significantly reduces CPU usage you could try a smaller interval. Of course most browsers are not good at handling high frame rate animations either.

Yup, modern web browsers, struggling to do things that 20 year old video game consoles had no problem with, at a quarter of the frame rate.

EDIT Try this http://jsbin.com/oxode/4/edit

I used the em unit for fontSize as it accepts fractional numbers, and used a 15ms timer (about 60fps if the browser can keep up). As you can see it scales smoother, although you will have to adjust your animation settings a bit...

MooGoo
I can see that this should performe much better (couldn't see the effect though, probably not testing correctly). Thanks, I learned something. But doesn't solve the text-jumping.
Steffen Wenzel
also in the `setTimeout` call, look at using either `window.setTimeout(doAnimation, 15);` or `window.setTimeout(arguments.callee, 15);` to remove the unneccessary anonymous function wrapping the function call
Russ Cam
@Steffen Wenzel the text jumping depends a lot on the browser. It seemed smoothest to me in Firefox. Also consider using `setInterval` instead of `setTimeout` (http://jsbin.com/oxode/5/edit) might result in a smoother animation. But in the end you are probably going to get some text jumping no matter what, which is why I suggested using an image instead if that is practical.
MooGoo
@MooGoo: Switching to EM really makes a big difference, especially in Safari (Firefox seems to be able to deal with pixel fractions). Images are not practical but would do the trick, I agree. I will also try the setInterval.The main problem with my code was px instead of em, so your answer pretty much solves my problem. Thanks a lot!
Steffen Wenzel