HTML鼠标移动的波浪线动画——页面将会初始化一个Canvas元素,并使用JavaScript代码在Canvas上绘制响应鼠标移动的波浪线动画

代码如下

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Wave Animation</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
        canvas {
            display: block;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        class Wave {
            constructor(e) {
                this.phase = e.phase || 0;
                this.offset = e.offset || 0;
                this.frequency = e.frequency || 0.001;
                this.amplitude = e.amplitude || 1;
            }

            update() {
                this.phase += this.frequency;
                return this.offset + Math.sin(this.phase) * this.amplitude;
            }
        }

        class Node {
            constructor() {
                this.x = 0;
                this.y = 0;
                this.vy = 0;
                this.vx = 0;
            }
        }

        class Line {
            constructor(e, pos) {
                this.spring = e.spring + 0.1 * Math.random() - 0.05;
                this.friction = E.friction + 0.01 * Math.random() - 0.005;
                this.nodes = [];
                this.pos = pos; 

                for (let i = 0; i < E.size; i++) {
                    const t = new Node();
                    t.x = this.pos.x;
                    t.y = this.pos.y;
                    this.nodes.push(t);
                }
            }

            update() {
                let spring = this.spring;
                let node = this.nodes[0];

                node.vx += (this.pos.x - node.x) * spring;
                node.vy += (this.pos.y - node.y) * spring;

                let prevNode;
                for (let i = 0; i < this.nodes.length; i++) {
                    node = this.nodes[i];

                    if (i > 0) {
                        prevNode = this.nodes[i - 1];
                        node.vx += (prevNode.x - node.x) * spring;
                        node.vy += (prevNode.y - node.y) * spring;
                        node.vx += prevNode.vx * E.dampening;
                        node.vy += prevNode.vy * E.dampening;
                    }

                    node.vx *= this.friction;
                    node.vy *= this.friction;
                    node.x += node.vx;
                    node.y += node.vy;
                    spring *= E.tension;
                }
            }

            draw(ctx) {
                let currNode,
                    nextNode,
                    x = this.nodes[0].x,
                    y = this.nodes[0].y;

                ctx.beginPath();
                ctx.moveTo(x, y);

                let i;
                for (i = 1; i < this.nodes.length - 2; i++) {
                    currNode = this.nodes[i];
                    nextNode = this.nodes[i + 1];
                    x = 0.5 * (currNode.x + nextNode.x);
                    y = 0.5 * (currNode.y + nextNode.y);
                    ctx.quadraticCurveTo(currNode.x, currNode.y, x, y);
                }
                currNode = this.nodes[i];
                nextNode = this.nodes[i + 1];
                ctx.quadraticCurveTo(currNode.x, currNode.y, nextNode.x, nextNode.y);

                ctx.stroke();
                ctx.closePath();
            }
        }

        const E = {
            friction: 0.5,
            trails: 20,
            size: 50,
            dampening: 0.25,
            tension: 0.98,
        };

        const renderCanvas = function () {
            const canvas = document.getElementById("canvas");
            const ctx = canvas.getContext("2d");
            let lines = [];
            const pos = { x: 0, y: 0 };
            const wave = new Wave({
                phase: Math.random() * 2 * Math.PI,
                amplitude: 85,
                frequency: 0.0015,
                offset: 285,
            });
            let running = true;
            let frame = 1;

            function resizeCanvas() {
                ctx.canvas.width = window.innerWidth;
                ctx.canvas.height = window.innerHeight;
            }

            resizeCanvas();

            function animate() {
                if (running) {
                    ctx.globalCompositeOperation = "source-over";
                    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
                    ctx.globalCompositeOperation = "lighter";
                    ctx.strokeStyle = `hsla(${Math.round(wave.update())}, 90%, 50%, 0.25)`;
                    ctx.lineWidth = 1;

                    for (let i = 0; i < E.trails; i++) {
                        const line = lines[i];
                        line.update();
                        line.draw(ctx);
                    }
                    frame++;
                    window.requestAnimationFrame(animate);
                }
            }

            function bindMouseMove(event) {
                function drawLine() {
                    lines = [];
                    for (let i = 0; i < E.trails; i++)
                        lines.push(new Line({ spring: 0.45 + (i / E.trails) * 0.025 }, pos));
                }
                function move(e) {
                    e.touches
                        ? ((pos.x = e.touches[0].pageX), (pos.y = e.touches[0].pageY))
                        : ((pos.x = e.clientX), (pos.y = e.clientY));
                    e.preventDefault();
                }
                function start(e) {
                    if (e.touches.length === 1) {
                        pos.x = e.touches[0].pageX;
                        pos.y = e.touches[0].pageY;
                    }
                }
                document.removeEventListener("mousemove", bindMouseMove);
                document.removeEventListener("touchstart", bindMouseMove);
                document.addEventListener("mousemove", move);
                document.addEventListener("touchmove", move);
                document.addEventListener("touchstart", start);
                move(event);
                drawLine();
                animate();
            }

            document.addEventListener("mousemove", bindMouseMove);
            document.addEventListener("touchstart", bindMouseMove);
            document.body.addEventListener("orientationchange", resizeCanvas);
            window.addEventListener("resize", resizeCanvas);
            window.addEventListener("focus", () => {
                if (!running) {
                    running = true;
                    animate();
                }
            });
            window.addEventListener("blur", () => {
                running = true;
            });
        };

        renderCanvas();
    </script>
</body>
</html>

#解析HTML代码

HTML结构
  • 页面中包含一个<canvas>元素,用于绘制动画。
  • CSS样式用于隐藏页面的默认边距,并使画布全屏显示。
JavaScript代码
  • 包含了之前定义的所有类和函数。
  • renderCanvas函数被调用以启动动画。
事件监听
  • 添加了鼠标移动和触摸事件监听器,以更新线条的位置。
  • 窗口调整大小事件监听器用于保持画布与窗口大小同步。

将上述HTML代码保存为一个.html文件,并在浏览器中打开,你就可以看到一个随着鼠标移动变化的波浪线动画了。

#解析JS代码

Wave 类
  • 用于描述一个正弦波,包含相位(phase)、偏移(offset)、频率(frequency)和振幅(amplitude)属性。
  • update 方法用于更新波形,每次调用时相位增加一定的频率,并返回当前波形的位置。
Node 类
  • 代表动画中的一个点,拥有位置(x, y)和速度(vx, vy)。
Line 类
  • 描述由多个Node组成的线段。
  • 包含弹簧系数(spring)、摩擦系数(friction)和节点列表(nodes)。
  • update 方法用于更新每个节点的位置,根据相邻节点的位置和速度以及弹簧和摩擦力。
  • draw 方法用于在Canvas上下文上绘制线条。
E 对象
  • 定义了动画的一些常量,如摩擦系数、轨迹数量、节点数量、阻尼系数和张力系数。
renderCanvas 函数
  • 初始化Canvas,并设置其尺寸。
  • 创建一个Wave实例,并定义了一些动画相关的变量。
  • animate 函数负责动画的绘制和更新。
  • 通过监听鼠标移动和触摸事件来更新线条的位置,并开始动画循环。
相关推荐
桂月二二5 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
CodeClimb6 小时前
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
hunter2062066 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb6 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角6 小时前
CSS 颜色
前端·css
九酒7 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔7 小时前
HTML5 新表单属性详解
前端·html·html5
lee5768 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579658 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
光头程序员8 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript