【问题标题】:Delay lineTo in for loop在for循环中延迟lineTo
【发布时间】:2015-05-07 04:17:13
【问题描述】:

我有一个点形状的 div (#option1),它使用数组 Option1[] 对图形进行动画处理,其中包括了几个“点”的所有高度。我正在使用 for 循环在两个点之间创建空间 (left: '+=5px') 并从数组中获取下一个点的高度,如下所示:

for (var i = 0; i < Option1.length; ++i) {
  $('#option1').animate({left: '+=5px',top: Option1[i]}, 200);
}

如您所见,div 需要 200 毫秒才能移动到下一个坐标。这一切都很好,但它只是一个移动的点。我实际上想让它看起来像画一条线,所以我尝试使用 canvaslineTo 方法,如下所示:

var xaxis=5;
var a = document.getElementById("myCanvas1");
var atx = a.getContext("2d");
atx.beginPath();
atx.moveTo(5, 900);

for (var i = 0; i < Option1.length; ++i) {
  xaxis += 5;

  $('#option1').animate({left: '+=5px',top: Option1[i]}, 200);

  atx.lineTo(xaxis, Option1[i]);
  atx.stroke();
}

如您所见,这条线从坐标 5,900 开始,然后向右移动 5px 并移动到 Option1[] 数组的下一个值的高度。 线路正确输出。问题是总线立即显示,然后点开始在已经绘制的线上移动。为了使线段仅在点超过新坐标后出现,我尝试了 setTimeout 函数,将超时设置为 200 毫秒,就像动画时间一样:

$(document).ready(function() {
  var Option1 = [100, 150, 150, 130, 50, 100, 75, 125, 50, 100];

  var xaxis = 5;
  var a = document.getElementById("myCanvas1");
  var atx = a.getContext("2d");
  atx.beginPath();
  atx.moveTo(5, 400);
  atx.strokeStyle="green";

  for (var i = 0; i < Option1.length; ++i) {
    xaxis += 5;

    $('#option1').animate({
      left: '+=5px',
      top: Option1[i]
    }, 400);

    setTimeout(drawLines(), 400);

    function drawLines() {
      atx.lineTo(xaxis, Option1[i]);
      atx.stroke();
    };
  };
});
html,
body {
  width: 100%;
  height: 100%;
  background-color: black;
}

#maindiv {
  position: absolute;
  top: 5px;
  left: 5px;
  z-index: 5;
  cursor: pointer;
  Width: 500px;
  Height: 400px;
  background-color: black;
  border-radius: 1%;
  border-width: 0px;
  border-color: blue;
  border-style: solid;
  font-family: Verdana, Arial, Sans-Serif;
  color: white;
  box-shadow: 0 0 20px white;
}

canvas {
  position: absolute;
  z-index: 5;
  cursor: pointer;
  Width: 100%;
  Height: 100%;
  background-color: none;
  border-radius: 1%;
  border-width: 1px;
  border-color: blue;
  border-style: solid;
  font-family: Verdana, Arial, Sans-Serif;
  color: white;
  box-shadow: 0 0 20px white;
}

#option1 {
  position: absolute;
  top: 390px;
  left: 5px;
  z-index: 10;
  Width: 5px;
  Height: 5px;
  background-color: green;
  border-radius: 50%;
  border-width: 0px;
  border-color: blue;
  border-style: solid;
  font-family: Verdana, Arial, Sans-Serif;
  color: white;
  box-shadow: 0 0 20px white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<html>
  <body>
    <div id="maindiv">
      <canvas id="myCanvas1" width="500" height="400"></canvas>
      <div id="option1"></div>
    </div>
  </body>
</html>

(最后一个隐藏的 sn-p 包含 html 和 css 顺便说一句,所以它正在工作)。没有成功。总线瞬间就在那里。我还尝试使用 stackoverflow 上的其他帖子以其他方式编写 setTimeout,但总行总是会立即显示。

任何帮助让我的线被实时绘制,将不胜感激!也欢迎使用完全不同的方法/功能的解决方案。 谢谢!

【问题讨论】:

  • 我认为setInterval 更适合您的情况。如果将 for 循环替换为 setInterval。您的线路不会立即显示。
  • 我看到如何在不使用forloop 的情况下为下一个lineTo 输入下一个高度坐标的唯一方法是使用实​​数作为数组中每个值的数组位置(@987654337 @、Option1[1]Option1[2] 等)而不是使用 Option1[i]。这样做的问题是每次我运行程序时数组都会改变。数组长度可以从 1 变为 200。
  • 这只是一个中间步骤,还是线条+点是唯一被绘制到画布上的东西?
  • 线条将是画布上唯一绘制的东西。

标签: javascript jquery for-loop canvas delay


【解决方案1】:

您的第一个问题是您立即调用 drawLines 函数,然后将该函数的结果(未定义)传递给 setTimeout

More on that here

一旦你解决了这个问题,你会发现你有一个循环中的闭包问题。有很多方法可以解决这个问题,尽管我选择创建一个新函数并将所需的变量传递给它,然后在该函数中创建超时。

More info on closure inside a loop

解决了这两个问题后,您将得到以下结果:

新功能:

function drawLine(atx, xaxis, y, delay){
    setTimeout(function(){
        atx.lineTo(xaxis, y);
        atx.stroke();
    }, delay);
}

代替您现有的setTimeout

drawLine(atx, xaxis, Option1[i], 400 * i);  

你会注意到我有400 * i 用于超时延迟,而不是像你一样只有400。如果使用 400,它们将在 400ms 后立即绘制。

这是一个有效的 sn-p:

$(document).ready(function() {
  var Option1 = [100, 150, 150, 130, 50, 100, 75, 125, 50, 100];

  var xaxis = 5;
  var a = document.getElementById("myCanvas1");
  var atx = a.getContext("2d");
  atx.beginPath();
  atx.moveTo(5, 400);
  atx.strokeStyle="green";

  for (var i = 0; i < Option1.length; ++i) {
    xaxis += 5;

    $('#option1').animate({
      left: '+=5px',
      top: Option1[i]
    }, 400);

    drawLine(atx, xaxis, Option1[i], 400 * i);  
  };
});

function drawLine(atx, xaxis, y, delay){
    setTimeout(function(){
        atx.lineTo(xaxis, y);
        atx.stroke();
    }, delay);
}
html,
body {
  width: 100%;
  height: 100%;
  background-color: black;
}

#maindiv {
  position: absolute;
  top: 5px;
  left: 5px;
  z-index: 5;
  cursor: pointer;
  Width: 500px;
  Height: 400px;
  background-color: black;
  border-radius: 1%;
  border-width: 0px;
  border-color: blue;
  border-style: solid;
  font-family: Verdana, Arial, Sans-Serif;
  color: white;
  box-shadow: 0 0 20px white;
}

canvas {
  position: absolute;
  z-index: 5;
  cursor: pointer;
  Width: 100%;
  Height: 100%;
  background-color: none;
  border-radius: 1%;
  border-width: 1px;
  border-color: blue;
  border-style: solid;
  font-family: Verdana, Arial, Sans-Serif;
  color: white;
  box-shadow: 0 0 20px white;
}

#option1 {
  position: absolute;
  top: 390px;
  left: 5px;
  z-index: 10;
  Width: 5px;
  Height: 5px;
  background-color: green;
  border-radius: 50%;
  border-width: 0px;
  border-color: blue;
  border-style: solid;
  font-family: Verdana, Arial, Sans-Serif;
  color: white;
  box-shadow: 0 0 20px white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<html>
  <body>
    <div id="maindiv">
      <canvas id="myCanvas1" width="500" height="400"></canvas>
      <div id="option1"></div>
    </div>
  </body>
</html>

【讨论】:

  • 谢谢詹姆斯,这很好用!正是我想要的。发生的下一个问题是,大约 25 步后,线条开始在 div 点动画之前运行(在“未来”中显示越来越多的线条和落后的 div 点)。由于每个设备的速度差异似乎不同(在多台计算机上尝试过),我猜delay 的处理方式与animate 的时间不同。我会尝试在forloop 之外调用动画,正如你向我展示的那样,但我认为这不会有帮助。无论如何,这是另一个话题。再次感谢!
  • @Teun 我很惊讶他们明显不同步。您可以考虑在对animate 的回调中调用下一个drawLine,而不是强制它们同步。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-19
  • 1970-01-01
相关资源
最近更新 更多