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

news2025/1/24 6:33:57

在网页开发领域,动画效果能够极大地提升用户体验,让页面变得更加生动有趣。今天,我们深入剖析一个基于 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.coloradmin.cn/o/2281270.html

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

相关文章

【Linux】其他备选高级IO模型

其他高级 I/O 模型 以上基本介绍的都是同步IO相关知识点&#xff0c;即在同步I/O模型中&#xff0c;程序发起I/O操作后会等待I/O操作完成&#xff0c;即程序会被阻塞&#xff0c;直到I/O完成。整个I/O过程在同一个线程中进行&#xff0c;程序在等待期间不能执行其他任务。下面…

Arduino D1 通过 Wi-Fi 控制 LED

Arduino D1 通过 Wi-Fi 控制 LED 硬件连接 将 LED 的正极&#xff08;长脚&#xff09;连接到 Arduino D1 的 D1 引脚。将 LED 的负极&#xff08;短脚&#xff09;通过一个电阻&#xff08;例如 220 欧姆&#xff09;连接到 Arduino D1 的 GND 引脚。 安装必要的库 在 Ard…

Flutter:自定义Tab切换,订单列表页tab,tab吸顶

1、自定义tab切换 view <Widget>[// 好评<Widget>[TDImage(assetUrl: assets/img/order4.png,width: 36.w,height: 36.w,),SizedBox(width: 10.w,),TextWidget.body(好评,size: 24.sp,color: controller.tabIndex 0 ? AppTheme.colorfff : AppTheme.color999,),]…

Tailscale 配置 subnet 实现访问 Openwrt 路由器下的子网

Openwrt 安装 Tailscale 参考 OpenWrt 配置 Tailscale 内网穿透。 tailscale两台openwrt(双lan)网对网(site to site)互通OpenWrt安装配置Tailscale 在 OpenWrt 上使用 Tailscale 使用 tailscale subnet 在openwrt terminal 执行 tailscale up --advertise-routes192.168.…

低代码可视化-转盘小游戏可视化-代码生成器

转盘小程序是一种互动工具&#xff0c;它通过模拟真实的转盘抽奖或决策体验&#xff0c;为用户提供了一种有趣且公平的选择方式。以下是对转盘小程序的详细介绍&#xff1a; 转盘小程序的应用场景 日常决策&#xff1a;转盘小程序可以帮助用户解决日常生活中的选择困难问题&a…

【Uniapp-Vue3】uni-icons的安装和使用

一、uni-icon的安装 进入到如下页面中&#xff0c;点击“点击下载&安装”。 uni-icons 图标 | uni-app官网 点击“下载插件并导入HBuilder”&#xff0c;如果没有登录就登陆一下 网页中会打开Hbuilder&#xff0c;进入Hbuilder以后&#xff0c;选择需要使用该插件的项目进…

【橘子ES】Kibana的分析能力Analytics简易分析

一、kibana是啥&#xff0c;能干嘛 我们经常会用es来实现一些关于检索&#xff0c;关于分析的业务。但是es本身并没有UI,我们只能通过调用api来完成一些能力。而kibana就是他的一个外置UI&#xff0c;你完全可以这么理解。 当我们进入kibana的主页的时候你可以看到这样的布局。…

一、引论,《组合数学(第4版)》卢开澄 卢华明

零、前言 发现自己数数题做的很烂&#xff0c;重新学一遍组合数学吧。 参考卢开澄 卢华明 编著的《组合数学(第4版)》&#xff0c;只打算学前四章。 通过几个经典问题来了解组合数学所研究的内容。 一、幻方问题 据说大禹治水之前&#xff0c;河里冒出来一只乌龟&#xff0c…

LabVIEW太阳能照明监控系统

在公共照明领域&#xff0c;传统的电力照明系统存在高能耗和维护不便等问题。利用LabVIEW开发太阳能照明监控系统&#xff0c;通过智能控制和实时监测&#xff0c;提高能源利用效率&#xff0c;降低维护成本&#xff0c;实现照明系统的可持续发展。 ​ 项目背景 随着能源危机…

5. 马科维茨资产组合模型+政策意图AI金融智能体(Qwen-Max)增强方案(理论+Python实战)

目录 0. 承前1. AI金融智能体1.1 What is AI金融智能体1.2 Why is AI金融智能体1.3 How to AI金融智能体 2. 数据要素&计算流程2.1 参数集设置2.2 数据获取&预处理2.3 收益率计算2.4 因子构建与预期收益率计算2.5 协方差矩阵计算2.6 投资组合优化2.7 持仓筛选2.8 AI金融…

【华为路由的arp配置】

华为路由的arp配置 ARP&#xff1a;IP地址与MAC地址的映射。 R1: g0/0/0:10.1.1.254/24 g0/0/1:10.1.2.254/24 PC1: 10.1.1.1/16 PC2: 10.1.1.2/16 PC3: 10.1.2.3/16 动态ARP 查看PC1的arp表&#xff0c;可以看到&#xff0c;列表为空。 查看R1的arp表 在PC3上ping命令测…

U3D的.Net学习

Mono&#xff1a;这是 Unity 最初采用的方式&#xff0c;它将 C# 代码编译为中间语言 (IL)&#xff0c;然后在目标平台上使用虚拟机 (VM) 将其转换为本地机器码执行。 IL2CPP&#xff1a;这是一种较新的方法&#xff0c;它会将 C# 代码先编译为 C 代码&#xff0c;再由 C 编译器…

机器学习-线性回归(简单回归、多元回归)

这一篇文章&#xff0c;我们主要来理解一下&#xff0c;什么是线性回归中的简单回归和多元回归&#xff0c;顺便掌握一下特征向量的概念。 一、简单回归 简单回归是线性回归的一种最基本形式&#xff0c;它用于研究**一个自变量&#xff08;输入&#xff09;与一个因变量&…

智能体的核心技能之插件,插件详解和实例 ,扣子免费系列教程(11)

欢迎来到滔滔讲AI&#xff0c;今天我们来学习智能体的核心功能点之一的插件。 插件是通过API连接集成各种平台和服务&#xff0c;它扩展了智能体的能力。平台内置了丰富的插件&#xff0c;我们可以直接调用。 一、什么是插件 首先&#xff0c;插件其实就像一个工具箱。 每个插…

Spring Security(maven项目) 3.0.2.6版本—总

通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往复以至无穷&#xf…

超强推理大模型 QVQ-32B-preview 一键部署

QwQ-32B-Preview 是 Qwen 团队于 2024 年开发的实验研究模型&#xff0c;专注于提高 AI 推理能力。这个模型在多个基准测试中展现了卓越的性能&#xff0c;特别是在 GPQA、AIME、MATH-500 和 LiveCodeBench 等测试中&#xff0c;准确率分别达到了 65.2%、50.0%、90.6% 和 50.0%…

数据结构(Java)——二叉树

1.概念 二叉树是一种树形数据结构&#xff0c;其中每个节点最多有两个子节点&#xff0c;通常被称为左子节点和右子节点。二叉树可以是空的&#xff08;即没有节点&#xff09;&#xff0c;或者由一个根节点以及零个或多个左子树和右子树组成&#xff0c;其中左子树和右子树也分…

谷粒商城——商品服务-三级分类

1.商品服务-三级分类 1.1三级分类介绍 1.2查询三级分类查询-递归树型结构数据获取 1.2.1导入数据pms_catelog.sql到数据表pms_category 1.2.2一次性查出所有分类及子分类 1.2.2.1修改CategoryController.java /*** 查出所有分类以及子分类&#xff0c;以树形结构组装起来*/R…

AviatorScript用法

AviatorScript的介绍&#xff0c;网上有很多&#xff0c;这里就不啰嗦了。这里介绍下传参的用法 应用场景&#xff1a;如果不想频繁的打包升级&#xff0c;而是想只更新某些规则脚本重启服务就可以升级的话&#xff0c;AviatorScript无疑是最佳选择。比如说&#xff0c;今天制…

云计算和服务器

一、云计算概述 ICT是世界电信协会在2001年的全球性会议上提出的综合性概念&#xff0c;ICT分为IT和CT&#xff0c;IT(information technology)信息技术&#xff0c;负责对数据生命周期的管理&#xff1b;CT(communication technology)&#xff0c;负责数据的传输管理。 CT技术…