【问题标题】:Need help optimizing my Javascript for canvas rendering需要帮助优化我的 Javascript 以进行画布渲染
【发布时间】:2021-04-18 11:08:38
【问题描述】:

我已经为我的作品集的背景编写了随机移动线的快速脚本。它单独运行很流畅,但是当我开始使用其他 CSS 动画和其他东西时,开始时会出现丢帧(后来它运行流畅)。至少在我的电脑上,在低端电脑上挣扎。

一些优化它的技巧会很有帮助。

这是我的代码:

/*Random Line Render Script aka Mini Browser Crasher */
/*XD Can't Revise This Script. Rofl Drains Memory. May crash low-end pc :V */
var c = document.getElementById("graph");
var dimension = [document.documentElement.clientWidth, document.documentElement.clientHeight];
c.width = dimension[0];

var ctx = c.getContext("2d");
var ctx2 = c.getContext("2d");
var posx = [100, 200, 150, 100, 0];
var posy = [100, 200, 300, 100, -100];
var posx2 = [600, 400, 200, 600];
var posy2 = [500, 200, 100, 150, 500, 500];
var posx3 = [];
var posy3 = [];

/*Generate random values for array( random starting point ) */
for (var i = 0; i < 2; i++) {
  posx2.push(500 + Math.round(Math.random() * 700));
  posy2.push(Math.round(Math.random() * 900));
}
for (var i = 0; i < 5; i++) {
  posx3.push(1000 + Math.round(Math.random() * 300));
  posy3.push(0 + Math.round(Math.random() * 1000));
}
var posx_len = posx.length;
var posx2_len = posx2.length;
var posx3_len = posx3.length;
var xa, ya;
var opa = 1;
var amount = 0.01;
var sinang = 0;
var distance1 = 0;
var distance2 = 0;
document.body.addEventListener('mousemove', (function(event) {
  xa = event.clientX;
  ya = event.clientY;
}));

/*Render Lines */
function draw() {

  ctx.clearRect(0, 0, 10000, 10000);
  ctx.beginPath();
  ctx.moveTo(posx[0], posy[0]);
  for (var i = 0; i < posx_len; i++) {
    ctx.lineTo(posx[i], posy[i]);
    ctx.strokeStyle = 'rgba(255,255,255,' + opa + ')';
    ctx.stroke();
    ctx.arc(posx[i], posy[i], 5, 0, 2 * Math.PI, false);
  }

  if (opa > 1) {
    amount = -0.01 * Math.random();
  }
  if (opa < 0) {
    amount = 0.01 * Math.random();
  }
  opa = opa + amount;

  ctx.moveTo(posx2[0], posy2[0]);
  for (var i = 0; i < posx2_len; i++) {
    ctx.lineTo(posx2[i], posy2[i]);
    ctx.strokeStyle = 'rgba(255,255,255,' + opa + ')';
    ctx.stroke();
    ctx.arc(posx2[i], posy2[i], 5, 0, 2 * Math.PI, false);
  }
  ctx.moveTo(posx3[0], posy3[0]);
  for (var i = 0; i < posx3_len; i++) {
    ctx.lineTo(posx3[i], posy3[i]);
    ctx.strokeStyle = 'rgba(255,255,255,' + opa + ')';
    ctx.stroke();
    ctx.arc(posx3[i], posy3[i], 5, 0, 2 * Math.PI, false);
  }
  sinang = sinang + 0.01;

  /*Frame Render Ends here*/

  /*Calculation for next frame*/
  for (var i = 0; i < posx_len; i++) {
    posx[i] = posx[i] + (Math.cos(sinang) * i) / 2; /* Sin curve for smooth value transition. Smooth assss Butter */
    posy[i] = posy[i] + (Math.cos(sinang) * i) / 2;
    /* Can't believe Distance Formula is useful ahaha  */

    distance1 = Math.sqrt(Math.pow((posx[i] - xa), 2) + Math.pow((posy[i] - ya), 2));

    if (distance1 <= 500) {
      ctx.moveTo(posx[i], posy[i]);
      ctx.lineTo(xa, ya);
    }

    for (var j = 0; j < posx2_len; j++) {
      distance12 = Math.sqrt(Math.pow((posx[i] - posx2[j]), 2) + Math.pow((posy[i] - posy2[j]), 2));

      if (distance12 <= 500) {
        ctx.moveTo(posx[i], posy[i]);
        ctx.lineTo(posx2[j], posy2[j]);
      }
    }
    for (var j = 0; j < posx3_len; j++) {
      distance13 = Math.sqrt(Math.pow((posx[i] - posx3[j]), 2) + Math.pow((posy[i] - posy3[j]), 2));

      if (distance13 <= 500) {
        ctx.moveTo(posx[i], posy[i]);
        ctx.lineTo(posx3[j], posy3[j]);
      }
    }
  }
  posx[posx.length - 1] = posx[0];
  posy[posy.length - 1] = posy[0];

  /*Repeat Above Steps. Should have done this in Multi-dimensional array. Ugh I feel sad now*/
  for (var i = 0; i < posx2_len; i++) {
    posx2[i] = posx2[i] + (Math.sin(sinang) * i) / 2;
    posy2[i] = posy2[i] - (Math.sin(sinang) * i) / 2;

    distance2 = Math.sqrt(Math.pow((posx2[i] - xa), 2) + Math.pow((posy2[i] - ya), 2));

    if (distance2 <= 500) {
      ctx.moveTo(posx2[i], posy2[i]);
      ctx.lineTo(xa, ya);
    }

    for (var j = 0; j < posx3_len; j++) {
      distance22 = Math.sqrt(Math.pow((posx2[i] - posx3[j]), 2) + Math.pow((posy2[i] - posy3[j]), 2));

      if (distance22 <= 500) {
        ctx.moveTo(posx2[i], posy2[i]);
        ctx.lineTo(posx3[j], posy3[j]);
      }
    }
  }

  posx2[posx2.length - 1] = posx2[0];
  posy2[posy2.length - 1] = posy2[0];

  for (var i = 0; i < posx3_len; i++) {
    posx3[i] = posx3[i] - (Math.sin(sinang) * i) / 1.2;
    posy3[i] = posy3[i] - (Math.sin(sinang) * i) / 1.2;

    distance2 = Math.sqrt(Math.pow((posx3[i] - xa), 2) + Math.pow((posy3[i] - ya), 2));
    if (distance2 <= 500) {
      ctx.moveTo(posx3[i], posy3[i]);
      ctx.lineTo(xa, ya);
    }
  }
  posx3[posx3.length - 1] = posx3[0];
  posy3[posy3.length - 1] = posy3[0];

  ctx.restore();
  ctx.stroke();
  window.requestAnimationFrame(draw);
}

