2016-05-27 160 views
0

前几天我来到了stackoverflow,询问如何缓慢地画一个箭头到画布中。没有人能够给我正确的答案...所以我希望这可以帮助别人。在画布中绘制动画曲线

基本上,我想动画从一个国家的入侵进展到另一个国家的地图。要做到这一点,我应该使用画布并画出从A国移到B国的箭头,但不能使用固定箭头......逐渐增长的箭头。

下面的代码绘制一个箭头,但不是渐进的。所以,我需要像5s过渡的CSS动画一样绘制这条曲线。

function drawCurve (ctx, x0, y0, x1, y1, x2, y2){ 
 
    ctx.beginPath(); 
 
    ctx.moveTo(x0, y0); 
 
    ctx.quadraticCurveTo(x1, y1, x2, y2); 
 
    ctx.stroke(); 
 
    ctx.closePath(); 
 
} 
 
var docCanvas = document.getElementById('canvas'); 
 
var ctx = docCanvas.getContext('2d'); 
 
drawCurve(ctx, 0, 100, 150, -50, 300, 100);
<canvas id="canvas" width="480" height="320"></canvas>

回答

0

一些挖后,我来到了这个解决方案,它给了我所有我想要的。基本上drawBezierSplit()允许你画一段二次贝塞尔曲线。

所有功劳Patrick Galbraith

/** 
 
* Animates bezier-curve 
 
* 
 
* @param ctx  The canvas context to draw to 
 
* @param x0  The x-coord of the start point 
 
* @param y0  The y-coord of the start point 
 
* @param x1  The x-coord of the control point 
 
* @param y1  The y-coord of the control point 
 
* @param x2  The x-coord of the end point 
 
* @param y2  The y-coord of the end point 
 
* @param duration The duration in milliseconds 
 
*/ 
 
function animatePathDrawing(ctx, x0, y0, x1, y1, x2, y2, duration) { 
 
    var start = null; 
 
    
 
    var step = function animatePathDrawingStep(timestamp) { 
 
     if (start === null) 
 
      start = timestamp; 
 
     
 
     var delta = timestamp - start, 
 
      progress = Math.min(delta/duration, 1); 
 
     
 
     // Clear canvas 
 
     ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); 
 
     
 
     // Draw curve 
 
     drawBezierSplit(ctx, x0, y0, x1, y1, x2, y2, 0, progress); 
 
     
 
     if (progress < 1) { 
 
      window.requestAnimationFrame(step); 
 
     } 
 
    }; 
 
    
 
    window.requestAnimationFrame(step); 
 
} 
 

 
/** 
 
* Draws a splitted bezier-curve 
 
* 
 
* @param ctx  The canvas context to draw to 
 
* @param x0  The x-coord of the start point 
 
* @param y0  The y-coord of the start point 
 
* @param x1  The x-coord of the control point 
 
* @param y1  The y-coord of the control point 
 
* @param x2  The x-coord of the end point 
 
* @param y2  The y-coord of the end point 
 
* @param t0  The start ratio of the splitted bezier from 0.0 to 1.0 
 
* @param t1  The start ratio of the splitted bezier from 0.0 to 1.0 
 
*/ 
 
function drawBezierSplit(ctx, x0, y0, x1, y1, x2, y2, t0, t1) { 
 
    ctx.beginPath(); 
 
    
 
\t if(0.0 == t0 && t1 == 1.0) { 
 
\t \t ctx.moveTo(x0, y0); 
 
\t \t ctx.quadraticCurveTo(x1, y1, x2, y2); 
 
\t } else if(t0 != t1) { 
 
     var t00 = t0 * t0, 
 
      t01 = 1.0 - t0, 
 
      t02 = t01 * t01, 
 
      t03 = 2.0 * t0 * t01; 
 
     
 
     var nx0 = t02 * x0 + t03 * x1 + t00 * x2, 
 
      ny0 = t02 * y0 + t03 * y1 + t00 * y2; 
 
     
 
     t00 = t1 * t1; 
 
     t01 = 1.0 - t1; 
 
     t02 = t01 * t01; 
 
     t03 = 2.0 * t1 * t01; 
 
     
 
     var nx2 = t02 * x0 + t03 * x1 + t00 * x2, 
 
      ny2 = t02 * y0 + t03 * y1 + t00 * y2; 
 
     
 
     var nx1 = lerp (lerp (x0 , x1 , t0) , lerp (x1 , x2 , t0) , t1), 
 
      ny1 = lerp (lerp (y0 , y1 , t0) , lerp (y1 , y2 , t0) , t1); 
 
     
 
     ctx.moveTo(nx0, ny0); 
 
     ctx.quadraticCurveTo(nx1, ny1, nx2, ny2); 
 
\t } 
 
    
 
    ctx.stroke(); 
 
    ctx.closePath(); 
 
} 
 

 
/** 
 
* Linearly interpolates between two numbers 
 
*/ 
 
function lerp(v0, v1, t) { 
 
    return (1.0 - t) * v0 + t * v1; 
 
} 
 

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

 
animatePathDrawing(ctx, 0, 100, 150, -50, 300, 100, 5000);
<canvas id="canvas" width="480" height="320"></canvas>

编辑

如果你需要一个填充工具,您可以使用此代码:

(function() { 
    var lastTime = 0; 
    var vendors = ['webkit', 'moz']; 
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 
     window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 
     window.cancelAnimationFrame = 
      window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; 
    } 

    if (!window.requestAnimationFrame) 
     window.requestAnimationFrame = function(callback, element) { 
      var currTime = new Date().getTime(); 
      var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 
      var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 
       timeToCall); 
      lastTime = currTime + timeToCall; 
      return id; 
     }; 

    if (!window.cancelAnimationFrame) 
     window.cancelAnimationFrame = function(id) { 
      clearTimeout(id); 
     }; 
}()); 

链接http://www.pjgalbraith.com/drawing-animated-curves-javascript/