使用HTML5 Canvas 实现呼吸粒子球动画效果的原理

在网页开发领域,动画效果能够极大地提升用户体验,让页面变得更加生动有趣。今天,我们深入剖析一个基于 HTML5 Canvas 的 3D 粒子动画 —— 呼吸粒子球。通过详细解读其代码实现,我们将全面了解如何运用 HTML5 的强大功能构建出如此迷人的视觉效果。
效果展示:

用 HTML5 Canvas 和 JavaScript 实现粒子恒星脉动特效

1,整体架构

整个呼吸粒子球效果是 HTML、CSS 和 JavaScript 协同工作的成果。HTML 搭建基础页面结构,CSS 负责样式与背景设置,而 JavaScript 则实现核心动画逻辑。

1.1,HTML结构

<!DOCTYPE html>
<html>
<head><title>呼吸粒子球</title><style>body {margin: 0;overflow: hidden;background: radial-gradient(circle at center, #1a1a2e 0%, #16213e 50%, #0f172a 100%);}canvas {display: block;}</style>
</head>
<body><canvas id="canvas"></canvas><script>// 动画相关的JavaScript代码</script>
</body>
</html>

在 HTML 部分,我们创建了一个canvas元素,它是动画的绘制区域。通过 CSS 设置页面背景为径向渐变,营造深邃空间感,同时将canvas设为块级元素并使其充满整个页面,保证动画能全屏展示。

1.2,JavaScript初始化

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');// 设置canvas尺寸为全屏
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

JavaScript 代码首先获取canvas元素,通过getContext(‘2d’)获取 2D 绘图上下文。然后将canvas尺寸设置为当前窗口的宽高,确保动画全屏显示。

2、粒子类的实现

粒子是构成呼吸粒子球的基本元素,通过定义Particle类来管理每个粒子的属性和行为。

2.1,粒子属性初始化

class Particle {constructor() {this.x = 0;this.y = 0;this.z = 0;this.radius = Math.random() * 1.2 + 0.3;this.theta = Math.random() * Math.PI * 2;this.phi = Math.acos((Math.random() * 2) - 1);this.baseR = 200;this.speed = Math.random() * 0.001 + 0.0005;// 根据深度设置颜色this.baseColor = {r: Math.random() * 100 + 155,g: Math.random() * 100 + 155,b: 255};}

在Particle类的构造函数中:

  • x、y、z表示粒子在三维空间中的位置,初始值为 0 ,后续会在动画过程中更新。
  • radius是粒子半径,通过Math.random()函数生成一个随机小数,再乘以 1.2 并加上 0.3,这样粒子半径范围在 0.3 到
    1.5 之间,使得粒子大小呈现多样化。
  • theta和phi是将三维空间点转换为笛卡尔坐标的角度值。theta通过Math.random()生成一个 0(包括)到 2 *
    Math.PI(不包括)之间的随机数,决定粒子在水平方向上的旋转角度;phi通过Math.acos((Math.random() * 2)- 1)生成,Math.random()生成 0(包括)到 1(不包括)之间的随机数,乘以 2 再减 1 得到 - 1(包括)到 1(不包括)之间的值,然后通过Math.acos函数得到 0(包括)到Math.PI(不包括)之间的角度,决定粒子在垂直方向上的角度,确保粒子在球面上均匀分布。
  • baseR是粒子围绕的基准半径,值为 200,用于控制粒子整体分布范围,所有粒子大致围绕这个半径形成一个球体。
  • speed是粒子旋转速度,通过Math.random()生成随机小数,乘以 0.001 再加上 0.0005,速度范围在 0.0005 到
    0.0015 之间,使粒子运动速度有差异。
  • baseColor是粒子基础颜色,红色和绿色分量通过Math.random()生成随机数,范围在 155 到 255 之间,蓝色分量固定为
    255,从而创建出不同蓝色调的粒子。

2.2,粒子位置更新

update(breathe) {this.theta += this.speed;const r = this.baseR * (1 + breathe * 0.2);this.x = r * Math.sin(this.phi) * Math.cos(this.theta);this.y = r * Math.sin(this.phi) * Math.sin(this.theta);this.z = r * Math.cos(this.phi);
}

update方法用于更新粒子位置。breathe参数控制粒子球呼吸效果,它是通过Math.sin函数生成的在 -1 到 1 之间波动的值。随着时间推移,theta不断增加(增加量为this.speed),使粒子围绕球体中心旋转。r的值根据breathe调整,breathe为正时,r增大,粒子向外扩张;breathe为负时,r减小,粒子向内收缩,实现粒子球缩放效果。最后通过三角函数将极坐标转换为笛卡尔坐标,更新粒子的x、y、z位置。

2.3,粒子绘制

draw() {// 增强透视效果const perspective = 800;const scale = perspective / (perspective + this.z);const x2d = canvas.width/2 + this.x * scale;const y2d = canvas.height/2 + this.y * scale;// 根据深度调整颜色和大小const depth = (this.z + this.baseR) / (this.baseR * 2);const alpha = 0.8 + (depth * 0.2);const radiusScale = this.radius * scale * (0.8 + depth * 0.4);// 计算深度相关的颜色const depthFactor = 0.3 + depth * 0.7;const color = {r: this.baseColor.r * depthFactor,g: this.baseColor.g * depthFactor,b: this.baseColor.b * depthFactor};ctx.beginPath();ctx.arc(x2d, y2d, radiusScale, 0, Math.PI * 2);ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${alpha})`;ctx.fill();// 为前景粒子添加发光效果if (depth > 0.8) {ctx.shadowBlur = 5;ctx.shadowColor = `rgba(${color.r}, ${color.g}, ${color.b}, 0.5)`;} else {ctx.shadowBlur = 0;}
}

draw方法负责将粒子绘制到canvas上。首先,通过透视变换公式计算粒子在 2D 画布上的位置x2d和y2d。这里perspective值设为 800,它模拟人眼到屏幕的距离,scale通过perspective / (perspective + this.z)计算得出,z值越大(粒子越远),scale越小,实现近大远小的透视效果。x2d和y2d通过画布中心坐标加上this.x和this.y乘以scale得到,确定粒子在画布上的实际绘制位置。
然后,根据粒子深度depth调整粒子透明度alpha、半径缩放radiusScale以及颜色。depth通过(this.z + this.baseR) / (this.baseR * 2)计算,范围在 0 到 1 之间,越接近 1 表示粒子越靠近观察者。alpha从 0.8 开始,随着depth增加而增大,使远处粒子更透明;radiusScale不仅考虑了scale,还根据depth进一步缩放,让近处粒子更大;depthFactor用于调整颜色,使近处粒子颜色更鲜艳。
最后,使用ctx.arc方法绘制粒子,并根据depth判断是否为粒子添加发光效果。当depth > 0.8时,为粒子添加模糊半径为 5、颜色为当前粒子颜色半透明的阴影,增强视觉层次感。

3、动画循环与管理

3.1,粒子数组创建与初始化

const particles = [];
const particleCount = 1500;
for(let i = 0; i < particleCount; i++) {particles.push(new Particle());
}

这里创建了一个包含 1500 个粒子的数组particles,通过循环实例化每个粒子并添加到数组中,这些粒子将共同构成呼吸粒子球。

3.2,动画循环函数

let time = 0;
function animate() {// 使用渐变背景增强深度感ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';ctx.fillRect(0, 0, canvas.width, canvas.height);// 按照z轴深度排序粒子particles.sort((a, b) => b.z - a.z);const breathe = Math.sin(time * 0.01);// 更新和绘制所有粒子particles.forEach(particle => {particle.update(breathe);particle.draw();});time++;requestAnimationFrame(animate);
}animate();

animate函数是动画的核心循环。每次循环:

  • 首先使用ctx.fillRect方法填充一个半透明黑色背景(rgba(0, 0, 0,
    0.3)),模拟深度感并清除上一帧绘制内容,为新的一帧绘制做准备。
  • 然后对粒子数组按z轴深度排序,particles.sort((a, b) => b.z -
    a.z)确保距离观察者近的粒子在上面绘制,实现正确遮挡效果,符合现实中物体的遮挡逻辑。
  • 通过Math.sin(time * 0.01)计算breathe的值,time每次循环自增 1,time *0.01作为Math.sin函数的参数,使breathe的值在 -1 到 1 之间周期性变化,控制粒子球呼吸节奏。
  • 遍历粒子数组,依次调用每个粒子的update和draw方法,更新粒子位置并绘制到画布上,让每个粒子都能按照设定的逻辑进行运动和显示。
  • 最后,time自增,并使用requestAnimationFrame方法请求浏览器在下一次重绘前调用animate函数,该方法会根据浏览器的刷新频率来优化动画性能,实现流畅动画效果,通常浏览器刷新频率为60Hz,即每秒 60 帧。

3.3,窗口大小响应

window.addEventListener('resize', () => {canvas.width = window.innerWidth;canvas.height = window.innerHeight;
});

为确保动画在不同窗口大小下正常显示,添加窗口大小变化监听器。当窗口大小改变时,重新设置canvas的宽度和高度为当前窗口的宽高,使动画始终适应屏幕尺寸,保证用户在不同设备和窗口状态下都能获得良好的视觉体验。

4、总结

通过对呼吸粒子球动画效果实现原理的详细分析,我们清晰看到如何利用 HTML5 Canvas 的 2D 绘图功能,结合 JavaScript 的数学计算和动画控制,创建出具有立体感和动态效果的粒子动画。从粒子属性初始化、位置更新、绘制,到动画循环管理以及窗口大小响应,每个环节紧密配合,共同打造出迷人的呼吸粒子球效果。希望本文能助您更好地理解和运用 HTML5 Canvas 进行动画开发,为网页增添更多精彩视觉效果。

完整的源码获取、技术问题讨论,请大家在评论区留言!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】引用(上)

1、引用的基本使用 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型&#xff08;该数据类型要与原名的数据类型一致&#xff09; &别名原名&#xff1b; 示例&#xff1a; #include<iostream> using namespace std; int main() {int a 10;int& …

JDBC实验测试

一、语言和环境 实现语言&#xff1a;Java。 环境要求&#xff1a;IDEA2023.3、JDK 17 、MySQL8.0、Navicat 16 for MySQL。 二、技术要求 该系统采用 SWING 技术配合 JDBC 使用 JAVA 编程语言完成桌面应用开发。 三、功能要求 某电商公司为了方便客服查看用户的订单信…

外包公司名单一览表(成都)

大家好&#xff0c;我是苍何。 之前写了一篇武汉的外包公司名单&#xff0c;评论区做了个简单统计&#xff0c;很多人说&#xff0c;在外包的日子很煎熬&#xff0c;不再想去了。 有小伙伴留言说有些外包会强制离职&#xff0c;不行就转岗&#xff0c;让人极度没有安全感。 这…

一些硬件知识【2025/1/21】

小米2K摄像头拆解&#xff1a; 这种小转接板空余部分一般全部打上过孔&#xff1a; 摄像头下面的SENSOR,这一部分才是摄像头的核心&#xff1a; 干硬件多久跳槽一次比较合适&#xff1f;3年跳一次可以吗&#xff1f; eMCC存储芯片外面那一圈焊盘是做什么用的&#xff1f; 没有…

WPF实战案例 | C# WPF实现计算器源码

WPF实战案例 | C# WPF实现计算器源码 一、设计来源计算器应用程序讲解1.1 主界面1.2 计算界面 二、效果和源码2.1 界面设计&#xff08;XAML&#xff09;2.2 代码逻辑&#xff08;C#&#xff09;2.3 实现步骤总结 源码下载更多优质源码分享 作者&#xff1a;xcLeigh 文章地址&a…

【HBuilderX 中 Git 的使用】

目录&#xff1a; 一&#xff1a;安装必要的版本控制工具二&#xff1a;把Github上的项目克隆到本地三&#xff1a;将本地的项目上传到Github上 一&#xff1a;安装必要的版本控制工具 1️⃣ 安装 TortoiseGit 工具&#xff0c;下载地址&#xff1a;https://tortoisegit.org/do…

浅谈 JVM

JVM 内存划分 JVM 内存划分为 四个区域&#xff0c;分别为 程序计数器、元数据区、栈、堆 程序计数器是记录当前指令执行到哪个地址 元数据区存储存储的是当前类加载好的数据&#xff0c;包括常量池和类对象的信息&#xff0c;.java 编译之后产生 .class 文件&#xff0c;运…

OpenCV简介、OpenCV安装

OpenCV简介、OpenCV安装 本文目录&#xff1a; 零、时光宝盒 一、OpenCV简介 二、OpenCV图像处理基础知识 三、OpenCV-Python环境安装 2.1、纯python环境下安装OpenCV 2.2、Anaconda管理环境下安装 OpenCV 四、如何用OpenCV 中进行读取展示图像 五、OpenCV读取图像、显…

使用Chrome和Selenium实现对Superset等私域网站的截图

最近遇到了一个问题&#xff0c;因为一些原因&#xff0c;我搭建的一个 Superset 的 Report 功能由于节假日期间不好控制邮件的发送&#xff0c;所以急需一个方案来替换掉 Superset 的 Report 功能 首先我们需要 Chrome 浏览器和 Chrome Driver&#xff0c;这是执行数据抓取的…

算法专题(三):二分查找

本篇还是像之前一样&#xff0c;以举例子的形式向大家讲解&#xff01;每道题的题目均是传送门&#xff01;点击跳转对应题&#xff01; 目录 一、二分查找 1.1 题目 1.2 思路 1.3 代码实现 总结&#xff08;模版&#xff09; 朴素版&#xff1a; 二、在排序数组中查找…

在k8s中部署一个可外部访问的Redis Sentinel

1.前提条件&#xff1a; 1.部署了multus 想要k8s外部能访问k8s内部的redis&#xff0c;redis-server启动时必须使用multus的IP 2.helm客户端安装 2.开始安装 准备3个multus ip 10.10.10.130 10.10.10.131 10.10.10.132 apiVersion: k8s.cni.cncf.io/v1 kind: NetworkAttac…

使用tritonserver完成clip-vit-large-patch14图像特征提取模型的工程化。

1、关于clip-vit-large-patch14模型 关于openapi开源的clip-vit-large-patch14模型的特征提取&#xff0c;可以参考之前的文章&#xff1a;Elasticsearch向量检索需要的数据集以及768维向量生成这篇文章详细介绍了模型的下载地址、使用方式、测试脚本&#xff0c;可以让你一步…

偏序关系.

一、偏序&#xff08;半序&#xff09;关系 偏序关系 自反反对称传递性 二、全序&#xff08;线序、链&#xff09;关系 三、偏序集中的重要元素 1. 极大元与极小元 极大元找所在集合的一个或几个最高点&#xff1b; 极小元找所在集合的一个或几个最低点。 2. 最大元与最小…

2024嵌入式系统的未来发展与技术洞察分享

时间如白驹过隙&#xff0c;不知不觉又是一年&#xff0c;这一年收获满满。接下来&#xff0c;将本年度对技术的感悟和洞察分析如下&#xff0c;希望对大家有所帮助。 在过去几十年里&#xff0c;嵌入式系统技术迅速发展&#xff0c;成为现代电子设备和智能硬件的核心组成部分。…

AQS公平锁与非公平锁之源码解析

AQS加锁逻辑 ReentrantLock.lock public void lock() {sync.acquire(1);}AbstractQueuedSynchronizer#acquire public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}addWaiter就是将节点加入…

数字电子技术基础(十五)——MOS管的简单介绍

目录 1 MOS的简单介绍 1.1 MOS简介 1.2 MOS管的基本结构 1.3 MOS管工作时的三个区域 1.4 MOSEF的结构的工作原理 1 MOS的简单介绍 1.1 MOS简介 绝缘栅型场效应管&#xff0c;简称MOS管&#xff0c;全称为金属-氧化物-半导体场效应晶体管&#xff08;Metal-Oxide-Semic…

基础入门-传输加密数据格式编码算法密文存储代码混淆逆向保护安全影响

知识点&#xff1a; 1、传输格式&传输数据-类型&编码&算法 2、密码存储&代码混淆-不可逆&非对称性 一、演示案例-传输格式&传输数据-类型&编码&算法 传输格式 JSON XML WebSockets HTML 二进制 自定义 WebSockets&#xff1a;聊天交互较常…

Spark/Kafka

文章目录 项目地址一、Spark1. RDD1.1 五大核心属性1.2 执行原理1.3 四种创建方式二、Kafka2.1 生产者(1)分区器(2)生产者提高吞吐量(3) 生产者数据可靠性数据传递语义幂等性和事务数据有序2.2 Broker(1)Broker工作流程(2)节点服役和退役2.3 副本(1)Follower故障细…

10倍数据交付提升 | 通过逻辑数据仓库和数据编织高效管理和利用大数据

数据已经成为企业核心竞争力的关键要素。随着大数据技术的发展&#xff0c;如何高效管理和利用海量的数据&#xff0c;已成为企业在数字化转型过程中面临的重要课题。传统的数据仓库已经不能满足当今企业对数据处理的高效性、灵活性和实时性的需求。在这种背景下&#xff0c;逻…

《keras 3 内卷神经网络》

keras 3 内卷神经网络 作者&#xff1a;Aritra Roy Gosthipaty 创建日期&#xff1a;2021/07/25 最后修改时间&#xff1a;2021/07/25 描述&#xff1a;深入研究特定于位置和通道无关的“内卷”内核。 &#xff08;i&#xff09; 此示例使用 Keras 3 在 Colab 中查看 GitHub …