html烟花代码在线编程,canvas实现烟花的示例代码

2023-11-11

前言:马上过年了,我打算在后台里面偷偷地埋个新春祝福+放烟花的彩蛋。项目是基于react+typescript的,因此最后封装成了一个组件,设置好开启时间就可以显示了。

目录结构

目录结构大致如下

fc88291da722caf3771290ec09973d88.png

我们将烟花分为两个阶段,一个是未炸开持续上升时期,另一个是炸开后分散的时期。

其中Vector表示一个坐标,Particle表示一个烟花的亮点,Firewor表示烟花未炸开时持续上升的亮点。index.tsx就是组件了,绘制了canvas,并执行了动画。

Vector

这个坐标就很简单,后面涉及到位置的变更都可以使用它的add方法进行偏移操作

export default class Vector {

constructor(public x: number, public y: number) {}

add(vec2: {x: number; y: number}) {

this.x = this.x + vec2.x;

this.y = this.y + vec2.y;

}

}

Particle

初始创建的时候给个坐标,后续每次更新的时候控制y坐标下落,gravity变量就是下落的值。timeSpan用于控制烟花展示的时长

import Vector from './Vector';

export default class Particle {

pos: Vector = null;

vel: {x: number; y: number} = null;

dead: boolean = false;

start: number = 0;

ctx: CanvasRenderingContext2D = null;

constructor(pos: {x: number; y: number}, vel: {x: number; y: number}, ctx: CanvasRenderingContext2D) {

this.pos = new Vector(pos.x, pos.y);

this.vel = vel;

this.dead = false;

this.start = 0;

this.ctx = ctx;

}

update(time: number, gravity: number) {

let timeSpan = time - this.start;

if (timeSpan > 500) {

this.dead = true;

}

if (!this.dead) {

this.pos.add(this.vel);

this.vel.y = this.vel.y + gravity;

}

}

draw() {

if (!this.dead) {

this.drawDot(this.pos.x, this.pos.y, Math.random() > 0.5 ? 1 : 2);

}

}

drawDot(x: number, y: number, size: number) {

this.ctx.beginPath();

this.ctx.arc(x, y, size, 0, Math.PI * 2);

this.ctx.fill();

this.ctx.closePath();

}

}

Firework

生成随机的hsl颜色,hsl(' + rndNum(360) + ', 100%, 60%);Firework每次上升的距离是一个递减的过程,我们初始设置一个上升的距离,之后每次绘制的时候,这个距离减gravity,当距离小于零的时候,说明该出现烟花绽放的动画了。

import Vector from './Vector';

import Particle from './Particle';

let rnd = Math.random;

function rndNum(num: number) {

return rnd() * num + 1;

}

export default class Firework {

pos: Vector = null;

vel: Vector = null;

color: string = null;

size: number = 0;

dead: boolean = false;

start: number = 0;

ctx: CanvasRenderingContext2D = null;

gravity: number = null;

exParticles: Particle[] = [];

exPLen: number = 100;

rootShow: boolean = true;

constructor(x: number, y: number, gravity: number, ctx: CanvasRenderingContext2D) {

this.pos = new Vector(x, y);

this.vel = new Vector(0, -rndNum(10) - 3);

this.color = 'hsl(' + rndNum(360) + ', 100%, 60%)';

this.size = 4;

this.dead = false;

this.start = 0;

this.ctx = ctx;

this.gravity = gravity;

}

update(time: number, gravity: number) {

if (this.dead) {

return;

}

this.rootShow = this.vel.y < 0;

if (this.rootShow) {

this.pos.add(this.vel);

this.vel.y = this.vel.y + gravity;

} else {

if (this.exParticles.length === 0) {

for (let i = 0; i < this.exPLen; i++) {

let randomR = rndNum(5);

let randomX = -rndNum(Math.abs(randomR) * 2) + Math.abs(randomR);

let randomY =

Math.sqrt(Math.abs(Math.pow(randomR, 2) - Math.pow(randomX, 2))) *

(Math.random() > 0.5 ? 1 : -1);

this.exParticles.push(new Particle(this.pos, new Vector(randomX, randomY), this.ctx));

this.exParticles[this.exParticles.length - 1].start = time;

}

}

let numOfDead = 0;

for (let i = 0; i < this.exPLen; i++) {

let p = this.exParticles[i];

p.update(time, this.gravity);

if (p.dead) {

numOfDead++;

}

}

if (numOfDead === this.exPLen) {

this.dead = true;

}

}

}

draw() {

if (this.dead) {

return;

}

this.ctx.fillStyle = this.color;

if (this.rootShow) {

this.drawDot(this.pos.x, this.pos.y, this.size);

} else {

for (let i = 0; i < this.exPLen; i++) {

let p = this.exParticles[i];

p.draw();

}

}

}

drawDot(x: number, y: number, size: number) {

this.ctx.beginPath();

this.ctx.arc(x, y, size, 0, Math.PI * 2);

this.ctx.fill();

this.ctx.closePath();

}

}