window.requestAnimationFrame(draw);
body {
  background: #1f1f1f;
}
<canvas height="1080px" width="1100px" id="graph">
</canvas>

【问题讨论】:

  • 这段代码徒劳地多次抚摸相同的子路径,它设置了strokeStyle而不使用它,它清除了一个疯狂的大区域,它试图恢复从未保存过的状态。目前还不清楚应该如何解决所有这些问题,因为每个代码块的意图都不是不言自明的,但乍一看我会说删除所有对 ctx.stroke() 的调用,除了最后一个,你应该赢得一些每帧毫秒数。
  • 谢谢,这真的很有帮助。这实际上是我第一次使用画布,所以我不知道我每帧只需要描边一次。我认为每次我们画一条线/多边形时都应该抚摸一下。无法挤出太多毫秒,但是的,谢谢。 :V

标签: javascript html css animation canvas


【解决方案1】:

所以,我所做的是使用方形对撞机而不是圆形(距离公式),它现在具有更快的运行时间。 (不多,但仍然)

<html>
<head>
</head>
<style>
    body{
        background: #1f1f1f;
    }
    canvas{

    }
</style>
<body >
    <canvas height="1080px" width="1100px" id="graph">
        
    </canvas>
</body>

<script>
/*Random Line Render Script aka Mini Browser Crasher */
/*XD Can't Revise This Script. Rofl Drains Memory. May crash low-end pc :V */
var c = document.getElementById("graph");
var dimension = [document.documentElement.clientWidth, document.documentElement.clientHeight];
c.width = dimension[0];

var ctx = c.getContext("2d");
 
var posx = [100,200,150,100,0];
var posy = [100,200,300,100,-100];
var posx2 = [600,400,200,600];
var posy2 = [500,200,100,150,500,500];
var posx3 = [];
var posy3 = [];

/*Generate random values for array( random starting point ) */
for(var i=0; i<2;i++){
    posx2.push(500+Math.round(Math.random()*700));
    posy2.push(Math.round(Math.random()*900));
}
for(var i=0; i<5;i++){
    posx3.push(1000+Math.round(Math.random()*300));
    posy3.push(0+Math.round(Math.random()*1000));
}
var posx_len = posx.length;
var posx2_len = posx2.length;
var posx3_len = posx3.length;
var xa,ya;
var opa =1;
var amount = 0.01;
var sinang = 0;
var distance1 = 0;
var distance2 = 0;
var t1, t2;
document.body.addEventListener('mousemove', (function (event) {
    xa = event.clientX;
    ya = event.clientY;
    

}));

