Javascript 提高 Canvas 性能

标签 javascript canvas optimization

我已经创建了一个背景 Canvas ,可以绘制大约 300 个对象,现在当我移动鼠标时它会滞后很多。可能只是 Canvas 不是用来绘制 300 个对象的?

我已经做了一些关于优化的研究,比如只使用整数,这样抗锯齿就会更少。

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

初始化函数称为onresizeonload,我是否可以做任何更改来优化代码?或者我只是在挑战极限。

最佳答案

这里对 requestAnimationFrame 的工作方式有一点误解。

您不需要尝试以每秒 60 次(re:1000/60)的速度强制调用 requestAnimationFrame。这会自动发生。

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

您在这里真正做的是每隔 1000/60 调用一次超时,然后尝试调用 drawBackground。由于超时不可靠,这会导致斜坡效应并导致您观察到的滞后问题。

从您的代码中删除 setTimeout,而是简单地使用

window.requestAnimationFrame(drawBackground);

JSFiddle Demo


除了超时使用之外,在运行 requestAnimationFrame 时多次调用 drawBackground 不是一个好主意 - 特别是考虑到它处理的数据不在函数范围内,这意味着它无论如何更新时都在使用星星数组。使用一个标志来确保动画尚未开始,以防止在初始化时多次调用它。

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

关于Javascript 提高 Canvas 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49824045/

相关文章:

javascript - 如何允许用户设置下载文件的目标文件夹

html - 在 HTML Canvas 上下文的路径上查找当前点?

performance - 有没有办法判断哪些动词更有效率

c - 取消引用类型双关指针将打破严格的别名规则

javascript - 如何使用正则表达式验证多封电子邮件?

javascript - vue中的箭头函数

javascript - JsPDF和chart.js : Increase chart resolution

c - 使用指针会取消关联变量的 "register"属性吗?

javascript - 如何让已取消的警报在警报 "cancel"之后返回到相同的先前选项?

javascript - Base64 SVG 图像