Example 11: Animated Phyllotaxy Spiral

refresh(dc, width, height, frame_number) // Sample code by Jim Bumgardner
{
  dc.clearRect(0,0,width,height);
  
  var nbr_circles = 333;
  var deviation = 5/8.0;
  
  var phi = (Math.sqrt(5)+1)/2 - 1;            // golden ratio
  var golden_angle = phi*2*Math.PI;            // golden angle
  
  var lg_rad = width * .45;
  var lg_area = Math.pow(lg_rad,2)*Math.PI;
  
  var mean_area = lg_area / nbr_circles;
  
  var min_area = mean_area * (1-deviation);
  var max_area = mean_area * (1+deviation);
  
  var cum_area = 0;
  
  var fudge = .87; // Fudge factor, since our circles don't actually fill up space entirely.
  
  var cx = width/2;
  var cy = height/2;
  
  var hue_incr = frame_number * .0002 + .1;
  var angle_offset = frame_number * .01;
  
  for (var i = 1; i <= nbr_circles; ++i) {
    dc.beginPath();
  
    var angle = i*golden_angle + angle_offset;
  
    var ratio = i / nbr_circles;
    var sm_area = min_area + ratio * (max_area - min_area);
    var sm_rad = Math.sqrt( sm_area / Math.PI );
  
    cum_area += sm_area;
  
    var spiral_rad = Math.sqrt( cum_area / Math.PI );
    var x = cx + Math.cos(angle) * spiral_rad;
    var y = cy + Math.sin(angle) * spiral_rad;
  
    var hue = hue_incr*i;
    hue -= Math.floor(hue);
    hue *= 360;
  
    dc.fillStyle = 'hsl(' + hue + ',80%,50%)';
  
    dc.arc(x, y, sm_rad * fudge, 0, 2*Math.PI, false);
    dc.fill();
  }
  
}

Notes:

To animate the colors, for each dot, I create a fill color using a variable called 'hue' which cycles through the colors. The colors are highly saturated, and bright. I'm using an HSL (hue, saturation, luminance) CSS style, which simplifies doing effects where you need precise control of hue (or saturation or luminance).

    dc.fillStyle = 'hsl(' + hue + ',80%,50%)';

I want each dot to have a different hue, so assuming there is an existing variable called hue_incr, I create a hue value for each dot, based on it's index i. This is the same method I used to wind the spiral earlier, and the effect will ultimately resemble that effect. Because each dot cycles at an increasing rate, you got spiraling color effects.

  var hue = hue_incr*i;
  hue *= 360;
  dc.fillStyle = 'hsl(' + hue + ',80%,50%)';

I want the hue to cycle back to zero when it hits 360. I accomplish this by subracting the part that is over 1, leaving just the stuff after the decimal (if I had wanted the color to go back and forth, instead of cycling around, I would have used sin() instead).

  var hue = hue_incr*i;
  hue -= Math.floor(hue);
  hue *= 360;
  dc.fillStyle = 'hsl(' + hue + ',80%,50%)';

Finally, I need to set a continuously rising value for hue_incr. This is done outside the loop, since it is not dependent on i.

  var hue_incr = frame_number * .0002 + .1;

I use a fraction of the frame number by multipling it by a small value (frame_number/5000.0 would have also worked, but I prefer to use multiplcation when setting speeds - this way larger numbers go faster). The fraction I used, .0002 was arrived experimentally by trying different values until I found a cycling speed I liked. After setting the speed, I add .1 so that the very first frame already has a spiral in it, otherwise, the first frame is mostly solid.