在画布中绘制动画曲线

时间:2016-05-27 09:10:59

标签: javascript html5 canvas

几天前,我来到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>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

经过一番挖掘后,我找到了这个能给我所有想要的解决方案。

基本上drawBezierSplit()允许您绘制二次贝塞尔曲线的一部分。

所有归功于 Patrick Galbraith

&#13;
&#13;
/**
 * 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();
    
	if( 0.0 == t0 && t1 == 1.0 ) {
		ctx.moveTo( x0, y0 );
		ctx.quadraticCurveTo( x1, y1, x2, y2 );
	} 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 );
	}
    
    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);
&#13;
<canvas id="canvas" width="480" height="320"></canvas>
&#13;
&#13;
&#13;

编辑

如果您需要填充,您可以使用以下代码:

(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/