麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 開發 > HTML5 > 正文

canvas實現煙花的示例代碼

2024-09-05 07:23:14
字體:
來源:轉載
供稿:網友

前言:馬上過年了,我打算在后臺里面偷偷地埋個新春祝福+放煙花的彩蛋。項目是基于react+typescript的,因此最后封裝成了一個組件,設置好開啟時間就可以顯示了。

目錄結構

目錄結構大致如下

我們將煙花分為兩個階段,一個是未炸開持續上升時期,另一個是炸開后分散的時期。
其中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;}@autobindclass FireworkComponent extends React.Component<PropTypes> {    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 (            <canvas                id="fireworks"                onClick={this.props.onClick}                style={{position: 'fixed', zIndex: 99, background: 'rgba(0,0,0, 0.8)'}}                width="400"                height="400"></canvas>        );    }}export default FireworkComponent;

大致效果

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 日韩毛片网 | 久久精品一区二区三区四区五区 | 国产精品视频六区 | 亚洲婷婷日日综合婷婷噜噜噜 | 91精品国产乱码久久桃 | 午夜精品久久久久久久99热浪潮 | 欧美黄色三级视频 | 日韩视频一二区 | 国产精品亚洲三区 | 欧美hdfree性xxxx | 香蕉秀 | 毛片视频网址 | 一区二区三区日本在线观看 | 国产91精品一区二区麻豆亚洲 | 国产一级αv片免费观看 | 深夜免费观看视频 | 一级黄色毛片子 | 国产91影院 | 99精彩视频在线观看 | 欧美一级精品片在线看 | 国产精品一区在线看 | 免费一级毛片在线播放视频老 | 美女毛片在线观看 | 狠狠操夜夜爱 | 国产免费小视频在线观看 | 福利免费在线 | 日本在线一区二区 | 高清国产在线 | 日本欧美国产 | 成人午夜视频网站 | 91九色免费视频 | 欧美日本一 | 国产精品久久久久久久久久大牛 | 一级性生活免费视频 | www亚洲免费| 欧美成人国产va精品日本一级 | 久草在线资源福利站 | 玩偶姐姐 在线观看 | 综合日韩欧美 | 国产精品成人一区二区三区电影毛片 | 精品在线观看一区 |