Question

I made a quick simple solution in JSFiddle, for better and faster explaining:

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/

As the browser chooses the fps, how would I rotate the ring independently from frame speed. Because for now, if speed is 30fps it will rotate slower, but if 60fps faster, because its rotate amount is added for each call.

As i understand from couple of thread it has something to do with getTime, i really tried but could not get it done, i would need to rotate it once in 10 seconds.

The other thing is, angle, it will increase more and more, and after long long time it will crash because variable max amount will be exceeded, so how do i make seamless rotate cap ?

Thank you for reading!

Était-ce utile?

La solution

Simply use a time-diff approach locking the steps to the difference between old and new time:

DEMO

Start with getting current time:

var oldTime = getTime();

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

Then in your loop:

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

Using this approach will bind the animation to time instead of FPS.

Update For one minute I thought MODing the angle wouldn't work with floats, but you can (had to double check) so code updated.

Autres conseils

Some math will let you draw your shape at a specified speed inside an animation loop.

Demo: http://jsfiddle.net/m1erickson/9Z8pG/

Declare a startTime.

    var startTime=Date.now();

Declare the time-length of a 360 degree rotation (10seconds == 10000ms)

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

Inside each animation frame...

Use modulus math to divide the current time into 10000ms cycles.

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

In each animation frame, calculate the percent that the current time is through the current cycle.

        var elapsedCyclePercent=elapsedCycle/cycleTime;

The current rotation angle is a full circle (Math.PI*2) X the percentage.

        var radianRotation=Math.PI*2 * elapsedCyclePercent;

Redraw your object at the frame’s current rotation angle:

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

To have consistent behaviour across devices, you need to handle time by yourself, and to update positions/rotations/... based on the good old formula : position = speed * time ;
The secondary benefit of this is that in case of a frame drop, the movement will still keep same speed, hence it will be less noticeable.

fiddle is here : http://jsfiddle.net/gamealchemist/YVEhE/6/

The time is commonly measured in milliseconds in Javascript, so the speed will be in radians per milliseconds.
This formula might make things easier :

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

Then to update your rotation, just compute time elapsed since last frame (dt) at the start of your update function and do :

    currentAngle +=  speed * dt ;

instead of adding a constant.

To avoid the angle overflow, or the loss of precision (which will happen after quite some time...), use the % operator :

    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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top