4

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

弧形小提琴

画完圆圈后,它会被洗掉,这是我不想要的,然后继续第二个动画。完成后会出现一些不必要的动画。

我应该怎么办?

我的代码:

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

更新:我什么时候应该清除间隔以节省一些 cpu 周期,为什么动画在第三圈变慢?

4

3 回答 3

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()将继续运行。这就是为什么性能会立即变慢的原因。你需要以某种方式阻止它。

我做了一个简单的修复,如果你喜欢,你可以擦亮它。小提琴演示

我的解决方法是删除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线程中,它提到了如何使它更流畅。您最好使用一些绘图框架,因为优化需要大量工作。

于 2013-07-29T18:04:09.080 回答
2

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

但我会使用完全不同的方法;只需检查自开始以来经过的时间,并使用循环绘制适当数量的圆圈。

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();
于 2013-07-29T18:17:28.007 回答
1

我应该什么时候清除间隔以节省一些 cpu 周期?

最好不要使用间隔,原因如下:

  • 间隔无法同步到监视器的 VBLANK 间隙,因此您会不时出现抽搐。
  • 如果您使用 setInterval ,您可能会冒着堆叠调用的风险(尽管在这种情况下风险并不高)。

更好的方法是您可能已经知道使用requestAnimationFrame. 如果当前选项卡/窗口不活动,它的 CPU 消耗更少,能够同步监控并使用更少的资源,甚至更少。

为什么动画在第三圈变慢?

您的绘图调用正在累积,这会减慢一切(setInterval未清除)。

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

在线演示

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

...,
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);
}
于 2013-07-29T23:09:28.967 回答