Like a sunflower seeds simulation, nature use 137,5077 angle to generate the most efficient arrangement of seeds AND, has not calculators like us. Enjoy it, you have it around you all the time.
p=new Array();x=0;y=0;r=1;co=0;w=0;h=0;ra=5;
function Pa(ox,oy,c,s){this.x=0;this.y=0;this.ox=ox;this.oy=oy;this.c=c;this.s=s;this.sx=0;this.sy=0;}
window.onload=function()
{
w=a.width;h=a.height;
x=w/2;y=h/2;
a.addEventListener('mousemove', function(evt){
var r=a.getBoundingClientRect();x=evt.clientX-r.left;y=evt.clientY-r.top;dx=w/2-x;dy=h/2-y;co=Math.sqrt(dx*dx+dy*dy)/((w+h)/14);
if(y<h*.3&&ra>1)ra--;
if(y>h*.7&&ra<10)ra++;
},false);
ml(0);
an();
};
function an()
{
c.clearRect(0,0,w,h);ml(1);window.setTimeout(an,16);
}
function ml(f)
{
for(var i=384;i>=0;i--)
{
if(f)
{
l=p[i];
l.x+=(x-l.x)/l.s;l.y+=(y-l.y)/l.s;l.sx=Math.random();l.sy=Math.random();
c.beginPath();c.arc(l.x+l.ox+l.sx,l.y+l.oy+l.sy,ra,0,6.28318-co);c.fillStyle=l.c;c.fill();c.strokeStyle=l.c;c.stroke();
}
else
{
ang=(2.399*i);
if(!(i%5))r+=2;
s=r+6;
pr=new Pa(Math.cos(ang)*r,Math.sin(ang)*r,'rgba('+s*2+','+s+','+s*12+','+(.5)+')',s);p.push(pr);
}
}
}
cD1uZXcgQXJyYXkoKTt4PTA7eT0wO3I9MTtjbz0wO3c9MDtoPTA7cmE9NTsNCmZ1bmN0aW9uIFBhKG94LG95LGMscyl7dGhpcy54PTA7dGhpcy55PTA7dGhpcy5veD1veDt0aGlzLm95PW95O3RoaXMuYz1jO3RoaXMucz1zO3RoaXMuc3g9MDt0aGlzLnN5PTA7fSAgDQoNCndpbmRvdy5vbmxvYWQ9ZnVuY3Rpb24oKSANCnsNCnc9YS53aWR0aDtoPWEuaGVpZ2h0Ow0KeD13LzI7eT1oLzI7DQphLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIGZ1bmN0aW9uKGV2dCl7DQp2YXIgcj1hLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO3g9ZXZ0LmNsaWVudFgtci5sZWZ0O3k9ZXZ0LmNsaWVudFktci50b3A7ZHg9dy8yLXg7ZHk9aC8yLXk7Y289TWF0aC5zcXJ0KGR4KmR4K2R5KmR5KS8oKHcraCkvMTQpOw0KaWYoeTxoKi4zJiZyYT4xKXJhLS07DQppZih5PmgqLjcmJnJhPDEwKXJhKys7DQp9LGZhbHNlKTsNCm1sKDApOw0KYW4oKTsNCn07DQoNCmZ1bmN0aW9uIGFuKCkNCnsNCmMuY2xlYXJSZWN0KDAsMCx3LGgpO21sKDEpO3dpbmRvdy5zZXRUaW1lb3V0KGFuLDE2KTsNCn0NCg0KZnVuY3Rpb24gbWwoZikNCnsNCmZvcih2YXIgaT0zODQ7aT49MDtpLS0pDQp7DQppZihmKQ0Kew0KbD1wW2ldOw0KbC54Kz0oeC1sLngpL2wucztsLnkrPSh5LWwueSkvbC5zO2wuc3g9TWF0aC5yYW5kb20oKTtsLnN5PU1hdGgucmFuZG9tKCk7DQpjLmJlZ2luUGF0aCgpO2MuYXJjKGwueCtsLm94K2wuc3gsbC55K2wub3krbC5zeSxyYSwwLDYuMjgzMTgtY28pO2MuZmlsbFN0eWxlPWwuYztjLmZpbGwoKTtjLnN0cm9rZVN0eWxlPWwuYztjLnN0cm9rZSgpOw0KfQ0KZWxzZQ0Kew0KYW5nPSgyLjM5OSppKTsNCmlmKCEoaSU1KSlyKz0yOw0Kcz1yKzY7DQpwcj1uZXcgUGEoTWF0aC5jb3MoYW5nKSpyLE1hdGguc2luKGFuZykqciwncmdiYSgnK3MqMisnLCcrcysnLCcrcyoxMisnLCcrKC41KSsnKScscyk7cC5wdXNoKHByKTsNCn0NCn0NCn0=
//Global variables
p=new Array();
mx=0; // mouse x
my=0; // mouse y
radious=1; // radious
coef=0;
w=0; // canvas width
h=0; // canvas height.
ra=5; // particle size.
//Seed class Pa because is a particle.
function Pa(ox,oy,c,s)
{
this.x=0; // center x coordinate
this.y=0; // center y coordinate
this.ox=ox; // offset x
this.oy=oy; // offset y
this.c=c; // colour
this.speed=s; // speed
this.sx=0; // shake x
this.sy=0; // shake y
}
//Program start
window.onload=function()
{
a=document.getElementById('canv');
c=a.getContext('2d');
w=a.width;
h=a.height;
mx=w/2;
my=h/2;
a.addEventListener('mousemove', function(evt)
{
var r=a.getBoundingClientRect();
mx=evt.clientX-r.left;
my=evt.clientY-r.top;
// Make 0,0 be the center of the canvas.
dx=w/2-mx;
dy=h/2-my;
coef = Math.sqrt(dx*dx + dy*dy) / ((w+h)/14);
// If mouse_y is near top or bottom change particle's size.
if(my < h*0.3 && ra > 1)
ra--;
if(my > h*0.7 && ra <10)
ra++;
},false);
// My custom loop funcion that recycles "for"
myLoop(0);
// Animate
animate();
};
// Clear canvas, update positions and render.
function animate()
{
c.clearRect(0,0,w,h);
myLoop(1);
// Canvas rectangle
c.beginPath();c.lineWidth = 1;c.rect(0, 0, w,h);c.stroke();
window.setTimeout(animate, 16);
}
//Perform initialization or update positions. Here the trick is recicle the function.
// functionality=0 then function update positions.
// functionality=1 then function does initialization.
function myLoop(functionality)
{
for (var i=384;i>=0;i--)
{
if(functionality)
{
// Reduce code because there are many places that uses p[i].
l=p[i];
// Update position using custom Xenon theorem (half path beetwen two point)
// in this case a proportional distance beetwen source and target given by .t
l.x+=(mx-l.x)/l.speed;
l.y+=(my-l.y)/l.speed;
l.sx=Math.random();
l.sy=Math.random();
c.beginPath();
// Use "arc" to draw circle, but 6.28318-coefspecial effect.
c.arc(l.x+l.ox+l.sx, l.y+l.oy+l.sy, ra,0,6.28318-coef);
c.fillStyle=l.c;
c.fill();
c.strokeStyle=l.c;
c.stroke();
}
else
{
// Convert to radian.
angle = (137.5077 * Math.PI / 180 * i); //You can replace "137,5077*PI/180" by "2.399" and win some bytes.
// Each 5 loops, perform radious variation.
if ((i % 5) == 0) //You can replace "(i % 5) == 0" by "!(i%5)" and save some bytes.
radious +=2;
// Trick, use speed to generate color and make it depend on radious and win some bytes.
speed = radious + 6;
// Create and initialize particle item.
pr=new Pa(
Math.cos(angle)*radious,
Math.sin(angle)*radious,
'rgba('+speed*2+','+speed+','+speed*12+','+(0.5)+')',
speed);
p.push(pr);
}
}
}