简体   繁体   中英

slowly animate a simple line

My problem is that the line draw is instantaneous .

What I want is it to draw the line very slowly , almost 3-5 seconds before it finishes at dy . For some reason I cannot get the setTimeout() to work. I have tried large and small values.

I just have a basic line example but I will expand on this concept to include x and bezier lines once I can figure how the timeout works.

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

function myLine(x, y, dx, dy) { //Line constructor
  this.x = x; //start x
  this.y = y; //start y
  this.dx = dx; //end x
  this.dy = dy; //end y
}
var line = new myLine(100, 5, 100, 100); //line object

function drawLine(myLine, context) { //Draw function
    context.moveTo(myLine.x, myLine.y);   
    animate(line, context);
  }
function animate(myLine, context) { //animation function
    if (myLine.y < myLine.dy) {
      myLine.y = myLine.y + 1;
      context.lineTo(myLine.dx, myLine.y);
      context.stroke();
      window.setTimeout(animate(line, context), 1000/60);
    }
}
drawLine(line, context);

That's actually not what you want to do: computers don't do things "slowly", especially not in a context that is single-threaded. What you want to do instead is draw lots of lines, over and over, where each next line is a little longer than the previous one. That way, it looks like the line is growing, and you get exactly what you want:

function drawLine(x1,y1,x2,y2,ratio) {
  ctx.fillRect(0,0,300,300);
  ctx.beginPath();
  ctx.moveTo(x1,y1);
  x2 = x1 + ratio * (x2-x1);
  y2 = y1 + ratio * (y2-y1);
  ctx.lineTo(x2,y2);
  ctx.stroke();
  // And if we intend to start new things after
  // this, and this is part of an outline, 
  // we probably also want a ctx.closePath()
}

function animate(ratio) {
  ratio = ratio || 0;
  drawLine(0,0,300,300,ratio);
  if(ratio<1) {
    requestAnimationFrame(function() {
      animate(ratio + 0.01);
    });
  }
}

animate();

Running code: http://jsbin.com/hanaqahoyu/edit?html,js,output

Also note that we do not want to use setTimeout: in order to ensure smooth animation, modern browsers have requestAnimationFrame , which is going to trigger when it makes the most sense for a frame of animation , which is super handy: we'll use that.

window.setTimeout takes a function reference as its first argument, you've passed in the result of calling animate() , which is undefined . This won't do much.

A simple fix is an anonymous function.

window.setTimeout(function () { animate(line, context); }, 1000/60);

The more advanced method is to use .bind() .

window.setTimeout(animate.bind(null, line, context), 1000/60);

Additionally, since you're working with animations, consider looking into requestAnimationFrame .

Another approach could be to use requestAnimationFrame . Take a look at the code below:

window.requestAnimFrame = (function () {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
        window.setTimeout(callback, 1000 / 60);
    };
})();

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

function myLine(x, y, dx, dy) {
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dy;
}

line = new myLine(100, 5, 100, 100);

requestAnimFrame(render);

function render() {
    requestAnimFrame(render);
    if (line.y < line.dy) {
        line.y = line.y + 1;
        context.lineTo(line.dx, line.y);
        context.stroke();
    }
}

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM