Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw continuous lines on HTML canvas one after the other

I am trying to write code for the above described problem. I tried finding a solution. This is what I currently have.

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>

The problem is both are being drawn at the same time. One should follow after the other. Using promsises is it possible to delay the second function while the first function is getting executed and later execute second function? I tried reading on Promises a bit but I couldn't translate what I understood into code.

Thanks in advance.

like image 711
Ramana Venkata Avatar asked Apr 27 '15 19:04

Ramana Venkata


People also ask

Can we have multiple canvas elements on one HTML?

Canvas Example The width and height attribute is necessary to define the size of the canvas. Tip: You can have multiple <canvas> elements on one HTML page. By default, the <canvas> element has no border and no content.

What is used to draw lines on the canvas?

Overview. The lineTo method is used to draw a line on the canvas. Below are the steps to draw a line on the canvas: Use the beginPath() method to start a new path.


2 Answers

Yes, you can use promises, altough for learning purposes you might want to write a pure callback solution first.

You'll want to have a look at my rules of thumb for promise development. Let's apply them here:

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

Voila!

drawColorLine([40, 40], [100, 40], '#116699').then(function() {
    return drawColorLine([40, 40], [40, 100], '#bb11dd');
}).then(console.log.bind(console, "both lines drawn"));
like image 54
Bergi Avatar answered Nov 10 '22 21:11

Bergi


Try utilizing .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>
like image 37
guest271314 Avatar answered Nov 10 '22 21:11

guest271314