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 函数负责动画的绘制和更新。
  • 通过监听鼠标移动和触摸事件来更新线条的位置,并开始动画循环。
相关推荐
摇头的金丝猴3 分钟前
uniapp vue3 使用echarts-gl 绘画3d图表
前端·uni-app·echarts
清清ww15 分钟前
【TS】九天学会TS语法---计划篇
前端·typescript
天天打码17 分钟前
html checkbox和label 文字不对齐解决办法
css·html
南棱笑笑生39 分钟前
20241105编译Rockchip原厂的Android13并给荣品PRO-RK3566开发板刷机
java·开发语言·前端
dy171740 分钟前
el-date-picker日期选择器动态设置日期
前端·vue.js·elementui
浏览器爱好者1 小时前
Chrome与火狐哪个浏览器的性能表现更好
前端·chrome
Topstip1 小时前
在 Google Chrome 上查找并安装 SearchGPT 扩展
前端·人工智能·chrome·gpt·ai·chatgpt
gqkmiss1 小时前
Chrome 130 版本开发者工具(DevTools)更新内容
前端·chrome·chrome devtools·开发者工具·chrome 130
codeGoogle1 小时前
计算机书籍打包
前端·后端·编程语言
小远yyds1 小时前
跨平台使用高德地图服务
前端·javascript·vue.js·小程序·uni-app