FireworkComponent

组件本身就很简单了,生成和绘制Firework。我们在这里面可以额外加一些文字

import React from 'react';

import Firework from './Firework';

import {autobind} from 'core-decorators';

let rnd = Math.random;

function rndNum(num: number) {

return rnd() * num + 1;

}

interface PropTypes {

onClick?: () => void;

}

@autobind

class FireworkComponent extends React.Component {

canvas: HTMLCanvasElement = null;

ctx: CanvasRenderingContext2D = null;

snapTime: number = 0;

fireworks: Firework[] = [];

gravity: number = 0.1;

componentDidMount() {

this.canvas = document.querySelector('#fireworks');

this.canvas.width = window.innerWidth;

this.canvas.height = window.innerHeight;

this.ctx = this.canvas.getContext('2d');

this.init();

this.draw();

}

init() {

let numOfFireworks = 20;

for (let i = 0; i < numOfFireworks; i++) {

this.fireworks.push(new Firework(rndNum(this.canvas.width), this.canvas.height, this.gravity, this.ctx));

}

}

update(time: number) {

for (let i = 0, len = this.fireworks.length; i < len; i++) {

let p = this.fireworks[i];

p.update(time, this.gravity);

}

}

draw(time?: number) {

this.update(time);

this.ctx.fillStyle = 'rgba(0,0,0,0.3)';

this.ctx.fillStyle = 'rgba(0,0,0,0)';

this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

this.ctx.font = 'bold 30px cursive';

this.ctx.fillStyle = '#e91818';

let text = 'XX项目组给您拜个早年!';

let textWidth = this.ctx.measureText(text);

this.ctx.fillText(text, this.canvas.width / 2 - textWidth.width / 2, 200);

text = '在新年来临之际,祝您:';

textWidth = this.ctx.measureText(text);

this.ctx.fillText(text, this.canvas.width / 2 - textWidth.width / 2, 260);

text = '工作顺利,新春快乐!';

this.ctx.font = 'bold 48px STCaiyun';

this.ctx.fillStyle = 'orangered';

textWidth = this.ctx.measureText(text);

this.ctx.fillText(text, this.canvas.width / 2 - textWidth.width / 2, 340);

this.ctx.fillStyle = 'gray';

this.ctx.font = '18px Arial';

text = '点击任意处关闭';

textWidth = this.ctx.measureText(text);

this.ctx.fillText(text, this.canvas.width - 20 - textWidth.width, 60);

this.snapTime = time;

this.ctx.fillStyle = 'blue';

for (let i = 0, len = this.fireworks.length; i < len; i++) {

let p = this.fireworks[i];

if (p.dead) {

p = this.fireworks[i] = new Firework(

rndNum(this.canvas.width),

this.canvas.height,

this.gravity,

this.ctx

);

p.start = time;

}

p.draw();

}

window.requestAnimationFrame(this.draw);

}

render() {

return (

id="fireworks"

onClick={this.props.onClick}

style={{position: 'fixed', zIndex: 99, background: 'rgba(0,0,0, 0.8)'}}

width="400"

height="400">

);

}

}

export default FireworkComponent;

