himcgyver
himcgyver

Reputation: 11

Making a spinning spiral

I have found a code to draw spiral and I need to make it spin 360 degrees (something like hypnotizing effect). I tried to animate it, but I don't know how to implement it properly. I am running out of time. It would be great if that code would be as simple as possible.

Here's the spiral code:

<canvas id="myCanvas" width="300" height="300"></canvas>
<script type="text/javascript">
    var c=document.getElementById("myCanvas");
    var cxt=c.getContext("2d");
    var centerX = 150;
    var centerY = 150;
    cxt.moveTo(centerX, centerY);

    var STEPS_PER_ROTATION = 60;
    var increment = 2*Math.PI/STEPS_PER_ROTATION;       
    var theta = increment;

    while( theta < 40*Math.PI) {
      var newX = centerX + theta * Math.cos(theta); 
      var newY = centerY + theta * Math.sin(theta); 
      cxt.lineTo(newX, newY);
      theta = theta + increment;
    }
    cxt.stroke();
</script>

Upvotes: 1

Views: 2895

Answers (2)

Jesse
Jesse

Reputation: 8749

While Xotic750's answer is much better because there's no mathematical recalculation constantly happening, here's the jsFiddle of a JavaScript-only alternative. The advantage this version provides is for backwards compatibility on browsers with no CSS3 animation support.

CSS3 animation support has only come recently to Firefox, Safari, Internet Explorer, and Opera (Desktop, Mobile, and Mini). Chrome (Desktop and Mobile), and BlackBerry Browser are the only ones shown to have supported animations from a very early stage.


Explanation:

var counter = 0;
setInterval(function () {
    DrawSpiral(counter);
    counter += 0.075;
}, 10);
  • counter is a variable that will keep count of the position that the spiral should be at on the next redraw.
  • DrawSpiral is the function that does the actual job.

There are two factors that will help with changing the speed of the spin; the change in counter (+= 0.075) and the setInterval delay (50).

The two factors should be inversely proportional. In other words, increasing the setInterval delay should go hand-in-hand with decreasing the counter change.


Changes from your original:

cxt.save();
cxt.clearRect(0, 0, c.width, c.height);

cxt.beginPath();
  • Encapsulated your spiral-drawing code into the DrawSpiral(...) function.
  • cxt.save() stores the current transformations.
  • cxt.clearRect(...) clears the canvas (so as to not draw on top of the previous drawing).
  • cxt.beginPath() starts a new line path (essentially cutting off from the last one).

Next set of changes:

var newX = centerX + theta * Math.cos(theta - mod);
var newY = centerY + theta * Math.sin(theta - mod);
  • ... Math.cos(theta - mod) changes the newX value to the next "spot".
  • ... Math.sin(theta - mod) changes the newY value to the next "spot".

Do keep in mind that this method may be a little bit slower depending on the browser, CPU, graphics card, etc.

Upvotes: 2

Xotic750
Xotic750

Reputation: 23472

ok, here is one solution using CSS animation rather than mathematical calculation.

CSS

@-webkit-keyframes myCanvas {
    0% { -webkit-transform: rotateZ(360deg); }
    100% { -webkit-transform: rotateZ(0deg); }
}
@-moz-keyframes myCanvas {
    0% { -moz-transform: rotateZ(360deg); }
    100% { moz-transform: rotateZ(0deg); }
}
@keyframes myCanvas {
    0% { transform: rotateZ(360deg); }
    100% { transform: rotateZ(0deg); }
}

#myCanvas {
    -webkit-animation: myCanvas 2s infinite linear;
    -moz-animation: myCanvas 2s infinite linear;
    animation: myCanvas 2s infinite linear;
}

HTML

<canvas id="myCanvas" width="300" height="300"></canvas>

Javascript

var c = document.getElementById("myCanvas");
var cxt = c.getContext("2d");
var centerX = 150;
var centerY = 150;
cxt.moveTo(centerX, centerY);

var STEPS_PER_ROTATION = 60;
var increment = 2 * Math.PI / STEPS_PER_ROTATION;
var theta = increment;

while (theta < 40 * Math.PI) {
    var newX = centerX + theta * Math.cos(theta);
    var newY = centerY + theta * Math.sin(theta);
    cxt.lineTo(newX, newY);
    theta = theta + increment;
}

cxt.stroke();

On jsfiddle

Upvotes: 1

Related Questions