js实现红包雨功能(canvas,react,ts),包括图片不规则旋转、大小、转速、掉落速度控制、屏幕最大红包数量控制等功能

news2025/1/15 8:08:18

介绍

  1. 本文功能由canvas实现红包雨功能(index.tsx
  2. 本文为react的ts版。如有其他版本需求可评论区
  3. 观赏地址,需过墙
import React, { Component } from 'react';
// import './index.css';
import moneyx from '@/assets/images/RedEnvelopeRain/ball1.png';
import money1 from '@/assets/images/RedEnvelopeRain/money1.webp';
import money2 from '@/assets/images/pointCon/机器人.png';
import money3 from '@/assets/images/pointCon/无人机.png';
import {
  loadImage,
  positionX,
  randomRange,
} from './utils';
type minMax = [number, number];
const config = {
  // speed value area
  speedLimit: [1, 4] as minMax,
  // display quantity
  density: [5, 15] as minMax,
  imgInfo: {
    // image width
    w: 50,
    // image height
    h: 50,
    // image rotate value area
    randomLimit: [0.5, 1] as minMax,
  },
  // image number max show
  numberMaxLimit: 200,
};
const { speedLimit, imgInfo, numberMaxLimit, density } = config;

export default class CanvasCom extends Component {
  // ratio = null;
  ctx: any = null;

  wid = 0;
  hei = 0;
  packedArr: ReturnType<typeof this.createPack>[] = [];
  // display quantity
  density = {
    min: density[0],
    max: density[1],
  };

  clearTime: any = null;
  img: any = [];
  loadingImageArr = [money1, moneyx, money2, money3]

  componentDidMount() {
    this.loadingImg();
  }
  loadingImg() {
    Promise.all(this.loadingImageArr.map(v => loadImage(v))).then((res) => {
      this.img = res;
      this.wid = window.innerWidth;
      this.hei = window.innerHeight;
      this.initCanvas();
      this.start();
    });
  }
  getPixelRatio = (context: any) => {
    const backingStore =
      context.backingStorePixelRatio ||
      context.webkitBackingStorePixelRatio ||
      context.mozBackingStorePixelRatio ||
      context.msBackingStorePixelRatio ||
      context.oBackingStorePixelRatio ||
      context.backingStorePixelRatio ||
      1;
    return (window.devicePixelRatio || 1) / backingStore;
  };
  initCanvas() {
    const canvas: HTMLCanvasElement | any = document.getElementById('canvas');
    canvas.width = this.wid;
    canvas.height = this.hei;
    if (canvas.getContext) {
      // 判断是否有此方法,如果有才能进入
      this.ctx = canvas.getContext('2d');
      // this.ratio = this.getPixelRatio(this.ctx);
    }
  }
  createPack() {
    const imgRandom = randomRange(...imgInfo.randomLimit);
    return {
      x: positionX(),
      y: 0,
      img: this.img[Math.floor(randomRange(0, this.loadingImageArr.length ))],
      // rotate
      rotate: randomRange(-45, 45),
      direction: Math.random(),
      speed: randomRange(...speedLimit),
      // rotate speed
      round: 0,
      roundSpeed: randomRange(1, 2),
      imgInfo: {
        w: imgInfo.w * imgRandom,
        h: imgInfo.h * imgRandom,
      },
    };
  }
  pushPackArr = () => {
    const { max, min } = this.density;
    const random = Math.floor(Math.random() * (max - min) + min);
    this.packedArr.push(
      ...new Array(random).fill('').map(() => this.createPack())
    );
    this.clearTime = setTimeout(() => {
      if (this.packedArr.length > numberMaxLimit)
        return clearTimeout(this.clearTime);
      this.pushPackArr();
    }, 300);
  };
  drawPacked = () => {
    this.ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
    this.packedArr.forEach((item, index) => {
      const r = ((item.rotate + item.round) * Math.PI) / 180;
      const temp = item.y - item.x * Math.tan(r);
      const top = temp * Math.cos(r);
      const left = item.x / Math.cos(r) + temp * Math.sin(r);
      this.ctx.save();
      this.ctx.rotate(r);
      this.ctx.drawImage(
        item.img,
        left - item.imgInfo.w / 2,
        top - item.imgInfo.h / 2,
        item.imgInfo.w,
        item.imgInfo.h
      );
      this.ctx.restore();
      if (item.direction < 0.5) {
        item.round -= item.roundSpeed;
      } else {
        item.round += item.roundSpeed;
      }
      if (item.y + item?.speed <= window.innerHeight) {
        item.y = item.y + item?.speed || 0;
      } else {
        // init
        item.y = 0 + item?.speed || 0;
        item.x = positionX();
        Object.assign(item, this.createPack());
      }
    });
    window.requestAnimationFrame(this.drawPacked);
  };

  start = () => {
    this.pushPackArr();
    this.drawPacked();
  };

  render() {
    return (
      <div style={{ position: 'absolute', left: 0, top: 0, background: '#000' }}>
        <canvas id="canvas"></canvas>
      </div>
    );
  }
}
  1. utils/index.ts
export const loadImage = (url: string) => {
  if (!window?.Image) return null;
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.src = url;
    img.onload = () => {
      resolve(img);
    };
    img.onerror = () => {
      reject(new Error('load image error!'));
    };
  });
};
export const positionX = () => Math.random() * window.innerWidth;
export const randomRange = (start: number, end: number) => {
  const random = (end - start) * Math.random() + start;
  const number = 1;
  const arr = new Array(number).fill('').map((v, i) => random / (i + 1));
  return arr[Math.floor(Math.random() * number)];
};