大致效果

8849d125c2d9e4bf1e553b3bb59f16bf.png

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

html烟花代码在线编程,canvas实现烟花的示例代码 的相关文章

  • 关于android instrumentation的理解、使用

    一般的应用不太会用到instrumentation 所以网上对其介绍也比较少 但因其强大的跟踪application及activity生命周期的功能 用于android 应用测试框架中 被做为基类使用 instrumentation的官方文
  • vooc是什么快充协议_一山更比一山高,常见的快充协议有哪些?

    快充这一领域充分诠释了 一山还有一山高 这一句话 当 65W 还历历在目的时候 90W 的联想拯救者新机冒出来了 这还不止 小米随即有一款 120W 的新机通过 3C 认证 快充的领军者 OV 两厂自然不会落下 vivo 宣布 8 月份将有
  • chrome插件使用整理

    1 postman 功能 模拟网页调试与发送网页HTTP请求 安装 进入chrome网上应用商店 搜索postman 点击添加至chrome 装好后 启用即可 使用 具体如下图 设置完请求 发送即可 总结 构建请求方便 对于调试API 以及
  • RK3399Pro LVDS接口触摸屏调试

    一 概述 市场上的触摸屏大都是由LCD与TP组成 LCD用于显示 TP用于反馈触摸点信息 目前选用的LCD屏为LVDS接口而RK3399系列没有原生LVDS接口 所以这里我们就需要用到信号转换芯片 将MIPI信号转为LVDS信号 二 LCD
  • C语言中的exit()函数

    函数名 exit 所在头文件 stdlib h 功 能 关闭所有文件 终止正在执行的进程 exit 1 表示异常退出 这个1是返回给操作系统的 exit x x不为0 都表示异常退出 exit 0 表示正常退出 exit 的参数会被传递给一
  • 不能初始化数据库支持endnote_终于修复了我的EndNote文献管理数据库

    之前一直用EndNote来管理文献资料 由于家里的电脑和办公室的电脑资料需要经常同步 就用115网盘来做为同步盘来同步文献资料库 但EndNote有个特点 就是在关闭它时才会最后更新文献资料库所在的data rdb目录的一些文件 因此 在用
  • webpack

    一 是什么 HMR全称 Hot Module Replacement 可以理解为模块热替换 指在应用程序运行过程中 替换 添加 删除模块 而无需重新刷新整个应用 例如 我们在应用运行过程中修改了某个模块 通过自动刷新会导致整个应用的整体刷新
  • iscsi 服务器

    iscsi服务器简介 当我们的系统需要大量的磁盘容量 但是身边却没有足够的存储设备 此时 我们可以使用通过网络的scsi磁盘 即Internet scsi iscsi iscsi主要是通过TCP IP的技术 将存储设备端通过iscsi ta
  • Python3.0+学习记录之数字

    Python3 数字 Number Python 数字数据类型用于存储数值 数据类型是不允许改变的 这就意味着如果改变数字数据类型得值 将重新分配内存空间 以下实例在变量赋值时 Number 对象将被创建 var1 1 var2 10 您也
  • 如何一步更改文件夹及其子文件夹/文件的权限

    问 我想在 Linux 中一步 命令 更改文件夹及其所有子文件夹和文件的权限 我已经尝试过以下命令 但它仅适用于提到的文件夹 chmod 775 opt lampp htdocs 有没有办法为 opt lampp htdocs 及其所有内容
  • Apache服务器设置虚拟目录,Apache服务器虚拟主机虚拟目录配置.pdf

    实验一 Apache 服务器配置 1 Apache 服务器介绍与安装 Apache 是世界使用排名第一的Web 服务器软件 它可以运行在几乎所有广 泛使用的计算机平台上 由于其跨平台和安全性被广泛使用 是最流行的 Web 服务器端软件之一
  • ResNet50进行image分类

    keras预训练模型应用 1 ResNet50进行image分类 Keras 中文文档 Application应用 Kera的应用模块Application提供了带有预训练权重的Keras模型 这些模型可以用来进行预测 特征提取和finet
  • 接口 测试

    一 接口概念 1 什么是接口 API 接口 接口是为了提供一种服务 所有的接口统称为API 接口分为内部接口和外部接口 外部接口 测试被测系统和外部系统之间的接口 测试内部接口 1 内部接口提供内部系统使用 开发人员自己开发的对自身系统提供
  • Android起始内存大,调整Android Studio分配内存大小

    如果Androidstudio运行起来非常卡顿 缓慢 很可能是因为初始分配的内存不够导致卡顿 查看当前分配的Heap 总大小以及使用状况可以在studio中设置展示 具体位置Settings gt Appearance 页里 打开Show
  • LINUX查看进程在哪个cpu核上运行的方法

    方法一 使用top命令 top 命令可以显示进程在哪个CPU上运行 可以连续监视随着时间的改变 该进程运行在哪个cpu上是否发生变化 使用步骤 top p 进程号 例如 top p 3000 按下 F 键 使用上下键选择P Last Use
  • Spring boot JdbcTemplate使用多数据源配置

    注 使用上篇的Mac Spring boot 1 5 9 使用JDBCTemplate操作数据库 现在我们使用两个数据库 都有个user表 对user表进行相关数据库操作 1 看下项目目录 2 我们配置下application proper
  • [转]汽车电子还能这么玩

    如果你认为本系列文章对你有所帮助 请大家有钱的捧个钱场 点击此处赞助 赞助额0 1元起步 多少随意 声明 本文只用于个人学习交流 若不慎造成侵权 请及时联系我 立即予以改正 锋影 email 174176320 qq com 导读 汽车电子
  • java成绩等级判断

    import java util Scanner 成绩等级判断 public class ScoreLevel public static void main String args Scanner sc new Scanner Syste
  • Element UI 的输入框

    Input 输入框 通过鼠标或键盘输入字符 Input el input 为受控组件 它总会显示 Vue 绑定值 通常情况下 应当处理 input 事件 并更新组件的绑定值 或使用v model 否则 输入框内显示的值将不会改变 不支持 v

