Skip to main content
deleted 24 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

JavaScript "snow" codeanimation

The thing isUnfortunately, when it has more than 1000 particles it becomes laggy. All the code is written in JavaScript. How can I improve it? Preview:  

http://codepen.io/LukasHaring/pen/azNYZKPreview

JavaScript "snow" code

The thing is, when it has more than 1000 particles it becomes laggy. All the code is written in JavaScript. How can I improve it? Preview: http://codepen.io/LukasHaring/pen/azNYZK

JavaScript "snow" animation

Unfortunately, when it has more than 1000 particles it becomes laggy. How can I improve it? 

Preview

Reconstructed demo (CodePen has been modified and no longer works)
Source Link
200_success
  • 145.7k
  • 22
  • 191
  • 481
$(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);
  }
});

$(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>

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

$(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>

edited tags; edited tags
Link
200_success
  • 145.7k
  • 22
  • 191
  • 481
added 51 characters in body
Source Link
Loading
Post Reopened by TheCoffeeCup, Mathieu Guindon, syb0rg, Jamal
added 3 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238
Loading
added code and improved grammar
Source Link
TheCoffeeCup
  • 9.5k
  • 4
  • 38
  • 96
Loading
Post Closed as "Not suitable for this site" by Jamal
Source Link
Loading