4

I am drawing an arc which increases gradually and turns in to a circle.On completion of animation(arc turning in to a circle) i want to draw another circle with increased radius with the previous circle persisting and the second animation continuing.

Arc to circle fiddle

After the circle is drawn,it gets washed out which is something that I dont want and continue the second animation. Some unnecessary animation appears after the completion.

What should I do?

MyCode:

    setInterval(function(){
        context.save();
        context.clearRect(0,0,500,400);
        context.beginPath();
        increase_end_angle=increase_end_angle+11/500;
        dynamic_end_angle=end_angle+increase_end_angle;
        context.arc(x,y,radius,start_angle,dynamic_end_angle,false);
        context.lineWidth=6;
        context.lineCap = "round";
        context.stroke();
        context.restore();
           if(dynamic_end_angle>3.5*Math.PI){  //condition for if circle completion
                draw(radius+10);//draw from same origin and increasd radius
           }
    },66);

window.onload=draw(30);

UPDATE:when should i clear the interval to save some cpu cycles and why does the animation slows down on third circle ??

3 Answers3

3

This snippet from your code has some flaw.

if(dynamic_end_angle>3.5*Math.PI){  //condition for if circle completion
    draw(radius+10);//draw from same origin and increased radius
}

The recursive call to draw() will continue to run after the first circle was drawn completely. This is why the performance will be slow down immediately. You need to somehow block it.

I did a simple fix, you can polish it if you like. FIDDLE DEMO

My fix is to remove context.clearRect(0, 0, 500, 400); and change the new circle drawing logic to:

if (dynamic_end_angle > 3.5 * Math.PI) { //condition for if circle completion
    increase_end_angle = 0; // this will prevent the draw() from triggering multiple times.
    draw(radius + 10); //draw from same origin.
}

In this stackoverflow thread, it mentions how to make it more smooth. You'd better use some drawing framework since the optimization needs a lot of work.

Community
  • 1
  • 1
zs2020
  • 53,766
  • 29
  • 154
  • 219
  • when should i clear the interval to save some cpu cycles and why does the animation slows down on third circle ?? – user2617915 Jul 29 '13 at 18:14
  • @ColeJohnson:should i clear interval?and what should i do to make the animation sharper..without clear rectangle my animation becomes ugly and loses sharpness – user2617915 Jul 29 '13 at 18:17
  • That fix won’t prevent `draw()` from triggering multiple times, because of `increase_end_angle = increase_end_angle + 11 / 500;`. – Ry- Jul 29 '13 at 18:36
3

First of all, about the flicker: you are using setInterval and not clearing it for the next draw(). So there’s that.

But I’d use a completely different approach; just check the time elapsed since the start, and draw an appropriate number of circles using a loop.

var start = new Date().getTime();

var timePerCircle = 2;
var x = 190, y = 140;

function draw() {
    requestAnimationFrame(draw);
    g.clearRect(0, 0, canvas.width, canvas.height);

    var t = (new Date().getTime() - start) / 1000;
    var circles = t / timePerCircle;
    var r = 30;

    do {
        g.beginPath();
        g.arc(x, y, r, 0, Math.PI * 2 * Math.min(circles, 1));
        g.stroke();
        r += 10;
        circles--;
    } while(circles > 0);
}

draw();
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • I have some json data and i have to draw my circles according to those?not according to date..+1 – user2617915 Jul 29 '13 at 18:20
  • @user2617915: Okay, so instead of using the time, use whatever’s in your JSON. `t` is flexible. – Ry- Jul 29 '13 at 18:21
  • @user2617915: I try to make it self-documenting. Which part(s) do you need explained? – Ry- Jul 29 '13 at 18:26
  • draw function...not much is left..i know what raf is. – user2617915 Jul 29 '13 at 18:30
  • @user2617915: It gets the time in seconds since the beginning of the animation and puts that in `t` (although anything can go in here — `t` is just some arbitrary “progress of animation” with the same unit as `timePerCircle`). Then it gets the number of circles or circle parts to draw as `circles`. With a starting radius (here `30`), it draws up to one circle at that radius, then increases the radius by 10 and reduces the number of circles left by one until there are no circles left. – Ry- Jul 29 '13 at 18:33
  • e.g. `t` is `15`, so `circles` would be `7.5` and it would draw 7 circles and then one half-circle. – Ry- Jul 29 '13 at 18:33
  • say i want to complete one cirlce in 60 sec and depending on my json data,how do i stop in the animation in midst??and i am unable to understand what you are doing with date? – user2617915 Jul 29 '13 at 18:36
  • @user2617915: Change `timePerCircle` to `60`. As for the second part, how does your JSON data affect the circles? Does it say how many circles to draw, or their radii or something? And `new Date().getTime()` gets the current timestamp in milliseconds. – Ry- Jul 29 '13 at 18:37
  • my json data provides time eg,0,10,20 to 60 but it is coming from ajax and may stop at any point say 20 – user2617915 Jul 29 '13 at 18:39
  • @user2617915: The time to draw each circle as an array? Or the time to draw all of the circles? Or the time to stop? – Ry- Jul 29 '13 at 18:41
  • for 10 it denotes 10 sec so a 60 sec=1 complete circle...and every ajax call sends one time..i want the animation to continue from say a to b to c and not a to c..i hope you understand what i am asking? – user2617915 Jul 29 '13 at 18:45
  • i have few questions..please go through it...these are doubts that came to my mind...your code works best for me...http://jsfiddle.net/VmkwD/1/ – user2617915 Aug 04 '13 at 06:50
1

When should I clear the interval to save some cpu cycles?

Better yet not use an interval at all for a couple of reasons:

  • Intervals are unable to sync to monitor's VBLANK gap so you will get jerks from time to time.
  • If you use setInterval you risk stacking calls (not high risk in this case though).

A much better approach is as you probably already know to use requestAnimationFrame. It's less CPU hungry, is able to sync to monitor and uses less resources in general even less if current tab/window is not active.

Why does the animation slows down on third circle ??

Your drawing calls are accumulating which slows everything down (setInterval is not cleared).

Here is a different approach to this. It's a simplified way and uses differential painting.

ONLINE DEMO

The main draw function here takes two arguments, circle index and current angle for that circle. The circles radius are stored in an array:

...,
sa = 0,                   // start angle
ea = 359,                 // end angle
angle = sa,               // current angle
oldAngle = sa,            // old angle
steps = 2,                // number of degrees per step
current = 0,              // current circle index
circles = [70, 80, 90],   // the circle radius
numOfCircles = circles.length, ...

The function stores the old angle and only draws a new segment between old angle and new angle with 0.5 added to compensate for glitches due to anti-alias, rounding errors etc.

function drawCircle(circle, angle) {

    angle *= deg2rad; // here: convert to radians

    /// draw arc from old angle to new angle
    ctx.beginPath();
    ctx.arc(0, 0, circles[circle], oldAngle, angle + 0.5);
    ctx.stroke();

    /// store angle as old angle for next round
    oldAngle = angle;
}

The loop increases the angle, if above or equal to end angle it will reset the angle and increase the current circle counter. When current counter has reach last circle the loop ends:

function loop() {

    angle += steps;

    /// check angle and reset, move to next circle        
    if (angle >= ea - steps) {
        current++;
        angle = sa;
        oldAngle = angle;
    }

    drawCircle(current, angle);

    if (current < numOfCircles)
        requestAnimationFrame(loop);
}
alex
  • 479,566
  • 201
  • 878
  • 984