简体   繁体   English

在画布中绘制动画曲线

[英]Drawing animated curves in canvas

A few days ago I came to stackoverflow asking about how to draw an arrow slowly into a canvas.几天前我来到stackoverflow询问如何在画布上缓慢绘制箭头。 No one was able to give me the correct answer... So I hope this helps someone.没有人能够给我正确的答案......所以我希望这对某人有所帮助。

Basically, i wanted to animate the progress of an invasion from one country to another country in a map.基本上,我想在地图上动画从一个国家到另一个国家的入侵过程。 To do that I should use canvas and draw an arrow that moved from country A to country B, but not a fixed arrow... An arrow that grows progressively.要做到这一点,我应该使用画布并绘制一个从 A 国移动到 B 国的箭头,但不是一个固定的箭头......一个逐渐增长的箭头。

The code below draws an arrow, but not progressively.下面的代码绘制了一个箭头,但不是渐进式的。 So, I needed to draw this curve like a CSS animation with a 5s transition.因此,我需要像具有 5 秒过渡的 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>

After some digging I came to this solution that gives me all I wanted.经过一番挖掘,我找到了这个解决方案,它提供了我想要的一切。

Basically drawBezierSplit() allow you to draw a section of a quadratic bezier curve.基本上drawBezierSplit()允许您绘制二次贝塞尔曲线的一部分。

All the credit to 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>

EDIT :编辑

And if you need a polyfill, you can use this code:如果你需要一个 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);
        };
}());

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM