I have worked for a few hours and this is the result:
$(document).ready(function(){
var canvas = $("#snow-collision")[0];
var stats = new Stats();
stats.setMode(1); // 0: fps, 1: ms
var debug = $("#debug");
var pi = Math.PI;
var hpi = pi / 2;
var tpi = hpi * 3;
// align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild( stats.domElement );
var ctx = canvas.getContext("2d");
var width = canvas.width = $(window).width(),
height = canvas.height = $(window).height();
var snow_canvas = $("#flake-creator")[0],
snow_ctx = snow_canvas.getContext("2d");
$(window).resize(function(){
width = canvas.width = $(window).width();
height = canvas.height = $(window).height();
});
var isClicking = false;
$(document).on("mousedown mouseup", function(e){
isClicking = e.type == "mousedown";
});
var xMouse = null,
yMouse = null;
$(document).mousemove(function(e){
xMouse = e.pageX;
yMouse = e.pageY;
});
var time = 0;
var snowFlakes = [];
var pi = Math.PI;
var windForce = 1;
setInterval(function(){
stats.begin();
time++;
var lSnow = snowFlakes.length;
if(lSnow < height) // I want the same num of snowflakes as the height of the screen!
{
var randomSize = RandomRange(5, 8);
var xSnow = RandomRange(randomSize, width - randomSize);
var newSnow = new Snowflake(xSnow, -randomSize, randomSize);
var randomSnow = RandomSnowflake(randomSize * 2);
newSnow.ChangeImage(randomSnow);
snowFlakes.push(newSnow);
}
// MOVE AROUND MOUSE
//var md = Direction(xMouse, yMouse, width / 2, height / 2),
// dd = Distance(xMouse, yMouse, width / 2, height / 2) / 50;
windForce = 0; //md > 90 && md < 270 ? dd : -dd;
ctx.clearRect(0, 0, width, height);
debug.text(lSnow + " snowflakes");
while(lSnow--)
{
var snow = snowFlakes[lSnow];
var xSnow = ~~snow.CordX,
ySnow = ~~snow.CordY,
sSnow = ~~snow.Size,
dsSnow = 2 * sSnow,
rSnow = 0;
if(time % 1 === 0) // If it becomes laggy, to make the maths a bit slower
{
var d = Distance(xMouse, yMouse, xSnow, ySnow);
var di = Direction(xMouse, yMouse, xSnow, ySnow);
var force = d / 20;
if(isClicking) force = -force;
if(d < 100 && Math.round(snow.ForceX) == 0)
{
snow.ForceX = di > hpi && di < tpi ? force : -force;
}
}
snow.Update();
if(ySnow >= height)
{
snow.CordY = -sSnow;
snow.CordX = RandomRange(sSnow, width - sSnow);
}
else if(xSnow > -dsSnow && xSnow < width + dsSnow &&
ySnow > -dsSnow && ySnow < height + dsSnow)
{
ctx.save();
ctx.translate(xSnow, ySnow);
ctx.translate(sSnow, sSnow);
ctx.rotate(rSnow);
ctx.drawImage(snow.Image, -sSnow, -sSnow, dsSnow, dsSnow);
ctx.restore();
}
}
stats.end();
}, 1000 / 60);
function Snowflake(x, y, size)
{
this.Image = null;
this.Life = 0;
this.Size = size;
this.ChangeImage = function(i)
{ this.Image = i; };
this.CordX = x;
this.CordY = y;
this.ForceX = 0;
this.Gravity = RandomRange(3, 20);
this.OnFloor = false;
this.Update = function(force)
{
var life = this.Life++;
var xForce = this.ForceX;
if(xForce > 0) xForce = this.ForceX -= 0.1;
else if(xForce < 0) xForce = this.ForceX += 0.1;
this.CordX += xForce;
this.CordY += Math.sqrt(this.Gravity) / 2;
};
}
function RandomSnowflake(size)
{
// http://codepen.io/zny/pen/QwEvMR?editors=001 Modified
snow_canvas.width = snow_canvas.height = size;
//snow_ctx.clearRect(0, 0, size, size);
var spark = 50;
var randomArms = RandomRange(5, 8);
var hs = ~~(size / 2);
var r = size;
var angle = 2 * Math.PI / randomArms;
var spShort = RandomRange(0, 6),
spN = RandomRange(0, 4);
var spY = RandomRange(0, r), // y of first spark
spYY = RandomRange(0, r), // y of last spark
spH = RandomRange(0, spark), // height of sparks
spDist = spYY - spY;
if (spDist > 0) spDist /= spN;
else
{
spDist = (spY - spYY)/spN;
spY = spYY;
spYY = spY;
}
var r2 = Math.random() * r, // shorter than main
spY2 = Math.random() * r2, // y of spark
spW2 = Math.random() * spark, // width of spark
spH2 = RandomRange(-spark, spark * 2), // height of spark
spShort = RandomRange(0, 6); // 1 in 6 chance of shorts not showing
snow_ctx.translate(hs, hs);
var grad = snow_ctx.createRadialGradient(0, 0, 0, 0, 0, r);
grad.addColorStop("0","rgba(255,255,255,0.7)");
grad.addColorStop("0.4","rgba(255,255,255,0.85)");
grad.addColorStop("0.8","rgba(255,255,255,0.2)");
grad.addColorStop("1","rgba(255,255,255,0)");
// Large arms
snow_ctx.beginPath();
for (var i = 0; i < randomArms; i++)
{
snow_ctx.moveTo(0, 0);
snow_ctx.lineTo(0, r);
snow_ctx.rotate(angle);
}
snow_ctx.lineWidth = 1;
snow_ctx.strokeStyle = grad;
snow_ctx.stroke();
snow_ctx.closePath();
// Short arms
if (spShort > 1)
{
snow_ctx.beginPath();
snow_ctx.rotate(angle / 2);
for (var i = 0; i < randomArms; i++)
{
snow_ctx.moveTo(0, 0);
snow_ctx.lineTo(0, r2);
snow_ctx.rotate(angle);
}
snow_ctx.lineWidth = 1;
snow_ctx.strokeStyle = grad;
snow_ctx.stroke();
snow_ctx.closePath();
//short spark
snow_ctx.beginPath();
snow_ctx.moveTo(0, 0);
for (var i = 0; i < randomArms; i++)
{
snow_ctx.moveTo(-spW2, spY2 + spH2);
snow_ctx.lineTo(0, spY2);
snow_ctx.lineTo(spW2, spY2 + spH2);
snow_ctx.rotate(angle);
}
snow_ctx.lineWidth = 1;
snow_ctx.strokeStyle = grad;
snow_ctx.stroke();
snow_ctx.closePath();
}
var image = new Image();
image.src = snow_canvas.toDataURL("image/png");
return image;
}
function RandomRange(min, max)
{ return Math.round(Math.random() * (max - min)) + min; }
function Distance(x0, y0, x1, y1)
{
var xx = x1 - x0;
var yy = y1 - y0;
return Math.sqrt(xx * xx + yy * yy)
}
function Direction(x0, y0, x1, y1)
{
var xx = x1 - x0;
var yy = y1 - y0;
return pi + Math.atan2(yy, xx);
}
});
body
{
padding: 0px;
margin: 0px;
background-color: #0092B2;
}
#debug{ display: block; position: absolute; right: 0px; top: 0px; }
#snow-collision
{
position: fixed;
left: 0px;
top: 0px;
z-index: 0;
}
.hide{ display: none; }
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/stats.js/r11/Stats.min.js"></script>
<canvas id="snow-collision">
Your browser doesnt support canvas-html5
</canvas>
<canvas id="flake-creator" class="hide">I can't create a snowflake :(</canvas>
<div id="debug"></div>
Unfortunately, when it has more than 1000 particles it becomes laggy. How can I improve it?