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

介绍

  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)];
};

效果图

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
压缩HTML: 可以使用多种工具来压缩HTML,例如HTMLMinifier或UglifyJS等。这些工具可以删除不必要的空格、注释和其他字符,从而减小文件大小。以下是使用HTMLMinifier进行HTML压缩的示例代码: ```javascript const html = '<html><head><title>Hello World</title></head><body><p>Hello, world!</p></body></html>'; const minifiedHtml = htmlMinifier.minify(html, { collapseWhitespace: true, removeComments: true, minifyCSS: true, minifyJS: true }); ``` 图片上传: 可以使用HTML5的File API来实现图片上传。以下是一个基本的示例: ```html <input type="file" id="upload-input"> <script> const input = document.getElementById('upload-input'); input.addEventListener('change', (e) => { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = (event) => { const imageData = event.target.result; // 图片数据 // 将图片数据上传到服务器 }; reader.readAsDataURL(file); }); </script> ``` JS Canvas 修改图片尺寸和压缩大小: 可以使用canvas的API来修改图片的尺寸和压缩图片大小。以下是一个基本的示例: ```html <input type="file" id="upload-input"> <canvas id="canvas"></canvas> <script> const input = document.getElementById('upload-input'); const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); input.addEventListener('change', (e) => { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = (event) => { const img = new Image(); img.onload = () => { // 计算缩小后的尺寸 const maxWidth = 300; const maxHeight = 300; let width = img.width; let height = img.height; if (width > height) { if (width > maxWidth) { height *= maxWidth / width; width = maxWidth; } } else { if (height > maxHeight) { width *= maxHeight / height; height = maxHeight; } } canvas.width = width; canvas.height = height; // 绘制缩小后的图片 context.drawImage(img, 0, 0, width, height); // 压缩图片 const quality = 0.7; const imageData = canvas.toDataURL('image/jpeg', quality); // 将图片数据上传到服务器 }; img.src = event.target.result; }; reader.readAsDataURL(file); }); </script> ``` 以上是一个基本的实现,具体的实现方式可以根据需求进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值