Improving performance of particles in canvas











up vote
4
down vote

favorite
1












I've been trying to recreate this Project in canvas and Javascript. I wasn't able to decipher the original code so I did it from scratch. The difference is that my projects starts to lag at about 2500 particles while the project above works with 30 000.



I'll paste my entire code below but these are the relevant parts:



var particleContainer = 
var distance = 10


for(let i = 0; i< square.height/distance; i++){
for(let j = 0; j< square.height/distance; j++){
particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
}
}

if( c < 90 ){
i.xVelocity = a/c * -20
i.yVelocity = b/c * -20
}else if(90 < c && c < 95){
i.xVelocity = a/c * -1
i.yVelocity = b/c * -1
}else if(c2 !== 0){
i.xVelocity =( a2/c2 )
i.yVelocity = (b2/c2 )
}



  • (c -> distance between mouse and particle)


I'm creating a new Particle every 'distance' pixels of my square and pushing all of them into an array. when My mouse is to close to one of them the particle will start moving away from the mouse until it is 90-95px away from the Mouse.



30 000 pixels seems to work in a similar fashion judging from this line



  for ( i = 0; i < NUM_PARTICLES; i++ ) {

p = Object.create( particle );
p.x = p.ox = MARGIN + SPACING * ( i % COLS );
p.y = p.oy = MARGIN + SPACING * Math.floor( i / COLS );

list[i] = p;
}


but that project doesn't run into the same case of performance Issues as I.



my full code for reference, (html is just a canvas):



var canvas = document.querySelector("canvas")
var c = canvas.getContext('2d')




function getMousePos(canvas, evt) {
// var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX,
y: evt.clientY
};
}

document.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
mouse.x= mousePos.x;
mouse.y= mousePos.y;
}, false);

var mouse = {
x:0,
y:0
}

function Particle(x,y){
this.x = x;
this.y = y;
this.xFixed = x;
this.yFixed = y;
this.radius = 1
this.xVelocity = 0
this.yVelocity = 0
this.color = 'white'
}

Particle.prototype.draw = function(){
c.save()
c.beginPath()
c.arc(this.x, this.y, this.radius,0,Math.PI*2,false)
c.fillStyle = this.color
c.fill()
}

Particle.prototype.update = function(){
this.draw()
this.x += this.xVelocity
this.y += this.yVelocity
}

var square = {
x: 500,
y: 150,
height: 500,
width: 500,
color: 'white'
}

var particleContainer =
var distance = 10


for(let i = 0; i< square.height/distance; i++){
for(let j = 0; j< square.height/distance; j++){
particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
}

}





function animate(){
requestAnimationFrame(animate);
c.clearRect(0,0,window.innerWidth,window.innerHeight)

canvas.width = window.innerWidth
canvas.height = window.innerHeight

for(i of particleContainer){
let a = mouse.x - i.x
let b = mouse.y - i.y
let c = Math.sqrt(Math.pow(b,2) + Math.pow(a,2))

let a2 = i.xFixed - i.x
let b2 = i.yFixed - i.y
let c2 = Math.sqrt(Math.pow(b2,2) + Math.pow(a2,2))

if( c < 90 ){
i.xVelocity = a/c * -20
i.yVelocity = b/c * -20
}else if(90 < c && c < 95){
i.xVelocity = a/c * -1
i.yVelocity = b/c * -1
}else if(c2 !== 0){
i.xVelocity =( a2/c2 )
i.yVelocity = (b2/c2 )
}


}

for(i of particleContainer){
i.update()
}
}

animate()