效果图

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

SEO业务适合什么代理IP?2023海外代理IP推荐排名

随着数字营销趋势的变化&#xff0c;搜索引擎优化仍然是企业在网络世界中努力繁荣的重要组成部分。为了实现 SEO 成功&#xff0c;从搜索引擎获取准确且多样化的数据至关重要&#xff0c;然而可能会受到诸如基于位置的限制和被检测风险等限制的阻碍&#xff0c;IP代理则可以帮助…

百度开源分布式id生成器集成--真香警告

百度开源分布式id生成器集成–真香警告 文章目录 [toc] 1.为什么需要分布式id生成器&#xff1f;2.常见id生成方案2.1 数据库表主键自增2.2 uuid2.3 雪花算法2.3.1 实现代码2.3.2 缺点的解决方案百度开源的分布式唯一ID生成器UidGenerator(本文重点讲解这个)Leaf--美团点评分布…

gnome-terminal禁止关闭确认

当你想要关闭一个终端时&#xff0c;弹出“确认关闭&#xff1f;”多少有些烦。 比如当前为root下&#xff0c;要么一路exit&#xff0c;要么就点击确认&#xff1a; 解决方法&#xff1a; 安装一个配置编辑器来帮我们方便地编辑配置项 sudo apt install dconf-editor找到…

小程序搭建OA项目首页布局界面

首先让我们来学习以下Flex布局 一&#xff0c;Flex布局简介 布局的传统解决方案&#xff0c;基于盒状模型&#xff0c;依赖 display属性 position属性 float属性 Flex布局简介 Flex是Flexible Box的缩写&#xff0c;意为”弹性布局”&#xff0c;用来为盒状模型提供最大的…

tomcat、nginx实现四层转发+七层代理+动静分离实验

实验环境&#xff1a; nginx1——20.0.0.11——客户端 静态页面&#xff1a; nginx2——20.0.0.21——代理服务器1 nginx3——20.0.0.31——代理服务器2 动态页面&#xff1a; tomcat1——20.0.0.12——后端服务器1 tomcat2——20.0.0.22——后端服务器2 实验步骤&…

什么是4K三路虚拟情景互动教学软件?

4K三路虚拟情景互动教学软件具备了AI对话&#xff0c;场景库丰富自定义选择&#xff0c;画面色差调节&#xff0c;人物滤镜调节&#xff0c;截图编辑&#xff0c;视频录制与编辑&#xff0c;视频直播&#xff0c;画中画控制功能&#xff0c;字幕&#xff0c;图片和特效录入功能…

sqlmap --os-shell选项原理解析

文章目录 sqlmap --os-shell选项原理解析原理解析总结 sqlmap --os-shell选项原理解析 以sqli第一关为例。 --os-shell 是 SQLMap 工具的一个参数&#xff0c;用于在成功注入数据库后&#xff0c;执行操作系统命令并获取其输出。 sqlmap -u "http://192.168.188.199/sq…

学信息系统项目管理师第4版系列31_信息系统工程

1. 信息系统战略三角突出了业务战略、信息系统和组织机制之间的必要一致性 1.1. 【高23上选07】 2. 软件工程 2.1. 软件工程方法是完成软件工程项目的技术手段&#xff0c;它支持整个软件生命周期 2.2. 软件工程使用的工具是人们在开发软件的活动中智力和体力的扩展与延伸 …

React合成事件