/*Render Lines */
function draw(){
    
    t1 =performance.now();
    ctx.clearRect(0, 0, 1920,1080);
    ctx.beginPath();
    ctx.moveTo(posx[0], posy[0]);
    for(var i= 0; i<posx_len;i++){
        ctx.lineTo(posx[i], posy[i]);
        
        ctx.arc(posx[i],posy[i], 5, 0, 2 * Math.PI, false);

    }
    
    
    if(opa>1){
    amount = -0.01*Math.random();
    }
    if(opa<0){
        amount =0.01*Math.random();
    }
    opa =opa +amount;
    
    ctx.moveTo(posx2[0], posy2[0]);
    for(var i = 0; i<posx2_len;i++){
        ctx.lineTo(posx2[i], posy2[i]);
        
        ctx.arc(posx2[i],posy2[i], 5, 0, 2 * Math.PI, false);
    }
    ctx.moveTo(posx3[0], posy3[0]);
    for(var i = 0; i<posx3_len;i++){
        ctx.lineTo(posx3[i], posy3[i]);
        
        ctx.arc(posx3[i],posy3[i], 5, 0, 2 * Math.PI, false);
    }
    sinang = sinang+0.01;
    
    /*Frame Render Ends here*/

    /*Calculation for next frame*/
    for(var i = 0;i<posx_len;i++){
        posx[i] = posx[i]+ (Math.cos(sinang)*i)/2;/* Sin curve for smooth value transition. Smooth assss Butter */
        posy[i] = posy[i]+ (Math.cos(sinang)*i)/2;
        /* Can't believe Distance Formula is useful ahaha  */
    
        

    
        if(Math.abs(posx[i]-xa)<500 && Math.abs(posy[i]-ya)<500){
            ctx.moveTo(posx[i],posy[i]);
            ctx.lineTo(xa, ya);
        }
        
        for(var j = 0;j<posx2_len;j++){
            
            
            if(Math.abs(posx[i]-posx2[j])<500 && Math.abs(posy[i]-posy2[j])<500){
                ctx.moveTo(posx[i],posy[i]);
                ctx.lineTo(posx2[j], posy2[j]);
            }
        }
        for(var j = 0;j<posx3_len;j++){
            
            
            if(Math.abs(posx[i]-posx3[j])<500 && Math.abs(posy[i]-posy3[j])<500){
                ctx.moveTo(posx[i],posy[i]);
                ctx.lineTo(posx3[j], posy3[j]);
            }
        }

    }
    posx[posx.length-1]=posx[0];
    posy[posy.length-1] = posy[0];

    /*Repeat Above Steps. Should have done this in Multi-dimensional array. Ugh I feel sad now*/
    for(var i = 0;i<posx2_len;i++){
    
        posx2[i] = posx2[i]+ (Math.sin(sinang)*i)/2;
        posy2[i] = posy2[i]-(Math.sin(sinang)*i)/2;
        
        
        
        if(Math.abs(posx2[i]-xa)<500 && Math.abs(posy2[i]-ya)<500){
            ctx.moveTo(posx2[i],posy2[i]);
            ctx.lineTo(xa, ya);
        }
    
        
        for(var j = 0;j<posx3_len;j++){
            
            
            if(Math.abs(posx2[i]-posx3[j])<500 && Math.abs(posy2[i]-posy3[j])<500){
                ctx.moveTo(posx2[i],posy2[i]);
                ctx.lineTo(posx3[j], posy3[j]);
            }
        }
        
        
    }

    posx2[posx2.length-1]=posx2[0];
    posy2[posy2.length-1] = posy2[0];
    
    for(var i = 0;i<posx3_len;i++){
    
        posx3[i] = posx3[i]- (Math.sin(sinang)*i)/1.2;
        posy3[i] = posy3[i]-(Math.sin(sinang)*i)/1.2;
        
        
        if(Math.abs(posx3[i]-xa)<500 && Math.abs(posy3[i]-ya)<500){
            ctx.moveTo(posx3[i],posy3[i]);
            ctx.lineTo(xa, ya);
        }
        

        
        
        
    }
    posx3[posx3.length-1]=posx3[0];
    posy3[posy3.length-1] = posy3[0];
    

    ctx.restore();
    ctx.strokeStyle = 'rgba(255,255,255,'+opa+')';
    ctx.stroke();
    window.requestAnimationFrame(draw);

    t2=performance.now();
    console.log(t2-t1);
}

window.requestAnimationFrame(draw);
</script>

</html>

【讨论】:

  • 将计算结果存储在临时变量中(我知道 C++ 通常足够聪明,可以捕捉到这些错误,但是 javascript...我不相信它)。多次计算(Math.cos(sinang)*i)/2 并不聪明。多次计算(Math.sin(sinang)*i)/1.2 也不明智。或posx3.length-1。开始分解你的计算,这样你只做一次,然后多次重复使用答案。 - 尽量让你的 cmets 保持专业,减少“我现在很难过”。 - 缩进做得很好。下次拆分 HTML 和 JS,这样代码对于两种语言都有很好的颜色。
猜你喜欢
  • 2013-12-26
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多