Canvas生成动画---显示一组彩色气泡

 一、JS版本

<!--* @Author: LYM* @Date: 2024-07-26 13:51:47* @LastEditors: LYM* @LastEditTime: 2024-07-26 16:14:40* @Description: Please set Description
-->
<!DOCTYPE html>
<html>
<head><title>canvas动态气泡</title><style>body {margin: 0;overflow: hidden;}#jellyCanvas {display: block;width: 100%;height: 100%;}.container {width: 780px;height: 780px;margin: 0 auto;border-radius: 99px;filter: blur(64px);opacity: 1;}</style>
</head>
<body><div class="container"><canvas id="jellyCanvas"></canvas></div><script>// 获取Canvas元素和2D绘图上下文const canvas = document.getElementById('jellyCanvas');const ctx = canvas.getContext('2d');// 定义泡泡数组const bubbles = [];// 定义泡泡数量const numBubbles = 5;// 定义泡泡最大半径和最小半径const maxRadius = 50;const minRadius = 20;// 定义泡泡颜色const colors = ['#45abb5', '#abb3ff', '#73d4c7', '#abb3ff', '#455ed4'];// 定义一个函数来生成随机数function random(min, max) {return Math.random() * (max - min) + min;}// 设置2秒完成该动画const animationDuration = 2000;let startTime;// 定义一个构造函数来创建泡泡对象function Bubble(x, y, radius, color) {this.x = x;this.y = y;this.radius = radius;this.color = color;this.dx = random(-2, 2);this.dy = random(-2, 2);// 绘制泡泡this.draw = function () {ctx.beginPath();ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);// ctx.shadowColor = this.color;// ctx.shadowBlur = 20;ctx.fillStyle = this.color;ctx.fill();ctx.closePath();};// 更新泡泡位置this.update = function () {this.x += this.dx;this.y += this.dy;// 碰撞检测if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {this.dx = -this.dx;}if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {this.dy = -this.dy;}};}// 创建泡泡并添加到数组中for (let i = 0; i < numBubbles; i++) {const x = random(maxRadius, canvas.width - maxRadius);const y = random(maxRadius, canvas.height - maxRadius);const radius = random(minRadius, maxRadius);const color = colors[Math.floor(random(0, colors.length))];bubbles.push(new Bubble(x, y, radius, color));}// 动画循环function animate() {// requestAnimationFrame(animate);  // 动画速度太快 但是性能比较好setInterval(function(){ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制和更新每个泡泡for (let i = 0; i < numBubbles; i++) {bubbles[i].draw();bubbles[i].update();}}, 100)}// 启动动画animate();</script>
</body>
</html>
<!DOCTYPE html>  
<html lang="en">  
<head>  
<meta charset="UTF-8">  
<title>彩色气泡动画</title>  
<style>  canvas {  border: 1px solid black;  }.container {width: 800px;height: 800px;margin: 0 auto;border-radius: 50%;/* filter: blur(64px); */opacity: 1;}
</style>  
</head>  
<body><div class="container"><canvas id="bubbleCanvas" width="800" height="800"></canvas>  </div><script>class Bubble {  constructor(x, y, radius, color, speedX, speedY) {  this.x = x;  this.y = y;  this.radius = radius;  this.color = color;  this.speedX = speedX;  this.speedY = speedY;  }  update() {  this.x += this.speedX;  this.y += this.speedY;  // 气泡碰到边界时反弹  if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {  this.speedX = -this.speedX;  }  if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {  this.speedY = -this. Speedy;  }  }  draw() {  ctx.beginPath();  ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);  ctx.fillStyle = this.color;  ctx.fill();  ctx.closePath();  }  
}  const canvas = document.getElementById('bubbleCanvas');  
const ctx = canvas.getContext('2d');  const bubbles = [];  // 初始化气泡  
function initBubbles() {  for (let i = 0; i < 5; i++) {  let radius = Math.random() * 50 + 40; // 气泡大小  let x = Math.random() * (canvas.width - radius * 2) + radius;  let y = Math.random() * (canvas.height - radius * 2) + radius;  let color = `rgba(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, 0.8)`;  let speedX = (Math.random() - 0.5) * 2;  let speedY = (Math.random() - 0.5) * 2;  bubbles.push(new Bubble(x, y, radius, color, speedX, speedY));  }  
}  initBubbles();  function animate() {  ctx.clearRect(0, 0, canvas.width, canvas.height);  bubbles.forEach(bubble => {  bubble.update();  bubble.draw();  });  requestAnimationFrame(animate);  
}  animate();
</script>  
</body>  
</html>

 

二、TS版本 

/** @Author: LYM* @Date: 2024-07-26 15:08:43* @LastEditors: LYM* @LastEditTime: 2024-07-26 17:18:06* @Description: 生成动画显示一组彩色气泡*/
/*** 生成动画显示一组彩色气泡* @param params 参数对象,用于控制气泡的生成和显示* @param params.el HTML canvas元素* @param params.colors 气泡的颜色数组,默认为粉色系颜色* @param params.numBubbles 生成的气泡数量,默认为5* @param params.maxRadius 气泡的最大半径,默认为50* @param params.minRadius 气泡的最小半径,默认为20*/
export const generatedBubbles = (params: {el: anycolors: Array<string>numBubbles: numbermaxRadius: numberminRadius: number
}) => {const {el,colors = ['#45abb5', '#47c2b5', '#73d4c7', '#a3f7ed', '#455ed4'],numBubbles = 5,maxRadius = 50,minRadius = 20,} = params ?? {}// 获取Canvas元素和2D绘图上下文const canvas = el as anyconst ctx = canvas.getContext('2d')// 定义泡泡数组const bubbles = [] as Array<any>// 定义一个函数来生成随机数const random = (min: number, max: number) => {return Math.random() * (max - min) + min}// 定义一个构造函数来创建泡泡类class Bubble {x: numbery: numberradius: numbercolor: stringconstructor(x: number, y: number, radius: number, color: string) {this.x = xthis.y = ythis.radius = radiusthis.color = color}dx = random(-2, 2)dy = random(-2, 2)// 绘制泡泡draw() {ctx.beginPath()ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2)// ctx.shadowColor = this.color;// ctx.shadowBlur = 20;ctx.fillStyle = this.colorctx.fill()ctx.closePath()}// 更新泡泡位置update() {this.x += this.dxthis.y += this.dy// 碰撞检测if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {this.dx = -this.dx}if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {this.dy = -this.dy}}}// 创建泡泡并添加到数组中for (let i = 0; i < numBubbles; i++) {const x = random(maxRadius, canvas.width - maxRadius)const y = random(maxRadius, canvas.height - maxRadius)const radius = random(minRadius, maxRadius)const color = colors[Math.floor(random(0, colors.length))]bubbles.push(new Bubble(x, y, radius, color))}// 动画循环const animate = () => {// requestAnimationFrame(animate);  // 动画速度太快 但是性能比较好setInterval(() => {ctx.clearRect(0, 0, canvas.width, canvas.height)// 绘制和更新每个泡泡for (let i = 0; i < numBubbles; i++) {bubbles[i].draw()bubbles[i].update()}}, 90)}// 启动动画animate()
}
/** @Author: LYM* @Date: 2024-07-26 18:36:17* @LastEditors: LYM* @LastEditTime: 2024-07-26 18:59:04* @Description: 生成气泡动画*/
/*** 生成气泡动画** @param params 生成气泡动画的参数* @param params.el 绑定的canvas元素* @param params.colors 气泡颜色数组,默认为['#45abb5', '#abb3ff', '#47c2b5', '#5e73ff', '#8e59d7']* @param params.numBubbles 气泡数量,默认为5* @param params.baseRadius 基础半径,默认为10* @param params.speed 气泡移动速度,默认为1*/
export const generatedBubbles = (params: {el: anycolors: Array<string>numBubbles: numberbaseRadius: numberspeed: number
}) => {const {el,colors = ['#45abb5', '#abb3ff', '#47c2b5', '#5e73ff', '#8e59d7'],numBubbles = 5,baseRadius = 10,speed = 1,} = params ?? {}class Bubble {x: numbery: numberradius: numbercolor: stringspeedX: numberspeedY: numberconstructor(x: number,y: number,radius: number,color: string,speedX: number,speedY: number) {this.x = xthis.y = ythis.radius = radiusthis.color = colorthis.speedX = speedXthis.speedY = speedY}update() {this.x += this.speedXthis.y += this.speedY// 气泡碰到边界时反弹if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {this.speedX = -this.speedX}if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {this.speedY = -this.speedY}}draw() {ctx.beginPath()ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false)ctx.fillStyle = this.colorctx.fill()ctx.closePath()}}// 获取Canvas元素和2D绘图上下文const canvas = el as anyconst ctx = canvas.getContext('2d')// 定义泡泡数组const bubbles = [] as Array<any>// 初始化气泡for (let i = 0; i < numBubbles; i++) {const radius = Math.random() * baseRadius + 20 // 气泡大小const x = Math.random() * (canvas.width - radius * 2) + radiusconst y = Math.random() * (canvas.height - radius * 2) + radiusconst color = `rgba(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, 0.8)`const speedX = (Math.random() - 0.5) * speedconst speedY = (Math.random() - 0.5) * speedbubbles.push(new Bubble(x, y, radius, colors[i] ?? color, speedX, speedY))}const animate = () => {ctx.clearRect(0, 0, canvas.width, canvas.height)bubbles.forEach(bubble => {bubble.update()bubble.draw()})requestAnimationFrame(animate)}animate()
}

三、效果

四、解释

  1. Bubble 类:定义了气泡的属性(位置、半径、颜色、速度)和方法(更新位置、绘制)。
  2. initBubbles 函数:初始化一组气泡,随机设置它们的位置、大小、颜色和速度。
  3. animate 函数:清除画布,更新每个气泡的位置,绘制所有气泡,并使用requestAnimationFrame递归调用自身以创建动画效果。

这个简单的例子展示了如何在<canvas>上创建和动画化一组彩色气泡。你可以根据需要调整气泡的数量、大小、颜色、速度等属性,以及边界反弹的行为。

 

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

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

相关文章

Spring Boot的Web开发

目录 Spring Boot的Web开发 1.静态资源映射规则 第一种静态资源映射规则 2.enjoy模板引擎 3.springMVC 3.1请求处理 RequestMapping DeleteMapping 删除 PutMapping 修改 GetMapping 查询 PostMapping 新增 3.2参数绑定 一.支持数据类型: 3.3常用注解 一.Request…

Spark+实例解读

第一部分 Spark入门 学习教程&#xff1a;Spark 教程 | Spark 教程 Spark 集成了许多大数据工具&#xff0c;例如 Spark 可以处理任何 Hadoop 数据源&#xff0c;也能在 Hadoop 集群上执行。大数据业内有个共识认为&#xff0c;Spark 只是Hadoop MapReduce 的扩展&#xff08…

22 Python常用内置函数——枚举

enumerate() 函数用来枚举可迭代对象中的元素&#xff0c;返回可迭代的 enumerate 对象&#xff0c;其中每个元素都是包含索引和值的元组。 print(enumerate(abcd)) print(list(enumerate(abcd))) # 枚举字符串中的元素 print(list(enumerate([hello, world]))) # 枚举列表中…

【数据结构】:大厂面试经典链表OJ题目详解

反转链表 206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 思路解透 本题就是通过不停地将最先的 head 节点位置的后一位插到最前面&#xff0c;完成链表的反转 本题需要两个节点变量 cur&#xff1a;其任务就是定位到原 head 节点位置的前一位&#xff0c;然后将自己…

百日筑基第二十八天-23种设计模式-行为型总汇

百日筑基第二十八天-23种设计模式-行为型总汇 文章目录 百日筑基第二十八天-23种设计模式-行为型总汇前言模板方法模式简介模板方式的特点模板方法模式结构类图模板方式模式案例分析模板方法模式应用源码分析模板方法模式的注意事项和细节 迭代器模式迭代器模式结构类图迭代器模…

git配置环境变量

一.找到git安装目录 打开此git安装目录下的bin文件&#xff0c;复制此文件路径 二.配置环境变量 2.1 右键点击此电脑的属性栏 2.2 点击高级系统配置 2.3 点击环境变量 2.4 按图中步骤进行配置 三.配置完成 win r 输入cmd打开终端 终端页面中输入 git --version 如图所示…

给定日期计算时间(2025新年倒计时)

目录 1.安装所需安装包 2.查看安装包是否安装成功 ​ 3.使用 Pandas 读取数据文件 4.定义图像背景 5.matplotlib输出 6.当前指定格式时间 7.2025新年倒计时 1.安装所需安装包 pip install 包名 2.查看安装包是否安装成功 python -m pip list ​ 3.使用 Pandas 读取数…

深度解析Linux-C——结构体(初始化,结构体数组,结构体大小,位段操作,联合体,内存对齐,C的预处理,宏和带参宏,条件编译)

目录 结构体的三种初始化 结构体的两种引用 结构体数组 结构体大小 结构体实现位段操作 联合体 内存对齐 C的预处理 带参宏 条件编译 结构体的三种初始化 定义如下结构体 struct student {char name[100]; int age; float height; } ; 1、定义变量时初始化 s…

Redis从入门到超神-(十二)Redis监听Key的过期事件

前言 试想一个业务场景&#xff0c;订单超过30分钟未支付需要做自动关单处理,修改订单状态&#xff0c;库存回退等&#xff0c;你怎么实现&#xff1f;方案一&#xff1a;可以使用定时任务扫表&#xff0c;通过支付状态和下单时间来判断是否支付过期。但是这样的方案是非常消耗…

推荐一款.NET开源、简洁易用的Windows桌面小说阅读应用

前言 今天大姚给大家分享一款.NET开源、免费、简洁易用的Windows桌面小说阅读应用(是原生的 Windows 应用&#xff0c;为 Windows 11 系统设计)&#xff1a;CleanReader.Desktop。 该应用适合喜欢阅读网文或者是本地轻量阅读的用户。 系统要求 操作系统&#xff1a;Windows 11…

Llama + Dify,在你的电脑搭建一套AI工作流

theme: smartblue 点赞 关注 收藏 学会了 本文简介 最近字节在推Coze&#xff0c;你可以在这个平台制作知识库、制作工作流&#xff0c;生成一个具有特定领域知识的智能体。 那么&#xff0c;有没有可能在本地也部署一套这个东西呢&#xff1f;这样敏感数据就不会泄露了&…

Linux之基础IO(下)

目录 缓冲区的概念 深入理解文件系统 创建文件的整个过程 软链接 硬链接 上一节课我们学习了基础IO中的文件的读写操作&#xff0c;以及文件描述符的概念和重定向的基本原理&#xff0c;本期我们继续进行基础IO的学习。 缓冲区的概念 在讲缓冲区之前&#xff0c;大家先看…

Redis实战篇(黑马点评)笔记总结

一、配置前后端项目的初始环境 前端&#xff1a; 对前端项目在cmd中进行start nginx.exe&#xff0c;端口号为8080 后端&#xff1a; 配置mysql数据库的url 和 redis 的url 和 导入数据库数据 二、登录校验 基于Session的实现登录&#xff08;不推荐&#xff09; &#xf…

C++ - char*、const char*、char[]、string

const char* const char* 用来定义字符串常量。 char[ ] char型的字符数组是一种定长的数组&#xff0c;存储指定长度的字符序列&#xff0c;数组中的每个元素都是一个char类型的变量&#xff0c;如&#xff1a; char arr[] {h, a, l, l, o, \0}; char c arr[0]; // 访问…

使用 Windows 应用程序 SDK 构建下一代应用程序

微软面临的最大问题之一是如何让 Windows 再次成为吸引开发者的平台。无论用户使用什么设备和操作系统&#xff0c;都可以很容易地将 Web 前端放在支持桌面和移动用户的云原生应用程序上。 我们处在一个奇怪的境地&#xff0c;唯一能利用最新 PC 硬件的应用程序是 Office、Phot…

【中项第三版】系统集成项目管理工程师 | 第 11 章 规划过程组⑤ | 11.13 - 11.14

前言 第11章对应的内容选择题和案例分析都会进行考查&#xff0c;这一章节属于10大管理的内容&#xff0c;学习要以教材为准。本章上午题分值预计在15分。 目录 11.13 制定预算 11.13.1 主要输入 11.13.2 主要输出 11.14 规划质量管理 11.14.1 主要输入 11.14.2 主要工…

HTML前端面试题之<iframe>标签

面试题&#xff1a;iframe 标签的作用是什么?有哪些优缺点 ? 讲真&#xff0c;刷这道面试题之前我根本没有接触过iframe&#xff0c;网课没讲过&#xff0c;项目实战没用过&#xff0c;但却在面试题里出现了&#xff01;好吧&#xff0c;我只能说&#xff1a;前端路漫漫&…

数据挖掘-数据预处理

来自&#x1f96c;&#x1f436;程序员 Truraly | 田园 的博客&#xff0c;最新文章首发于&#xff1a;田园幻想乡 | 原文链接 | github &#xff08;欢迎关注&#xff09; 文章目录 3.3.1 数据的中心趋势平均数和加权平均数众数&#xff0c;中位数和均值描述数据的离散程度 &a…

快速搞定分布式RabbitMQ---RabbitMQ进阶与实战

本篇内容是本人精心整理&#xff1b;主要讲述RabbitMQ的核心特性&#xff1b;RabbitMQ的环境搭建与控制台的详解&#xff1b;RabbitMQ的核心API&#xff1b;RabbitMQ的高级特性;RabbitMQ集群的搭建&#xff1b;还会做RabbitMQ和Springboot的整合&#xff1b;内容会比较多&#…

火山引擎云搜索服务通过信通院向量数据库可信认证

7月16日&#xff0c;首届线下“可信数据库发展大会”在北京举办&#xff0c;会上中国信息通信研究院&#xff08;中国信通院&#xff09;公布了 2024 上半年“可信数据库”产品能力评测结果。火山引擎云搜索服务在基本功能、运维管理、安全性、兼容性、扩展性、高可用、工具生态…