Canvas使用RequestAnimationFrame以特定速度旋转圆圈

时间:2013-12-07 19:06:48

标签: javascript canvas rotation requestanimationframe

我在JSFiddle中做了一个快速简单的解决方案,以便更好,更快地解释:

var Canvas = document.getElementById("canvas");
var ctx = Canvas.getContext("2d");

var startAngle = (2*Math.PI);
var endAngle = (Math.PI*1.5);
var currentAngle = 0;

var raf = window.mozRequestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    window.oRequestAnimationFrame;

function Update(){
    //Clears
    ctx.clearRect(0,0,Canvas.width,Canvas.height);

    //Drawing
    ctx.beginPath();                  
    ctx.arc(40, 40, 30, startAngle + currentAngle, endAngle + currentAngle, false);

    ctx.strokeStyle = "orange";
    ctx.lineWidth = 11.0;
    ctx.stroke();

    currentAngle += 0.02;
    document.getElementById("angle").innerHTML=currentAngle;
    raf(Update);
}
raf(Update);

http://jsfiddle.net/YoungDeveloper/YVEhE/3/

当浏览器选择fps时,如何独立于帧速旋转环。因为目前,如果速度是30fps,它将旋转得更慢,但如果速度提高60fps,因为它的旋转量是为每次调用添加的。

正如我从几个线程中了解到它与getTime有关,我真的尝试但是无法完成它,我需要在10秒内旋转一次。

另一方面,角度,它会越来越多,经过很长一段时间后它会崩溃,因为会超过可变的最大量,所以如何制作无缝旋转帽?

感谢您阅读!

3 个答案:

答案 0 :(得分:3)

有些数学运算会让您在动画循环中以指定的速度绘制形状。

演示:http://jsfiddle.net/m1erickson/9Z8pG/

声明一个startTime。

    var startTime=Date.now();

声明360度旋转的时间长度(10秒== 10000毫秒)

    var cycleTime=1000*10;  // 1000ms X 10 seconds

在每个动画框架内......

使用模数学将当前时间分成10000ms周期。

        var elapsed=Date.now()-startTime;
        var elapsedCycle=elapsed%cycleTime;

在每个动画帧中,计算当前时间在当前周期中的百分比。

        var elapsedCyclePercent=elapsedCycle/cycleTime;

当前旋转角度是一个完整的圆圈(Math.PI * 2)X百分比。

        var radianRotation=Math.PI*2 * elapsedCyclePercent;

以帧的当前旋转角度重绘对象:

        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.beginPath();                  
        ctx.arc(40, 40, 30, -Math.PI/2, -Math.PI/2+radianRotation, false);
        ctx.strokeStyle = "orange";
        ctx.lineWidth = 11.0;
        ctx.stroke();

答案 1 :(得分:3)

只需使用time-diff方法将步骤锁定到新旧时间之间的差异:

DEMO

从获取当前时间开始:

var oldTime = getTime();

/// for convenience later
function getTime() {
    return (new Date()).getTime();
}

然后在你的循环中:

function Update(){

    var newTime = getTime(),       /// get new time
        diff = newTime - oldTime;  /// calc diff between old and new time

    oldTime = newTime;             /// update old time

    ...

    currentAngle += diff * 0.001;  /// use diff to calc angle step

    /// reset angle
    currentAngle %= 2 * Math.PI;

    raf(Update);
}

使用此方法会将动画绑定到时间而不是FPS。

更新一分钟我认为修改角度不适用于花车,但你可以(不得不仔细检查)以便代码更新。

答案 2 :(得分:1)

要在设备之间保持一致的行为,您需要自己处理时间,并根据良好的旧公式更新位置/旋转/ ...:position = speed * time;
这样做的第二个好处是,在帧丢失的情况下,移动仍将保持相同的速度,因此它将不太明显。

小提琴在这里: http://jsfiddle.net/gamealchemist/YVEhE/6/

时间通常以毫秒为单位,以Javascript为单位,因此速度将以弧度/毫秒为单位。
这个公式可能会使事情变得更容易:

var turnsPerSecond = 3;
var speed = turnsPerSecond * 2 * Math.PI / 1000; // in radian per millisecond

然后要更新轮换,只需计算更新功能开始时自上一帧(dt)起经过的时间,然后执行以下操作:

    currentAngle +=  speed * dt ;

而不是添加常量。

为避免角度溢出或精度损失(将在相当长的时间后发生......),请使用%运算符:

    currentAngle = currentAngle % ( 2 * Math.PI) ;

 function Update() {
    var callTime = perfNow();
    var dt = callTime - lastUpdateTime;
    lastUpdateTime = callTime;

    raf(Update);
    //Clears
    ctx.clearRect(0, 0, Canvas.width, Canvas.height);

    //Drawing
    ctx.beginPath();
    ctx.arc(40, 40, 30, startAngle + currentAngle, endAngle + currentAngle, false);

    ctx.strokeStyle = "orange";
    ctx.lineWidth = 11.0;
    ctx.stroke();

    currentAngle += (speed * dt);
    currentAngle = currentAngle % (2 * Math.PI);
    angleDisplay.innerHTML = currentAngle;
}