share|improve this question




























    up vote
    4
    down vote

    favorite
    1












    I've been trying to recreate this Project in canvas and Javascript. I wasn't able to decipher the original code so I did it from scratch. The difference is that my projects starts to lag at about 2500 particles while the project above works with 30 000.



    I'll paste my entire code below but these are the relevant parts:



    var particleContainer = 
    var distance = 10


    for(let i = 0; i< square.height/distance; i++){
    for(let j = 0; j< square.height/distance; j++){
    particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
    }
    }

    if( c < 90 ){
    i.xVelocity = a/c * -20
    i.yVelocity = b/c * -20
    }else if(90 < c && c < 95){
    i.xVelocity = a/c * -1
    i.yVelocity = b/c * -1
    }else if(c2 !== 0){
    i.xVelocity =( a2/c2 )
    i.yVelocity = (b2/c2 )
    }



    • (c -> distance between mouse and particle)


    I'm creating a new Particle every 'distance' pixels of my square and pushing all of them into an array. when My mouse is to close to one of them the particle will start moving away from the mouse until it is 90-95px away from the Mouse.



    30 000 pixels seems to work in a similar fashion judging from this line



      for ( i = 0; i < NUM_PARTICLES; i++ ) {

    p = Object.create( particle );
    p.x = p.ox = MARGIN + SPACING * ( i % COLS );
    p.y = p.oy = MARGIN + SPACING * Math.floor( i / COLS );

    list[i] = p;
    }


    but that project doesn't run into the same case of performance Issues as I.



    my full code for reference, (html is just a canvas):



    var canvas = document.querySelector("canvas")
    var c = canvas.getContext('2d')




    function getMousePos(canvas, evt) {
    // var rect = canvas.getBoundingClientRect();
    return {
    x: evt.clientX,
    y: evt.clientY
    };
    }

    document.addEventListener('mousemove', function(evt) {
    var mousePos = getMousePos(canvas, evt);
    mouse.x= mousePos.x;
    mouse.y= mousePos.y;
    }, false);

    var mouse = {
    x:0,
    y:0
    }

    function Particle(x,y){
    this.x = x;
    this.y = y;
    this.xFixed = x;
    this.yFixed = y;
    this.radius = 1
    this.xVelocity = 0
    this.yVelocity = 0
    this.color = 'white'
    }

    Particle.prototype.draw = function(){
    c.save()
    c.beginPath()
    c.arc(this.x, this.y, this.radius,0,Math.PI*2,false)
    c.fillStyle = this.color
    c.fill()
    }

    Particle.prototype.update = function(){
    this.draw()
    this.x += this.xVelocity
    this.y += this.yVelocity
    }

    var square = {
    x: 500,
    y: 150,
    height: 500,
    width: 500,
    color: 'white'
    }

    var particleContainer =
    var distance = 10


    for(let i = 0; i< square.height/distance; i++){
    for(let j = 0; j< square.height/distance; j++){
    particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
    }

    }





    function animate(){
    requestAnimationFrame(animate);
    c.clearRect(0,0,window.innerWidth,window.innerHeight)

    canvas.width = window.innerWidth
    canvas.height = window.innerHeight

    for(i of particleContainer){
    let a = mouse.x - i.x
    let b = mouse.y - i.y
    let c = Math.sqrt(Math.pow(b,2) + Math.pow(a,2))

    let a2 = i.xFixed - i.x
    let b2 = i.yFixed - i.y
    let c2 = Math.sqrt(Math.pow(b2,2) + Math.pow(a2,2))

    if( c < 90 ){
    i.xVelocity = a/c * -20
    i.yVelocity = b/c * -20
    }else if(90 < c && c < 95){
    i.xVelocity = a/c * -1
    i.yVelocity = b/c * -1
    }else if(c2 !== 0){
    i.xVelocity =( a2/c2 )
    i.yVelocity = (b2/c2 )
    }


    }

    for(i of particleContainer){
    i.update()
    }
    }

    animate()









    share|improve this question


























      up vote
      4
      down vote

      favorite
      1









      up vote
      4
      down vote

      favorite
      1






      1





      I've been trying to recreate this Project in canvas and Javascript. I wasn't able to decipher the original code so I did it from scratch. The difference is that my projects starts to lag at about 2500 particles while the project above works with 30 000.



      I'll paste my entire code below but these are the relevant parts:



      var particleContainer = 
      var distance = 10


      for(let i = 0; i< square.height/distance; i++){
      for(let j = 0; j< square.height/distance; j++){
      particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
      }
      }

      if( c < 90 ){
      i.xVelocity = a/c * -20
      i.yVelocity = b/c * -20
      }else if(90 < c && c < 95){
      i.xVelocity = a/c * -1
      i.yVelocity = b/c * -1
      }else if(c2 !== 0){
      i.xVelocity =( a2/c2 )
      i.yVelocity = (b2/c2 )
      }



      • (c -> distance between mouse and particle)


      I'm creating a new Particle every 'distance' pixels of my square and pushing all of them into an array. when My mouse is to close to one of them the particle will start moving away from the mouse until it is 90-95px away from the Mouse.



      30 000 pixels seems to work in a similar fashion judging from this line



        for ( i = 0; i < NUM_PARTICLES; i++ ) {

      p = Object.create( particle );
      p.x = p.ox = MARGIN + SPACING * ( i % COLS );
      p.y = p.oy = MARGIN + SPACING * Math.floor( i / COLS );

      list[i] = p;
      }


      but that project doesn't run into the same case of performance Issues as I.



      my full code for reference, (html is just a canvas):



      var canvas = document.querySelector("canvas")
      var c = canvas.getContext('2d')




      function getMousePos(canvas, evt) {
      // var rect = canvas.getBoundingClientRect();
      return {
      x: evt.clientX,
      y: evt.clientY
      };
      }

      document.addEventListener('mousemove', function(evt) {
      var mousePos = getMousePos(canvas, evt);
      mouse.x= mousePos.x;
      mouse.y= mousePos.y;
      }, false);

      var mouse = {
      x:0,
      y:0
      }

      function Particle(x,y){
      this.x = x;
      this.y = y;
      this.xFixed = x;
      this.yFixed = y;
      this.radius = 1
      this.xVelocity = 0
      this.yVelocity = 0
      this.color = 'white'
      }

      Particle.prototype.draw = function(){
      c.save()
      c.beginPath()
      c.arc(this.x, this.y, this.radius,0,Math.PI*2,false)
      c.fillStyle = this.color
      c.fill()
      }

      Particle.prototype.update = function(){
      this.draw()
      this.x += this.xVelocity
      this.y += this.yVelocity
      }

      var square = {
      x: 500,
      y: 150,
      height: 500,
      width: 500,
      color: 'white'
      }

      var particleContainer =
      var distance = 10


      for(let i = 0; i< square.height/distance; i++){
      for(let j = 0; j< square.height/distance; j++){
      particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
      }

      }





      function animate(){
      requestAnimationFrame(animate);
      c.clearRect(0,0,window.innerWidth,window.innerHeight)

      canvas.width = window.innerWidth
      canvas.height = window.innerHeight

      for(i of particleContainer){
      let a = mouse.x - i.x
      let b = mouse.y - i.y
      let c = Math.sqrt(Math.pow(b,2) + Math.pow(a,2))

      let a2 = i.xFixed - i.x
      let b2 = i.yFixed - i.y
      let c2 = Math.sqrt(Math.pow(b2,2) + Math.pow(a2,2))

      if( c < 90 ){
      i.xVelocity = a/c * -20
      i.yVelocity = b/c * -20
      }else if(90 < c && c < 95){
      i.xVelocity = a/c * -1
      i.yVelocity = b/c * -1
      }else if(c2 !== 0){
      i.xVelocity =( a2/c2 )
      i.yVelocity = (b2/c2 )
      }


      }

      for(i of particleContainer){
      i.update()
      }
      }

      animate()









      share|improve this question















      I've been trying to recreate this Project in canvas and Javascript. I wasn't able to decipher the original code so I did it from scratch. The difference is that my projects starts to lag at about 2500 particles while the project above works with 30 000.



      I'll paste my entire code below but these are the relevant parts:



      var particleContainer = 
      var distance = 10


      for(let i = 0; i< square.height/distance; i++){
      for(let j = 0; j< square.height/distance; j++){
      particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
      }
      }

      if( c < 90 ){
      i.xVelocity = a/c * -20
      i.yVelocity = b/c * -20
      }else if(90 < c && c < 95){
      i.xVelocity = a/c * -1
      i.yVelocity = b/c * -1
      }else if(c2 !== 0){
      i.xVelocity =( a2/c2 )
      i.yVelocity = (b2/c2 )
      }



      • (c -> distance between mouse and particle)


      I'm creating a new Particle every 'distance' pixels of my square and pushing all of them into an array. when My mouse is to close to one of them the particle will start moving away from the mouse until it is 90-95px away from the Mouse.



      30 000 pixels seems to work in a similar fashion judging from this line



        for ( i = 0; i < NUM_PARTICLES; i++ ) {

      p = Object.create( particle );
      p.x = p.ox = MARGIN + SPACING * ( i % COLS );
      p.y = p.oy = MARGIN + SPACING * Math.floor( i / COLS );

      list[i] = p;
      }


      but that project doesn't run into the same case of performance Issues as I.



      my full code for reference, (html is just a canvas):



      var canvas = document.querySelector("canvas")
      var c = canvas.getContext('2d')




      function getMousePos(canvas, evt) {
      // var rect = canvas.getBoundingClientRect();
      return {
      x: evt.clientX,
      y: evt.clientY
      };
      }

      document.addEventListener('mousemove', function(evt) {
      var mousePos = getMousePos(canvas, evt);
      mouse.x= mousePos.x;
      mouse.y= mousePos.y;
      }, false);

      var mouse = {
      x:0,
      y:0
      }

      function Particle(x,y){
      this.x = x;
      this.y = y;
      this.xFixed = x;
      this.yFixed = y;
      this.radius = 1
      this.xVelocity = 0
      this.yVelocity = 0
      this.color = 'white'
      }

      Particle.prototype.draw = function(){
      c.save()
      c.beginPath()
      c.arc(this.x, this.y, this.radius,0,Math.PI*2,false)
      c.fillStyle = this.color
      c.fill()
      }

      Particle.prototype.update = function(){
      this.draw()
      this.x += this.xVelocity
      this.y += this.yVelocity
      }

      var square = {
      x: 500,
      y: 150,
      height: 500,
      width: 500,
      color: 'white'
      }

      var particleContainer =
      var distance = 10


      for(let i = 0; i< square.height/distance; i++){
      for(let j = 0; j< square.height/distance; j++){
      particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
      }

      }





      function animate(){
      requestAnimationFrame(animate);
      c.clearRect(0,0,window.innerWidth,window.innerHeight)

      canvas.width = window.innerWidth
      canvas.height = window.innerHeight

      for(i of particleContainer){
      let a = mouse.x - i.x
      let b = mouse.y - i.y
      let c = Math.sqrt(Math.pow(b,2) + Math.pow(a,2))

      let a2 = i.xFixed - i.x
      let b2 = i.yFixed - i.y
      let c2 = Math.sqrt(Math.pow(b2,2) + Math.pow(a2,2))

      if( c < 90 ){
      i.xVelocity = a/c * -20
      i.yVelocity = b/c * -20
      }else if(90 < c && c < 95){
      i.xVelocity = a/c * -1
      i.yVelocity = b/c * -1
      }else if(c2 !== 0){
      i.xVelocity =( a2/c2 )
      i.yVelocity = (b2/c2 )
      }


      }

      for(i of particleContainer){
      i.update()
      }
      }

      animate()






      javascript canvas html5-canvas






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 24 at 7:44









      marc_s

      569k12811001250




      569k12811001250










      asked Nov 22 at 8:56









      cubefox

      918




      918
























          2 Answers
          2






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          To get better rendering you need to add render objects to the same path. Once the path is created then you can draw them in one call to ctx.fill



          Try to limit accessing innerWidth and innerHeight as they are very slow DOM objects that may cause reflows just by accessing them.



          Further improvements can be made by using object pools and preallocation but that is beyond the scope of a single answer.



          Make the following changes to your animate function.



          var W = 1, H = 1;
          function animate() {
          requestAnimationFrame(animate);
          c.clearRect(0 ,0, W, H)
          if (H !== innerHeight || W !== innerWidth) {
          W = canvas.width = innerWidth;
          H = canvas.height = innerHeight;
          }
          c.beginPath(); // start a new path
          c.fillStyle = "white";
          for (i of particleContainer) { // update and draw all particles in one pass
          const a = mouse.x - i.x, b = mouse.y - i.y
          const c = (b * b + a * a) ** 0.5;
          const a2 = i.xFixed - i.x, b2 = i.yFixed - i.y
          const c2 = (b2 * b2 + a2 * a2) ** 0.5;
          if( c < 90 ){
          i.x += a/c * -20
          i.y += b/c * -20
          }else if(90 < c && c < 95){
          i.x += a/c * -1
          i.y += b/c * -1
          }else if(c2 !== 0){
          i.x +=( a2/c2 )
          i.y += (b2/c2 )
          }
          c.rect(i.x, i.y, 1,1);
          }
          c.fill(); // path complete render it.
          //for(i of particleContainer){ // no longer needed
          // i.update()
          //}
          }





          share|improve this answer




























            up vote
            1
            down vote













            Learn to use the Performance tab in dev tools and you can see which functions are taking the most time. In this case I think you’ll see that it’s ctx.fill. The example you posted is writing pixels into an ImageData buffer which will be much faster than drawing and filling arcs. There are a lot of other small optimisations in the example but that’s going to be the most important one, drawing is usually much slower than updating.






            share|improve this answer





















              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427122%2fimproving-performance-of-particles-in-canvas%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              1
              down vote



              accepted










              To get better rendering you need to add render objects to the same path. Once the path is created then you can draw them in one call to ctx.fill



              Try to limit accessing innerWidth and innerHeight as they are very slow DOM objects that may cause reflows just by accessing them.



              Further improvements can be made by using object pools and preallocation but that is beyond the scope of a single answer.



              Make the following changes to your animate function.



              var W = 1, H = 1;
              function animate() {
              requestAnimationFrame(animate);
              c.clearRect(0 ,0, W, H)
              if (H !== innerHeight || W !== innerWidth) {
              W = canvas.width = innerWidth;
              H = canvas.height = innerHeight;
              }
              c.beginPath(); // start a new path
              c.fillStyle = "white";
              for (i of particleContainer) { // update and draw all particles in one pass
              const a = mouse.x - i.x, b = mouse.y - i.y
              const c = (b * b + a * a) ** 0.5;
              const a2 = i.xFixed - i.x, b2 = i.yFixed - i.y
              const c2 = (b2 * b2 + a2 * a2) ** 0.5;
              if( c < 90 ){
              i.x += a/c * -20
              i.y += b/c * -20
              }else if(90 < c && c < 95){
              i.x += a/c * -1
              i.y += b/c * -1
              }else if(c2 !== 0){
              i.x +=( a2/c2 )
              i.y += (b2/c2 )
              }
              c.rect(i.x, i.y, 1,1);
              }
              c.fill(); // path complete render it.
              //for(i of particleContainer){ // no longer needed
              // i.update()
              //}
              }





              share|improve this answer

























                up vote
                1
                down vote



                accepted










                To get better rendering you need to add render objects to the same path. Once the path is created then you can draw them in one call to ctx.fill



                Try to limit accessing innerWidth and innerHeight as they are very slow DOM objects that may cause reflows just by accessing them.



                Further improvements can be made by using object pools and preallocation but that is beyond the scope of a single answer.



                Make the following changes to your animate function.



                var W = 1, H = 1;
                function animate() {
                requestAnimationFrame(animate);
                c.clearRect(0 ,0, W, H)
                if (H !== innerHeight || W !== innerWidth) {
                W = canvas.width = innerWidth;
                H = canvas.height = innerHeight;
                }
                c.beginPath(); // start a new path
                c.fillStyle = "white";
                for (i of particleContainer) { // update and draw all particles in one pass
                const a = mouse.x - i.x, b = mouse.y - i.y
                const c = (b * b + a * a) ** 0.5;
                const a2 = i.xFixed - i.x, b2 = i.yFixed - i.y
                const c2 = (b2 * b2 + a2 * a2) ** 0.5;
                if( c < 90 ){
                i.x += a/c * -20
                i.y += b/c * -20
                }else if(90 < c && c < 95){
                i.x += a/c * -1
                i.y += b/c * -1
                }else if(c2 !== 0){
                i.x +=( a2/c2 )
                i.y += (b2/c2 )
                }
                c.rect(i.x, i.y, 1,1);
                }
                c.fill(); // path complete render it.
                //for(i of particleContainer){ // no longer needed
                // i.update()
                //}
                }





                share|improve this answer























                  up vote
                  1
                  down vote



                  accepted







                  up vote
                  1
                  down vote



                  accepted






                  To get better rendering you need to add render objects to the same path. Once the path is created then you can draw them in one call to ctx.fill



                  Try to limit accessing innerWidth and innerHeight as they are very slow DOM objects that may cause reflows just by accessing them.



                  Further improvements can be made by using object pools and preallocation but that is beyond the scope of a single answer.



                  Make the following changes to your animate function.



                  var W = 1, H = 1;
                  function animate() {
                  requestAnimationFrame(animate);
                  c.clearRect(0 ,0, W, H)
                  if (H !== innerHeight || W !== innerWidth) {
                  W = canvas.width = innerWidth;
                  H = canvas.height = innerHeight;
                  }
                  c.beginPath(); // start a new path
                  c.fillStyle = "white";
                  for (i of particleContainer) { // update and draw all particles in one pass
                  const a = mouse.x - i.x, b = mouse.y - i.y
                  const c = (b * b + a * a) ** 0.5;
                  const a2 = i.xFixed - i.x, b2 = i.yFixed - i.y
                  const c2 = (b2 * b2 + a2 * a2) ** 0.5;
                  if( c < 90 ){
                  i.x += a/c * -20
                  i.y += b/c * -20
                  }else if(90 < c && c < 95){
                  i.x += a/c * -1
                  i.y += b/c * -1
                  }else if(c2 !== 0){
                  i.x +=( a2/c2 )
                  i.y += (b2/c2 )
                  }
                  c.rect(i.x, i.y, 1,1);
                  }
                  c.fill(); // path complete render it.
                  //for(i of particleContainer){ // no longer needed
                  // i.update()
                  //}
                  }





                  share|improve this answer












                  To get better rendering you need to add render objects to the same path. Once the path is created then you can draw them in one call to ctx.fill



                  Try to limit accessing innerWidth and innerHeight as they are very slow DOM objects that may cause reflows just by accessing them.



                  Further improvements can be made by using object pools and preallocation but that is beyond the scope of a single answer.



                  Make the following changes to your animate function.



                  var W = 1, H = 1;
                  function animate() {
                  requestAnimationFrame(animate);
                  c.clearRect(0 ,0, W, H)
                  if (H !== innerHeight || W !== innerWidth) {
                  W = canvas.width = innerWidth;
                  H = canvas.height = innerHeight;
                  }
                  c.beginPath(); // start a new path
                  c.fillStyle = "white";
                  for (i of particleContainer) { // update and draw all particles in one pass
                  const a = mouse.x - i.x, b = mouse.y - i.y
                  const c = (b * b + a * a) ** 0.5;
                  const a2 = i.xFixed - i.x, b2 = i.yFixed - i.y
                  const c2 = (b2 * b2 + a2 * a2) ** 0.5;
                  if( c < 90 ){
                  i.x += a/c * -20
                  i.y += b/c * -20
                  }else if(90 < c && c < 95){
                  i.x += a/c * -1
                  i.y += b/c * -1
                  }else if(c2 !== 0){
                  i.x +=( a2/c2 )
                  i.y += (b2/c2 )
                  }
                  c.rect(i.x, i.y, 1,1);
                  }
                  c.fill(); // path complete render it.
                  //for(i of particleContainer){ // no longer needed
                  // i.update()
                  //}
                  }






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 22 at 11:20









                  Blindman67

                  26.2k52659




                  26.2k52659
























                      up vote
                      1
                      down vote













                      Learn to use the Performance tab in dev tools and you can see which functions are taking the most time. In this case I think you’ll see that it’s ctx.fill. The example you posted is writing pixels into an ImageData buffer which will be much faster than drawing and filling arcs. There are a lot of other small optimisations in the example but that’s going to be the most important one, drawing is usually much slower than updating.






                      share|improve this answer

























                        up vote
                        1
                        down vote













                        Learn to use the Performance tab in dev tools and you can see which functions are taking the most time. In this case I think you’ll see that it’s ctx.fill. The example you posted is writing pixels into an ImageData buffer which will be much faster than drawing and filling arcs. There are a lot of other small optimisations in the example but that’s going to be the most important one, drawing is usually much slower than updating.






                        share|improve this answer























                          up vote
                          1
                          down vote










                          up vote
                          1
                          down vote









                          Learn to use the Performance tab in dev tools and you can see which functions are taking the most time. In this case I think you’ll see that it’s ctx.fill. The example you posted is writing pixels into an ImageData buffer which will be much faster than drawing and filling arcs. There are a lot of other small optimisations in the example but that’s going to be the most important one, drawing is usually much slower than updating.






                          share|improve this answer












                          Learn to use the Performance tab in dev tools and you can see which functions are taking the most time. In this case I think you’ll see that it’s ctx.fill. The example you posted is writing pixels into an ImageData buffer which will be much faster than drawing and filling arcs. There are a lot of other small optimisations in the example but that’s going to be the most important one, drawing is usually much slower than updating.







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 22 at 9:43









                          Ben West

                          2,6511814




                          2,6511814






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.





                              Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                              Please pay close attention to the following guidance:


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427122%2fimproving-performance-of-particles-in-canvas%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Berounka

                              Sphinx de Gizeh

                              Different font size/position of beamer's navigation symbols template's content depending on regular/plain...