2016-05-27 218 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/