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

代码如下

<!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代码

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

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

#解析JS代码

  1. Wave 类
    • 用于描述一个正弦波,包含相位(phase)、偏移(offset)、频率(frequency)和振幅(amplitude)属性。
    • update 方法用于更新波形,每次调用时相位增加一定的频率,并返回当前波形的位置。
  2. Node 类
    • 代表动画中的一个点,拥有位置(x, y)和速度(vx, vy)。
  3. Line 类
    • 描述由多个Node组成的线段。
    • 包含弹簧系数(spring)、摩擦系数(friction)和节点列表(nodes)。
    • update 方法用于更新每个节点的位置,根据相邻节点的位置和速度以及弹簧和摩擦力。
    • draw 方法用于在Canvas上下文上绘制线条。
  4. E 对象
    • 定义了动画的一些常量,如摩擦系数、轨迹数量、节点数量、阻尼系数和张力系数。
  5. renderCanvas 函数
    • 初始化Canvas,并设置其尺寸。
    • 创建一个Wave实例,并定义了一些动画相关的变量。
    • animate 函数负责动画的绘制和更新。
    • 通过监听鼠标移动和触摸事件来更新线条的位置,并开始动画循环。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/906607.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

玩转Docker | Docker基础入门与常用命令指南

玩转Docker | Docker基础入门与常用命令指南 引言基本概念help帮助信息常用命令管理镜像运行容器构建镜像其他Docker命令整理结语引言 Docker 是一种开源的应用容器引擎,它允许开发者将应用程序及其依赖打包进一个可移植的容器中,然后发布到任何流行的 Linux 机器上。这大大简…

信息学科平台设计与实现:Spring Boot技术详解

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

现代化水电管理:Spring Boot在大学城的实践

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

Rust 力扣 - 289. 生命游戏

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们记录上一行和当前行转换之后的状态&#xff0c;当前行转换之后的状态计算完毕后调整上一行状态&#xff0c;直至最后一行状态计算完毕后调整最后一行状态 题解代码 pub fn game_of_life(board: &mut V…

015:地理信息系统开发平台ArcGIS Engine10.2与ArcGIS SDK for the Microsoft .NET Framework安装教程

摘要&#xff1a;本文详细介绍地理信息系统开发平台ArcGIS Engine10.2与ArcGIS SDK for the Microsoft .NET Framework的安装流程。 一、软件介绍 ArcGIS Engine 10.2是由Esri公司开发的一款强大的GIS&#xff08;地理信息系统&#xff09;开发平台。该软件基于ArcGIS 10.2 fo…

如何进行PDF高效合并?盘点11款PDF编辑器给你

是不是经常觉得烦&#xff1a;一个PDF文件特别长&#xff0c;里面好多章节或者报告&#xff0c;每次要看或者给别人发都得翻半天&#xff1f;别担心&#xff0c;今天我就来教你们几个合并PDF的小技巧&#xff0c;保证让你在2024年变成整理文件的高手&#xff01; 1、福昕PDF文…

PPT素材、模板免费下载!

做PPT一定要收藏好这6个网站&#xff0c;PPT模板、素材、图表、背景等超多素材全部免费下载。 1、菜鸟图库 ppt模板免费下载|ppt背景图片 - 菜鸟图库 菜鸟图库网有非常丰富的免费素材&#xff0c;像设计类、办公类、自媒体类等素材都很丰富。PPT模板种类很多&#xff0c;全部都…

Cpp二叉搜索树的讲解与实现(21)

文章目录 前言一、二叉搜索树的概念定义特点 二、二叉树的实现基本框架查找插入删除当只有0 ~ 1个孩子的时候当有2个孩子的时候 三、二叉树的应用K模型KV模型 四、二叉树的性能分析总结 前言 这是全新的一个篇章呢&#xff0c;二叉搜索树是我们接下来学习set、map的前提 迈过它…

群控系统服务端开发模式-应用开发-菜单功能开发

