html5 canvas - animating an object following a path

前端 未结 3 1089
情话喂你
情话喂你 2021-01-31 05:12

I\'m a bit new to canvas and such so forgive if it\'s a trivial question.

I\'d like to be able to animate an object following a path (defined as bezier path) but I\'m no

3条回答
  •  眼角桃花
    2021-01-31 05:56

    Use the code on my website from this related question, but instead of changing the .style.left and such in the callback, erase and re-draw your canvas with the item at the new location (and optionally rotation).

    Note that this uses SVG internally to easily interpolate points along a bézier curve, but you can use the points it gives you for whatever you want (including drawing on a Canvas).

    In case my site is down, here's a current snapshot of the library:

    function CurveAnimator(from,to,c1,c2){
      this.path = document.createElementNS('http://www.w3.org/2000/svg','path');
      if (!c1) c1 = from;
      if (!c2) c2 = to;
      this.path.setAttribute('d','M'+from.join(',')+'C'+c1.join(',')+' '+c2.join(',')+' '+to.join(','));
      this.updatePath();
      CurveAnimator.lastCreated = this;
    }
    CurveAnimator.prototype.animate = function(duration,callback,delay){
      var curveAnim = this;
      // TODO: Use requestAnimationFrame if a delay isn't passed
      if (!delay) delay = 1/40;
      clearInterval(curveAnim.animTimer);
      var startTime = new Date;
      curveAnim.animTimer = setInterval(function(){
        var now = new Date;
        var elapsed = (now-startTime)/1000;
        var percent = elapsed/duration;
        if (percent>=1){
          percent = 1;
          clearInterval(curveAnim.animTimer);
        }
        var p1 = curveAnim.pointAt(percent-0.01),
            p2 = curveAnim.pointAt(percent+0.01);
        callback(curveAnim.pointAt(percent),Math.atan2(p2.y-p1.y,p2.x-p1.x)*180/Math.PI);
      },delay*1000);
    };
    CurveAnimator.prototype.stop = function(){
      clearInterval(this.animTimer);
    };
    CurveAnimator.prototype.pointAt = function(percent){
      return this.path.getPointAtLength(this.len*percent);
    };
    CurveAnimator.prototype.updatePath = function(){
      this.len = this.path.getTotalLength();
    };
    CurveAnimator.prototype.setStart = function(x,y){
      var M = this.path.pathSegList.getItem(0);
      M.x = x; M.y = y;
      this.updatePath();
      return this;
    };
    CurveAnimator.prototype.setEnd = function(x,y){
      var C = this.path.pathSegList.getItem(1);
      C.x = x; C.y = y;
      this.updatePath();
      return this;
    };
    CurveAnimator.prototype.setStartDirection = function(x,y){
      var C = this.path.pathSegList.getItem(1);
      C.x1 = x; C.y1 = y;
      this.updatePath();
      return this;
    };
    CurveAnimator.prototype.setEndDirection = function(x,y){
      var C = this.path.pathSegList.getItem(1);
      C.x2 = x; C.y2 = y;
      this.updatePath();
      return this;
    };
    

    …and here's how you might use it:

    var ctx = document.querySelector('canvas').getContext('2d');
    ctx.fillStyle = 'red';
    
    var curve = new CurveAnimator([50, 300], [350, 300], [445, 39], [1, 106]);
    
    curve.animate(5, function(point, angle) {
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        ctx.fillRect(point.x-10, point.y-10, 20, 20);
    });​
    

    In action: http://jsfiddle.net/Z2YSt/

提交回复
热议问题