在HTML画布上连续绘制直线

8

我正在尝试编写解决上述问题的代码。我尝试找到一个解决方案。这是我目前拥有的。

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var drawColorLine = function(start, end, color) {
  var deltaX, deltaY, i = 0,
    currLength = 0,
    isHor, isVert;

  deltaX = end[0] - start[0];
  deltaY = end[1] - start[1];
  context.strokeStyle = color;

  isHor = deltaX === 0 ? 0 : 1;
  isVert = deltaY === 0 ? 0 : 1;

  function draw() {
    context.beginPath();
    context.moveTo(start[0] + currLength * isHor, start[1] + currLength * isVert);

    currLength = currLength + 0.5 * i;
    context.lineTo(start[0] + currLength * isHor, start[1] + currLength * isVert);
    context.stroke();

    if (currLength <= Math.max(deltaX, deltaY)) {
      i = i + 1;
      requestAnimationFrame(draw);
    }
  }
  draw();
};

drawColorLine([40, 40], [100, 40], '#116699');
drawColorLine([40, 40], [40, 100], '#bb11dd');
<canvas id='canvas' width='400' height='400'></canvas>

问题是两个函数同时被调用,而应该一个接一个地执行。使用 Promise 可以延迟第二个函数的执行,等待第一个函数完成后再执行第二个函数。我尝试了解 Promises,但我无法将理解的内容转化为代码。
提前致谢。
2个回答

5

是的,你可以使用Promise,但是出于学习目的,你可能首先想编写一个纯回调解决方案。

你需要看一下我关于Promise开发的经验法则。让我们在这里应用它们:

  1. Every asynchronous function must return a promise.

    These would be drawColorLine, draw, and requestAnimationFrame in your case.

  2. As requestAnimationFrame is a native, primitively asynchronous function that unfortunately still takes a callback, we'll have to promisify it:

    function getAnimationFrame() {
        return new Promise(function(resolve) {
            requestAnimationFrame(resolve); // this promise never gets rejected
            // TODO: cancellation support :-)
        });
    }
    
  3. Everything that follows an asynchronous action goes into a .then() callback:

    function drawColorLine(start, end, color) {
        … // initialisation
    
        function draw() {
            … // do work
            // always return a promise:
            if (/* furter work */) {
                i++;
                return getAnimationFrame().then(draw); // magic happens here :-)
            } else {
                return Promise.resolve(…); // maybe have a path object as eventual result?
                                           // or anything else, including nothing (no arg)
            }
        }
        return draw(); // returns a promise - but don't forget the `return`
    }
    

大功告成!

drawColorLine([40, 40], [100, 40], '#116699').then(function() {
    return drawColorLine([40, 40], [40, 100], '#bb11dd');
}).then(console.log.bind(console, "both lines drawn"));

我最初用回调函数写了一个解决方案。我需要画很多线条。我想要按顺序执行它们。回调似乎不是正确的方法,或者我找不到一个好的方法来扩展我的函数。 我尝试从各种地方阅读关于Promise的内容,但我仍然没有很好的想法如何有效地使用它们。重新阅读这些内容的最佳方法是什么? - Ramana Venkata
回调函数同样适用,只需稍微改变规则:“每个异步函数必须带有回调函数,并在执行完成后调用它”,“异步操作后面的所有内容都必须放入回调函数中,然后在最后进行回调”。这相当于在返回 Promise 的情况下传递连续性。 - Bergi
是的,then回调函数可以返回承诺,然后会进行等待(详见这里这里)。我的答案在 magic happens here 那一行使用了它 :-) - Bergi
1
@guest271314:不,它还没有准备好用于大规模使用(并且几乎没有文档),但是如果您非常熟练闭包,您可以在此处阅读其代码:https://github.com/bergus/F-promise - Bergi
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Bergi
显示剩余5条评论

2

尝试利用.animate()jQuery.Deferred()

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var drawColorLine = function(start, end, color) {
  // create new `deferred` object
  var dfd = new $.Deferred(),
    deltaX, deltaY, i = 0,
    currLength = 0,
    isHor, isVert,
    // create animation object
    props = $({"prop":i}); 

  deltaX = end[0] - start[0];
  deltaY = end[1] - start[1];
  context.strokeStyle = color;

  isHor = deltaX === 0 ? 0 : 1;
  isVert = deltaY === 0 ? 0 : 1;

  function draw(n) {
    context.beginPath();
    context.moveTo(start[0] + currLength * isHor
                   , start[1] + currLength * isVert);

    currLength = currLength + 0.5 * n;
    context.lineTo(start[0] + currLength * isHor
                   , start[1] + currLength * isVert);
    context.stroke();

    if (currLength <= Math.max(deltaX, deltaY)) {
      // create object to animate,
      // do animation stuff      
      props.animate({"prop":1}, {
        // set duration of animation
        duration:10, 
        complete:function() {
          // increment `n`:`i`
          n = n + 1;
          // call `draw` with `n` as parameter
          draw(n)
        }
      })         
    } else {
      // if `currLength > Math.max(deltaX, deltaY)`,
      // resolve `deferred` object, 
      // set `canvas` element as `this` at `.then()`
      // pass `deltaX`, `deltaY`, `currLength`, `n`` 
      // arguments to `.then()`
      dfd.resolveWith(canvas, [deltaX, deltaY, currLength, n]);
    }

    }
  draw(i);
  // return jQuery promise object
  return dfd.promise()
};
// draw first line
drawColorLine([40, 40], [100, 40], '#116699')
.then(function() {
  console.log("first line complete", arguments, this);
  // draw sencond line
  return drawColorLine([40, 40], [40, 100], '#bb11dd');
}).then(function() {
  console.log("second line complete", arguments, this);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<canvas id='canvas' width='400' height='400'></canvas>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接