为什么优先开发菜单&#xff0c;而不是优先开发管理员&#xff1f;查看一下程序草图就明白&#xff0c;还有一个重点就是&#xff0c;管理员需要添加图片&#xff0c;而我还没有封装上传工具及上传目标。 一、添加路由 在根目录下route文件夹下的app.php文件里面&#xff0c;添…

2024年,Rust开发语言,现在怎么样了?

Rust开发语言有着一些其他语言明显的优势&#xff0c;但也充满着争议&#xff0c;难上手、学习陡峭等。 Rust 是由 Mozilla 主导开发的通用、编译型编程语言&#xff0c;2010年首次公开。 在 Stack Overflow 的年度开发者调查报告中&#xff0c;Rust 连续多年被评为“最受喜爱…

c# 值类型

目录 1、c#类型2、值类型2.1 结构体2.2 枚举 1、c#类型 类型&#xff08;Type&#xff09;又叫数据类型&#xff08;Data Type&#xff09;。 A data type is a homogeneous collection of values,effectively prensented,equipped with a set of operations which manipulate…

怒刷666条提示词后,终于总结出终结 AI 味儿的3种方法(强烈建议收藏)

大家好&#xff0c;我是凡人。 最近一个朋友给我发了几张他知乎的评论&#xff0c;是这样的&#xff1a; 这样的&#xff1a; 还有这样的&#xff1a; 无奈他就问我 “ AI 怎么能生成没有 AI味儿 的回答&#xff1f;” &#xff0c;说实话这真是个神奇的问题。 老话儿讲 “ 耳…

Angular实现gridview效果

说明&#xff1a;使用angular实现grid效果&#xff0c;支持文字图片多条数据展示 效果图: step1: <mat-grid-list cols"2" rowHeight"2:1"><mat-grid-tile *ngFor"let course of courses">{{ course }}</mat-grid-tile> &l…

2、顶点着色器之视图矩阵

1、作用&#xff1a;将物体从世界坐标系转换到相机坐标系&#xff0c;相当于从世界坐标系转换到相机的局部(本地)坐标系。 2、基于LookAt函数的视图矩阵&#xff1a; 相机位置eye&#xff1a;(ex,ey,ez)&#xff0c;世界坐标系下的位置 目标位置center&#xff1a;(cx,cy,cz…

react使用Fullcalendar 实战用法

使用步骤请参考&#xff1a;react使用Fullcalendar 卡片式的日历&#xff1a; 需求图&#xff1a; 卡片式的日历&#xff0c;其实我是推荐 antd的&#xff0c;我两个都写了一下都能实现。 antd 的代码&#xff1a; antd的我直接用的官网示例&#xff1a;antd 日历示例 i…

基于SpringBoot+Vue实现智能停车收费系统

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

ApsaraMQ Serverless 能力再升级,事件驱动架构赋能 AI 应用

本文整理于 2024 年云栖大会阿里云智能集团高级技术专家金吉祥&#xff08;牟羽&#xff09;带来的主题演讲《ApsaraMQ Serverless 能力再升级&#xff0c;事件驱动架构赋能 AI 应用》 云消息队列 ApsaraMQ 全系列产品 Serverless 化&#xff0c;支持按量付费、自适应弹性、跨可…

基于SpringBoot+Vue实现高校毕业与学位资格审查系统

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

0.STM32F1移植到F0的各种经验总结

1.结构体的声明需放在函数的最前面 源代码&#xff1a; /*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启USART1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructu…

RDT——清华开源的双臂机器人扩散大模型:先预训练后微调,支持语言、图像、动作多种输入

第一部分 清华开源全球最大双臂机器人扩散大模型RDT 2.1 什么是RDT 2.1.1 RDT推出的背景及其与以前工作的对比 受到最近在单手操作方面尝试的启发&#xff08;Brohan等&#xff0c;2023&#xff1b;Kim等&#xff0c;2024&#xff09;&#xff0c;清华一研究团队推出了RDT&a…