简体   繁体   中英

Javascript improve canvas performance

I've created a background canvas that draw around 300 objects, Now it lags quite a bit when I move my mouse. It might just be that canvas isn't made to draw 300 objects?

I've done some research on optimizing such as only using integers so there will be less anti-aliasing.

<script>
  var stars = [];
  var starCount = 500;
  var starColors = ["#125A89", "#409897", "#042B44", "#125987"];

  //Setup canvas
  var canvas = document.getElementById("background");
  var ctx = canvas.getContext("2d");

  //Initialize all the measurements
  function initialize() {
    var backgroundWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
    var backgroundHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);

    document.getElementById("myCanvas").setAttribute('width', backgroundWidth);
    document.getElementById("myCanvas").setAttribute('height', backgroundHeight);

    //Start the background and draw it
    createStars(starCount);
    drawBackground();
  }

  //Create the star objects in a array
  function createStars(starCount) {
    stars = [];
    for (var i = 0; i < starCount; i ++) {
      var star = {
        size: getRandomInt(1, 3),
        Yspeed: getRandomInt(4, 10),
        Xpos: getRandomInt(0, canvas.width),
        Ypos: getRandomInt(0, canvas.height),
        color: starColors[getRandomInt(0, starColors.length)]
      }
      stars.push(star);
    }
  }

  //Generate random number
  function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  function drawBackground() {
    //Clear canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    //Draw background
    ctx.rect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "#000000";
    ctx.fill();

    //Draw al the stars from the array
    for (var i = 0; i < stars.length; i ++) {
      var star = stars[i];

      ctx.beginPath();
      ctx.rect(star.Xpos, star.Ypos, star.size, star.size);

      if (ctx.fillStyle != star.color) ctx.fillStyle = star.color;
      ctx.fill();

      if (star.Ypos + star.size > canvas.height) star.Ypos = -star.size;
      else star.Ypos += star.Yspeed;
    }

    //Call the next draw cycle
    setTimeout(function() {
      window.requestAnimationFrame(drawBackground);
    }, 1000/60);
  }
</script>

The initialize function is called onresize and onload , are there any changes I could make to optimize the code? Or am I just pushing the limit.

There is a slight misunderstanding here with the way that requestAnimationFrame works.

You don't need to attempt to force the call for requestAnimationFrame at 60 times per second (re: 1000/60). That happens automatically .

The window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser call a specified function to update an animation before the next repaint. The method takes a callback as an argument to be invoked before the repaint.

The number of callbacks is usually 60 times per second, but will generally match the display refresh rate in most web browsers as per W3C recommendation.
- window.requestAnimationFrame() MDN

What you are really doing here is calling the timeout every 1000/60, which then attempts to call drawBackground . Since timeouts are not reliable, this results in a ramping effect and causes the lag issues you are observing.

Remove the setTimeout from your code, and instead simply use

window.requestAnimationFrame(drawBackground);

JSFiddle Demo


In addition to the timeOut use, calling drawBackground multiple times when it is running requestAnimationFrame is not a good idea - especially given that the data it working on is not scoped to the function, meaning that it is using the stars array when it is updated anyway. Use a flag to ensure that the animation hasn't already started to prevent calling this multiple times from initialize.

var animationRunning = false;
function initialize() {
    //... existing code
    if(!animationRunning){
        drawBackground();
        animationRunning = true;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM