1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
| type initOption = { el: string | HTMLCanvasElement particuleNum: number, colors: string[] }
type Particule = { x: number y: number currentRadius: number direction: ParticuleDirection color: string radius: number }
type ParticuleDirection = { x: number y: number length: number }
const defaultOptions: initOption = { el: 'canvas.fireworks', particuleNum: 20, colors: ['#FF1461', '#18FF92', '#5A87FF', '#FBF38C'] }
function randomInt(min: number, max: number) { return Math.floor(Math.random() * (max + 1 - min) + min) }
function setCanvasSize(canvasEl: HTMLCanvasElement) { canvasEl.width = window.innerWidth * 2 canvasEl.height = window.innerHeight * 2 canvasEl.style.width = window.innerWidth + 'px' canvasEl.style.height = window.innerHeight + 'px' canvasEl.style.pointerEvents = 'none' canvasEl.getContext('2d')!.scale(2, 2) }
function fireworks(options: initOption = defaultOptions) { const canvasEl: HTMLCanvasElement | null = typeof options.el === 'string' ? document.querySelector(options.el) : options.el if (!canvasEl || canvasEl.nodeName.toLowerCase() !== 'canvas') { throw new Error('未找到canvas元素') } setCanvasSize(canvasEl) window.addEvnetListener('resize', () => { setCanvasSize(canvasEl) }) let pointerX = 0 let pointerY = 0 const particuleNum = options.particuleNum const colors = options.colors const ctx = (canvasEl as HTMLCanvasElement).getContext('2d')! const tap = 'ontouchstart' in window ? 'touchstart' : 'mousedown' const particules: Particule[] = []
function setParticuleDirection(x: number, y: number): ParticuleDirection { const length = randomInt(50, 180) const angle = randomInt(0, 360) * Math.PI / 180 const direction = [-1, 1][randomInt(0, 1)] const xlength = Math.cos(angle) * length * direction const ylength = Math.sin(angle) * length * direction return { x: x + xlength, y: y + ylength, length } }
function createParticule(x: number, y: number): Particule { const color = colors[randomInt(0, colors.length - 1)] const radius = randomInt(8, 16) const endPoint = setParticuleDirection(x, y) return { x, y, color, direction: endPoint, radius, currentRadius: radius } }
function calcParticuleCoords(particule: Particule) { const direction = particule.direction let x = particule.x + (direction.x - pointerX) / 500 * elapsed let y = particule.y + (direction.y - pointerY) / 500 * elapsed const length = Math.sqrt(Math.pow(Math.abs(x - pointerX), 2) + Math.pow(Math.abs(y - pointerY), 2)) if (length > direction.length) { x = direction.x y = direction.y } return {x, y} }
let startTimeStamp = 0 let elapsed let done = true function drawStep(timestamp: number) { done = false if (!startTimeStamp) { startTimeStamp = timestamp } elapsed = timestamp - startTimeStamp ctx.clearRect(0, 0, canvasEl!.clientWidth, canvasEl!.clientHeight) for (let i = 0; i < particules.length; i++) { const particule = particules[i] const direction = particule.direction const coord = calcParticuleCoords(particule) const radius = Math.max(particule.radius - particule.radius / 500 * elapsed, 0) ctx.beginPath() ctx.arc(coord.x, coord.y, radius, 0, 2 * Math.PI, true) ctx.fillStyle = particule.color ctx.fill() if ((coord.x === direction.x && coord.y === direction.y) || radius === 0) { particules.splice(i, 1) i-- } } if (elapsed > 1000 || particules.length === 0) { particules.splice(0) done = true } else { requestAnimationFrame(drawStep) } }
document.addEventListener(tap, function (e) { if (!done) { return } pointerX = (e as MouseEvent).clientX || (e as TouchEvent).touches[0].clientX pointerY = (e as MouseEvent).clientY || (e as TouchEvent).touches[0].clientY startTimeStamp = 0 elapsed = null for (let i = 0; i < particuleNum; i++) { particules.push(createParticule(pointerX, pointerY)) } requestAnimationFrame(drawStep) }) }
export default fireworks
|