沿半径增加绘制圆弧?

时间:2013-07-29 17:58:50

标签: javascript jquery animation canvas html5-canvas

我正在绘制一个渐渐增加的圆弧,然后变成圆形。完成动画(圆弧变成圆形)后,我想绘制另一个半径增大的圆,前一个圆持续存在,第二个动画继续。

Arc to circle fiddle

绘制圆圈后,它会被淘汰掉,这是我不想要的东西并继续第二个动画。 完成后会出现一些不必要的动画。

我该怎么办?

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 :我什么时候应该清除间隔以保存一些cpu周期?为什么动画会在第三圈减慢?

3 个答案:

答案 0 :(得分:4)

您的代码中的代码段存在一些缺陷。

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

在完全绘制第一个圆圈后,对draw()的递归调用将继续运行。这就是为什么性能会立即降低的原因。你需要以某种方式阻止它。

我做了一个简单的修复,你可以根据自己的喜好进行修饰。的 FIDDLE DEMO

我的解决方法是删除context.clearRect(0, 0, 500, 400);并将新的圆绘图逻辑更改为:

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.
}

在此stackoverflow thread中,它提到如何使其更顺畅。你最好使用一些绘图框架,因为优化需要很多工作。

答案 1 :(得分:2)

首先,关于闪烁:您正在使用setInterval而不是为下一个draw()清除它。就是这样。

但我会使用completely different approach;只需检查自开始以来经过的时间,并使用循环绘制适当数量的圆圈。

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();

答案 2 :(得分:1)

  

何时应该清除间隔以节省一些cpu周期?

最好不要使用间隔,原因有两个:

  • 间隔时间无法与监视器的VBLANK间隙同步,因此您将不时得到混蛋。
  • 如果您使用setInterval,则存在堆叠呼叫的风险(在这种情况下不是高风险)。

一种更好的方法是你可能已经知道使用requestAnimationFrame。如果当前标签/窗口不活动,它可以减少CPU占用,并且能够同步监视并使用更少的资源,甚至更少。

  

为什么动画在第三圈减速?

您的绘图调用正在累积,这会减慢所有内容(setInterval未清除)。

这是一种不同的方法。这是一种简化的方式,并使用差异绘画。

<强> ONLINE DEMO

这里的主要绘制函数有两个参数,圆形索引当前角度。圆半径存储在一个数组中:

...,
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, ...

该函数存储旧角度,仅在旧角度和新角度之间绘制一个新的段,添加0.5以补偿由于抗锯齿,舍入误差等引起的毛刺。

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;
}

循环增加角度,如果大于或等于结束角度,它将重置角度并增加当前圆形计数器。当当前计数器到达最后一个圆圈时,循环结束:

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);
}