一、合成事件 event 是 SyntheticEvent &#xff0c;模拟出来 DOM 事件所有能力 event.nativeEvent 是原生事件对象 所有的事件&#xff0c;都被挂载到 document 上&#xff08;React ≤ 16&#xff09;&#xff0c;React17之后是挂载到root组件 和 DOM 事件不一样&#xff…

[1Panel]开源,现代化,新一代的 Linux 服务器运维管理面板

测评介绍 本期测评试用一下1Panel这款面板。1Panel是国内飞致云旗下开源产品。整个界面简洁清爽&#xff0c;后端使用GO开发&#xff0c;前端使用VUE的Element-Plus作为UI框架&#xff0c;整个面板的管理都是基于docker的&#xff0c;想法很先进。官方还提供了视频的使用教程&…

Spring Security配置多个数据源并添加登录验证码(7)

1、配置多个数据源 多个数据源是指在同一个系统中&#xff0c;用户数据来自不同的表&#xff0c;在认证时&#xff0c;如果第一张表没有查找到用户&#xff0c;那就去第二张表中査询&#xff0c;依次类推。 看了前面的分析&#xff0c;要实现这个需求就很容易了&#xff0c;认…

【计算机网络笔记】计算机网络体系结构概念

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

GO 语言的函数??

函数是什么&#xff1f; 学过编程的 xdm 对于函数自然不会陌生&#xff0c;那么函数是什么呢&#xff1f; 函数是一段可以重用的代码块&#xff0c;可以被多次调用&#xff0c;我们可以通过使用函数&#xff0c;提高咱们代码代码的模块化&#xff0c;提高程序的可读性和可维护…

渐进式编程之旅:探寻PHP函数的奇妙世界

目录 前言 一、函数的定义和调用 1.1 初识函数 1.1.1 函数分类 1.1.2 自定义函数 1.1.3 return关键字 1.2 参数设置 1.2.1 无参函数 1.2.2 按值传递参数 1.2.3 引用传参 1.2.4 设置参数默认值 1.2.5 指定参数类型&#xff08;弱&#xff09; 1.3 变量的作用域 1.3.1 变量分类 1…

使用bisect模块进行二分查找操作 bisect.bisect()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 使用bisect模块 进行二分查找操作 bisect.bisect() 选择题 请问bisect.bisect(c,2)的结果是&#xff1a; import bisect print("【执行】c [1,2,2,6,7]") c [1,2,2,6,7] print(c…

Linux性能优化--性能追踪3:系统级迟缓(prelink)

12.0 概述 本章包含的例子说明了如何用Linux性能工具寻找并修复影响整个系统而不是某个应用程序的性能问题。阅读本章后&#xff0c;你将能够&#xff1a; 追踪是哪一个进程导致了系统速度的降低。用strace调查一个不受CPU限制的进程的性能表现。用strace调查一个应用程序是如…

清除git历史敏感数据--bfg的应用

项目场景&#xff1a; 开源项目中的git历史中存在敏感 信息&#xff0c;如数据库地址&#xff0c;端口&#xff0c;密码&#xff0c;用户等 我们我们在主分支擦除密码&#xff0c;用户名等&#xff0c;git的历史记录里还是会有相关信息&#xff0c;并不能真正做到清除敏感信息…

前端自学需要把大量时间放在 HTML、CSS 吗?

前言 html和css其实不需要花费太多的时间&#xff0c;html暂且不说&#xff0c;css各类的属性太多了&#xff0c;平时如果只是简单做一些小网站根本不需要全部掌握&#xff0c;只需要掌握一些基础常用的即可&#xff0c;一般遇到不会的也可以直接查文档&#xff0c;就我个人来…

负载均衡、代理和动静分离的战略

一、Nginx简介 1.1 概述 Nginx (“engine x”) 是一个高性能的 HTTP 和 反向代理服务器,特点是占有内存少,并发能力强,能经受高负载的考验,有报告表明能支持高达 50,000 个并发连接数 。 1.2正向代理与反向代理 1.2.1正向代理 正向代理:如果把局域网外的 Internet 想象…

【数之道 06】神经网络模型中激活函数的选择

激活函数的选择 为什么使用激活函数激活函数的选择sigmoidtanhReLU(Rectified Linear Unit)Leaky ReLU&#xff08; ReLU 函数的变形体&#xff09;隐藏层的选择顺序 输出层的激活函数以业务要求为导向二分类问题多分类问题多标签问题线性回归问题 b站视频 为什么使用激活函数…