在画布上绘制动画曲线

皮特里奥

几天前,我来到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>

皮特里奥

经过一番挖掘,我得出了这个解决方案,它为我提供了我想要的一切。

基本上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();
    
	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);
<canvas id="canvas" width="480" height="320"></canvas>

编辑

如果您需要一个polyfill,则可以使用以下代码:

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在画布上绘制动画曲线

来自分类Dev

画布线条绘制动画

来自分类Dev

在html5画布中绘制动画的贝塞尔曲线时如何保持平滑的线条

来自分类Dev

绘制动画时间

来自分类Dev

以编程方式绘制动画

来自分类Dev

如何绘制动画的UIImage?

来自分类Dev

使用画布绘制对角曲线

来自分类Dev

用Python绘制动画颤动

来自分类Dev

绘制动画openlayers线串路径

来自分类Dev

使用Matplotlib绘制动画股票的价格

来自分类Dev

在按钮下可绘制动画

来自分类Dev

在 Angular 7 中绘制动画 SVG

来自分类Dev

在 Nattable OverlayPainter 中绘制动画

来自分类Dev

如何在 Java Swing 中的背景图像上绘制动画

来自分类Dev

如何在画布上绘制绘图线动画

来自分类Dev

在box2d中绘制动态射弹曲线

来自分类Dev

Android:为圆形进度动画绘制动画

来自分类Dev

如何在画布上的两个点之间绘制一条曲线?

来自分类Dev

如何在画布上绘制通过三个点的曲线?

来自分类Dev

画布上的毛刺动画

来自分类Dev

可以用SpriteKit绘制动画线吗?

来自分类Dev

SVG绘制动画半圆不适用于虚线

来自分类Dev

如何在TVirtualStringTree中绘制动画级别栏?

来自分类Dev

在画布上绘制多次

来自分类Dev

在旋转的画布上绘制

来自分类Dev

如何在 HTML5 画布上使用二次贝塞尔曲线绘制小写 b

来自分类Dev

如何在画布上绘制带有动画的圆轨迹的箭头?

来自分类Dev

我想遵循绘制动态曲线的路径,如何解决?

来自分类Dev

使用 MVVM 在 WPF Canvas 上绘制动态圆