使用HTML5画布创建动态点网格动画

本文介绍了如何使用HTML5 Canvas创建动态点网格动画。文章详细解释了创建点、创建线的过程,以及如何通过JavaScript调整粒子的位置和速度,使得点在画布上形成流动的网格效果。此外,还讨论了动画性能优化和可能的改进方向。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Perhaps one of the most recognizable visual motifs of the last several years is the animation style you should see above; I’m not sure it has a name, but I call it a dynamic point mesh animation. This is my variation on the style, derived from previous work by Daniel Mayovskiy.

过去几年中,最知名的视觉主题之一可能是您应该在上面看到的动画样式; 我不确定它的名称,但我称其为动态点网格动画 。 这是我对风格的变化,它是由Daniel Mayovskiy的先前作品衍生而来的。

Frequently such animations are layered behind other content, so it makes sense to size this example to the same size as the viewport:

通常,此类动画会位于其他内容的后面,因此可以将本示例的大小调整为与视口相同的大小:

<canvas id="canvas"></canvas>

The CSS:

CSS:

body {
    background: #222;
    margin: 0rem;
    min-height: 100vh;
}
#canvas {
    position: absolute;
    display: block;
    top: 0;
    left: 0;
    z-index: -1;
}

The Codepen version of this code has a little more detail, including the CSS and markup for placing the text on top of the animation.

代码Codepen版本具有更多细节,包括CSS和用于将文本置于动画顶部的标记。

To ensure that the <canvas> is always the full height and width of the viewport, the first part of the JavaScript at the end of the page is a resize function:

为了确保<canvas>始终是视口的完整高度和宽度,页面结尾处的JavaScript的第一部分是一个调整大小的函数:

let resizeReset = function() {
    w = canvasBody.width = window.innerWidth;
    h = canvasBody.height = window.innerHeight;
}

创建点 (Creating the Dots)

opts is an object that contains a series of properties that act as default values for the script:

opts是一个对象 ,其中包含一系列用作脚本默认值的属性:

const opts = { 
        particleColor: "rgb(200,200,200)",
        lineColor: "rgb(200,200,200)",
        particleAmount: 40,
        defaultSpeed: 1,
        variantSpeed: 1,
        defaultRadius: 2,
        variantRadius: 2,
        linkRadius: 200,
}

The variants for speed and radius are used to add randomness to the size and movement of the mesh points; linkRadius is how close the points must come before they are joined with lines.

速度和半径的变体用于增加网格点的大小和运动的随机性linkRadius是点与线连接之前必须达到的接近程度。

The <canvas> element must be resized so that the particles always meet the edge of the browser window. The resizeReset() function is called once on script load, but needs to be throttled or “debounced” so that it doesn’t slow down the script during operation of the rest of the page:

必须调整<canvas>元素的大小,以使粒子始终与浏览器窗口的边缘相交。 resizeReset()函数在脚本加载时被调用一次,但需要进行限制或“反跳”处理,以使其在页面其余部分的操作期间不会降低脚本的运行速度:

let delay = 200, tid;

window.addEventListener("resize", function(){
        deBouncer();
});

let deBouncer = function() {
    clearTimeout(tid);
    tid = setTimeout(function() {
        resizeReset();
    }, delay);
};

The Particle object is a fairly large function that generates each of the “dots”:

Particle对象是一个相当大的函数,它会生成每个“点”:

Particle = function(xPos, yPos){ 
    this.x = Math.random() * w; 
    this.y = Math.random() * h;
    this.speed = opts.defaultSpeed + Math.random() * opts.variantSpeed; 
    this.directionAngle = Math.floor(Math.random() * 360); 
    this.color = opts.particleColor;
    this.radius = opts.defaultRadius + Math.random() * opts. variantRadius; 
    this.vector = {
        x: Math.cos(this.directionAngle) * this.speed,
        y: Math.sin(this.directionAngle) * this.speed
    };
    this.update = function(){ 
        this.border(); 
        this.x += this.vector.x; 
        this.y += this.vector.y; 
    };
    this.border = function(){ 
        if (this.x >= w || this.x <= 0) { 
            this.vector.x *= -1;
        }
        if (this.y >= h || this.y <= 0) {
            this.vector.y *= -1;
        }
        if (this.x > w) this.x = w;
        if (this.y > h) this.y = h;
        if (this.x < 0) this.x = 0;
        if (this.y < 0) this.y = 0; 
    };
    this.draw = function(){ 
        drawArea.beginPath();
        drawArea.arc(this.x, this.y, this.radius, 0, Math.PI*2);
        drawArea.closePath();
        drawArea.fillStyle = this.color;
        drawArea.fill();
    };
};

In the context of the script, this refers to each particle, as it is created:

在脚本的上下文中, this是指创建时每个粒子

  • the initial position, speed and angle of each particle are decided randomly; the particle’s color is determined from the associated option setting.

    每个粒子的初始位置,速度和角度是随机确定的; 粒子的颜色由相关的选项设置确定。
  • this.vector stores the direction of the particle: if this.vector.x is 1, it’s moving to the right; if -1, it’s moving to the left. Similarly, if this.vector.y is negative, it’s moving up, if positive, it’s moving down.

    this.vector存储粒子的方向 :如果this.vector.x1 ,则向右移动; 如果为-1 ,则向左移动。 同样,如果this.vector.y负数 ,则向上移动;如果为正数 ,则向下移动。

  • this.update calculates the next coordinates for each particle. First, it checks if the particle is touching the border; if the particle goes past the dimensions of the canvas, it’s vector is changed, multiplied by -1 to produce the opposite direction

    this.update计算每个粒子的下一个坐标。 首先,它检查粒子是否接触边界。 如果粒子超出画布的尺寸,则其向量将更改,乘以-1即可产生相反的方向

  • a window resize may leave a particle further across the perimeter than the border function will capture, so a series of if statements checks if that’s the case, resetting the position of the particle to the current limits of the canvas.

    调整窗口大小可能会使粒子在边界上保留的距离超出border函数捕获的border ,因此一系列的if语句检查是否存在这种情况,将粒子的位置重置为画布的当前限制。

  • finally, the dots are drawn in place.

    最后,将点绘制到位。

