5

我有一堆我想慢慢画的点。我尝试 setTimeOut 和本教程的效果。但是没有那么大的成功。

函数看起来像这样

功能:

var myFunction = function(ctx, grid, points) {
                ctx.beginPath();
                ctx.moveTo(points[0].x, points[0].y);
                ctx.lineWidth = 2;
                ctx.strokeStyle = '#2068A8';
                ctx.fillStyle = '#2068A8';
                var count = 1;
                for (count = 1; count < points.length; count++) {
                    ctx.lineTo(points[count].x , points[count].y);
                }
                ctx.stroke();
            }

围绕这个功能还有许多其他绘图功能,但我只想为其中一个设置动画。

如何用画布慢慢绘制函数?

4

2 回答 2

10

有两种方法可以做到这一点,我能想到的。一个基本上是画一个点并在画另一个点之前暂停一段时间。这是我提供的第一个示例。第二种方法涉及将部分线绘制到当前目标,这会提供更平滑的绘制外观。作为一个旁注,我requestAnimationFrame在这两个示例中都使用了它,这是执行任何类型的画布动画的推荐方法。

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d");

canvas.width = 400;
canvas.height = 200;

var points = [],
    currentPoint = 1,
    nextTime = new Date().getTime()+500,
    pace = 200;

// make some points
for (var i = 0; i < 50; i++) {
    points.push({
        x: i * (canvas.width/50),
        y: 100+Math.sin(i) * 10
    });
}

function draw() {

    if(new Date().getTime() > nextTime){
        nextTime = new Date().getTime() + pace;

        currentPoint++;
        if(currentPoint > points.length){
            currentPoint = 0;
        }
    }
    ctx.clearRect(0,0,canvas.width, canvas.height);
    ctx.beginPath();
    ctx.moveTo(points[0].x, points[0].y);
    ctx.lineWidth = 2;
    ctx.strokeStyle = '#2068A8';
    ctx.fillStyle = '#2068A8';
    for (var p = 1, plen = currentPoint; p < plen; p++) {
        ctx.lineTo(points[p].x, points[p].y);
    }
    ctx.stroke();

    requestAnimFrame(draw);
}

draw();

现场演示

如果您发现这有点不稳定,您可以执行以下操作以绘制更平滑的线条

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d");

canvas.width = 400;
canvas.height = 200;

var points = [],
    currentPoint = 1,
    speed = 2,
    targetX = 0,
    targetY = 0,
    x = 0,
    y = 0;

// make some points
for (var i = 0; i < 50; i++) {
    points.push({
        x: i * (canvas.width/50),
        y: 100+Math.sin(i) * 10
    });
}

// set the initial target and starting point
targetX = points[1].x;
targetY = points[1].y;
x = points[0].x;
y = points[0].y;

function draw() {
    var tx = targetX - x,
        ty = targetY - y,
        dist = Math.sqrt(tx*tx+ty*ty),
        velX = (tx/dist)*speed,
        velY = (ty/dist)*speed;

        x += velX
        y += velY;

    if(dist < 1){
        currentPoint++;

        if(currentPoint >= points.length){
            currentPoint = 1;
            x = points[0].x;
            y = points[0].y;
        }

        targetX = points[currentPoint].x;
        targetY = points[currentPoint].y;
    }

    ctx.clearRect(0,0,canvas.width, canvas.height);
    ctx.beginPath();
    ctx.moveTo(points[0].x, points[0].y);
    ctx.lineWidth = 2;
    ctx.strokeStyle = '#2068A8';
    ctx.fillStyle = '#2068A8';

    for (var p = 0, plen = currentPoint-1; p < plen; p++) {
        ctx.lineTo(points[p].x, points[p].y);
    }
    ctx.lineTo(x, y);    
    ctx.stroke();

    requestAnimFrame(draw);
}

draw();

现场演示

于 2013-01-23T18:41:04.093 回答
0

感谢您提供这些示例,Loktar!这应该是对 Loktar 发布的答案中上面第二个示例的评论,但我无法发表评论,因为我刚刚注册并且没有足够的“声誉”。

我尝试了上面的第二个演示,如果你放慢速度,你会注意到新的线段从它应该开始的点之前的点开始增长。这就是我对其进行调整以使其工作的方式:

我更改了以下行:

ctx.lineTo(points[p].x, points[p].y); 
// => 
ctx.lineTo(points[p+1].x, points[p+1].y);

现在结果看起来非常顺利。我发表评论是因为 Loktar 的帖子几乎是完美的,我希望人们不要因为需要调整的一个小细节而错过他的帖子。再次感谢,洛克塔!

于 2020-12-11T07:38:00.230 回答