随机推荐

  • css line-height小酌

    1 行高的实际应用 1 1 一个空的div 打开浏览器看什么都会没有 给他嵌套个字体啊 就能撑开啊 好 兄弟来 试试看看行不行 div line height 0 background f00 或 div font size 0 backg
  • CTF系列之Web——SQL注入

    前言 在刚学习SQL注入的过程中非常艰难 查资料的时间有一周这么长 点开的网页也不下一千 认真读的也最少有两百 可是能引导入门的真的没几篇 都是复制来复制去的 没意思 感觉就是在浪费时间 有很多知识点都很散 很少能考到一片吧所有知识点总结在
  • Hutool-core 核心------cn.hutool.core.bean包下的DynaBean、BeanDesc、BeanDesc.PropDesc、BeanPath、BeanUtil、

    1 DynaBean 动态Bean 封装实例对象 进行反射调用 2 BeanDesc Bean信息描述做为BeanInfo替代方案 3 BeanDesc PropDesc 属性描述 4 BeanPath Bean路径表达式对象 用于属性检
  • FPGA面试真题解析(2)

    5 下面哪种不是组合逻辑电路功能描述方法 硬件逻辑实习岗 A 真值表 B 布尔方程 C 状态机 D 逻辑框图 解析 考察数字电路中对组合逻辑电路的认识 A选项真值表是使用于逻辑中的一类数学用表 用来计算逻辑表示式在每种论证 即每种逻辑变量取
  • C++学习--cin不支持录入空格

    https blog csdn net EXLsunshine article details 28440629 举个栗子 当使用cin功能然后键盘输入 aaa bbb ccc 时 cin的那个字符串只会保留 aaa
  • Apache解析漏洞

    Apache解析漏洞主要是因为Apache默认一个文件可以有多个用 分割得后缀 当最右边的后缀无法识别 mime types文件中的为合法后缀 则继续向左看 直到碰到合法后缀才进行解析 以最后一个合法后缀为准 1 如图 最后一个后缀名为 x
  • IPC:消息队列

    消息队列 gcc messageQueue c o mq lrt mqd t mq send mqd t mqdes const char msg ptr size t msg len unsigned msg prio msg prio
  • OpenCV 实现读取摄像头、视频读取保存 (C++)

    一 读取摄像头 重点语句 VideoCapture imshow 原理 使用VideoCapture语句读取摄像头 再利用while一次次将VideoCapture所读取的数据利用imshow语句一帧帧地读取出来 include
  • 基于多任务学习和GCN的交通路网出租车需求预测

    1 文章信息 文章题目为 Multitask Learning and GCN Based Taxi Demand Prediction for a Traffic Road Network 是一篇发表在Sensors期刊上的有关基于多任务
  • 解决vista和win10在windows服务中交互桌面权限问题:穿透Session 0 隔离

    服务 Service 对于大家来说一定不会陌生 它是Windows 操作系统重要的组成部分 我们可以把服务想像成一种特殊的应用程序 它随系统的 开启 关闭 而 开始 停止 其工作内容 在这期间无需任何用户参与 Windows 服务在后台执行
  • python数据分析面试_python数据分析面试

    1 如何利用SciKit包训练一个简单的线性回归模型 利用linear model LinearRegression 函数 Create linear regression object regr linear model LinearRe
  • vs code配置c语音环境

    要在VS Code中配置C语言环境 您可以按照以下步骤进行操作 安装C C 扩展程序 在VS Code中 您可以通过搜索 C C 来找到C C 扩展程序 安装该扩展程序后 您可以在VS Code中使用C C 语言编写代码 创建C C 项目
  • C++入门-----拷贝构造

    学习目标 1 拷贝构造函数的概念及使用 2 特征 3 注意的点 3 1 防止无穷递归 3 2 防止原对象被修改 4 默认生成拷贝构造 4 1 浅拷贝 4 2 为什么要自己实现拷贝构造函数 4 3 其对于内置类型和自定义类型的处理方式 5 总
  • vue响应式数据-修改对象的属性值,视图不更新

    目录 bug复现 原因 怎么在console中判断是不是响应式数据 怎样才能设置为响应式数据 bug复现 在代码中给一个对象 新增多个属性并赋值 然后在另一个方法中修改对象其中一个属性的值 发现数据改变 页面视图并没有更新 data ret
  • 在Vue.js的public目录下的index.html文件中,可以使用EJS(Embedded JavaScript)模板语法来插入变量。

    这个示例中 和被用于插入对应的变量 这些变量将被EJS模板引擎根据环境和配置进行替换 同样 会将htmlWebpackPlugin插件的options title属性插入到
  • vue中动态水印

    效果 一 根元素div上增加 div class rootZhy div 二 增加方法 watermarkZhy content let container document body let width 120px let height
  • BeanCreationException: Error creating bean with name ‘configurationPropertiesBeans‘ defined in class

    1 现象 启动 SpringCloud项目时报错 2 解决方案 2 1 spring cloud dependencies添加到dependencyManagement标签
  • STM32开发(六)STM32F103 通信 —— RS485 Modbus通信编程详解

    上一篇 主目录 下一篇 文章目录 一 基础知识点 二 开发环境 三 STM32CubeMX相关配置 1 STM32CubeMX基本配置 2 STM32CubeMX RS485 相关配置 四 Vscode代码讲解 五 结果演示以及报文解析 六
  • Spring Boot 添加拦截器

    文章目录 Spring Boot 添加拦截器 方法1 新增拦截器 配置拦截器 方法2 新增拦截器 配置拦截器 拦截所有响应 Spring Boot 添加拦截器 介绍一下在Spring Boot 2 0 0以上版本如何添加拦截器 方法1 新增
  • html烟花代码在线编程,canvas实现烟花的示例代码

    前言 马上过年了 我打算在后台里面偷偷地埋个新春祝福 放烟花的彩蛋 项目是基于react typescript的 因此最后封装成了一个组件 设置好开启时间就可以显示了 目录结构 目录结构大致如下 我们将烟花分为两个阶段 一个是未炸开持续上升