To start it all moving, we need the following:

要开始这一切,我们需要以下内容:

function setup(){ 
    particles = [];
    for (let i = 0; i < opts.particleAmount; i++){
        particles.push( new Particle() );
    }
    window.requestAnimationFrame(loop);
}

The setup function creates a particles array, and fills it with a series of particle elements before calling the loop function, using requestionAnimationFrame.

setup函数创建一个particles数组,并使用requestionAnimationFrame在调用loop函数之前用一系列粒子元素填充它。

That loop function looks like this:

loop函数如下所示:

function loop(){ 
    window.requestAnimationFrame(loop);
    drawArea.clearRect(0,0,w,h);
    for (let i = 0; i < particles.length; i++){
        particles[i].update();
        particles[i].draw();
    }
}

The loop function clears the canvas area, updates each particle position, and draws it; the constant refreshing with requestAnimationFrame() creates the impression of animation.

loop功能清除画布区域,更新每个粒子位置并绘制; 使用requestAnimationFrame()不断刷新可创建动画效果。

Everything is started by calling the setup() function, after setting a few other constants and variables and initializing the resizeReset function:

在设置了其他一些常量和变量并初始化resizeReset函数之后,通过调用setup()函数开始一切操作:

const canvasBody = document.getElementById("canvas"),
drawArea = canvasBody.getContext("2d");
let delay = 200, tid;
resizeReset();
setup();

At this point, the animation will look like a series of dots moving around the canvas:

此时,动画将看起来像一系列围绕画布移动的点:

See the Pen Dynamic Point Animation with HTML5 Canvas by Dudley Storey (@dudleystorey) on CodePen.

见笔动态点动画与HTML5画布由达德利·斯托里( @dudleystorey )上CodePen

To create the mesh, we must add a little more code.

要创建网格,我们必须添加一些代码。

创建线 (Creating the Lines)

To draw the lines, the loop() function is added to, becoming:

为了画线,将loop()函数添加到其中,成为:

function loop(){ 
    window.requestAnimationFrame(loop);
    drawArea.clearRect(0,0,w,h);
    for (let i = 0; i < particles.length; i++){
        particles[i].update();
        particles[i].draw();
    }
    for (let i = 0; i < particles.length; i++){
        linkPoints(particles[i], particles);
    }
}

The linkPoints function is called for every particle. That function also uses a piece of code called checkDistance:

每个粒子都会调用linkPoints函数。 该函数还使用了一段称为checkDistance的代码:

let checkDistance = function(x1, y1, x2, y2){ 
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
};

The checkDistance function determines the distance between each point; if that distance is less than linkDistance, the calculated opacity of the line will be greater than 0, and it will be drawn between the matching points.

checkDistance函数确定每个点之间的距离; 如果该距离小于linkDistance ,则计算出的线的opacity将大于0,并将在匹配点之间绘制。

Before we get there, the rgb color is broken into its components:

在到达那里之前, rgb颜色分为以下成分:

let rgb = opts.lineColor.match(/\d+/g);

The linkPoints function checks each point against the other particles (referred to as “hubs” in the context of the function) and draws the line at the determined level of opacity, using template literals:

linkPoints函数将每个点与其他粒子(在该函数的上下文中称为“集线器”)进行对照,并使用模板文字以确定的不透明度级别绘制线条:

let linkPoints = function(point1, hubs){ 
    for (let i = 0; i < hubs.length; i++) {
        let distance = checkDistance(point1.x, point1.y, hubs[i].x, hubs[i].y);
        let opacity = 1 - distance / opts.linkRadius;
        if (opacity > 0) { 
            drawArea.lineWidth = 0.5;
            drawArea.strokeStyle = `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${opacity})`;
            drawArea.beginPath();
            drawArea.moveTo(point1.x, point1.y);
            drawArea.lineTo(hubs[i].x, hubs[i].y);
            drawArea.closePath();
            drawArea.stroke();
        }
    }
}

结论 (Conclusion)

The result (using aspects of ES6) is very efficient, and I encourage you to experiment with the various options in the script.

结果(使用ES6的各个方面)非常有效,我鼓励您尝试使用脚本中的各种选项。

Note that the animation can be brought to its knees by adding too many points and/or too great a link distance (which creates too many lines). It would also be nice to have the speed of the particles slow down as the viewport narrows: at small sizes, the particles appear to move faster in a more confined space.

请注意,可以通过添加太多点和/或太大链接距离(从而创建太多线)来使动画屈服。 当视口变窄时,让粒子的速度减慢也将是一件好事:在较小的尺寸下,粒子似乎在更狭窄的空间中移动得更快。

翻译自: https://thenewcode.com/1159/Create-a-Dynamic-Point-Mesh-Animation-with-HTML5-Canvas

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值