firework.js 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. (function(){
  2. window.HPX = window.HPX || {};
  3. window.HPX['firework'] = function(el){
  4. const U = window.HPX._u;
  5. const k = U.canvas(el), ctx = k.ctx;
  6. const pal = U.palette(el);
  7. let rockets = [], sparks = [];
  8. const launch = () => {
  9. rockets.push({
  10. x: U.rand(k.w*0.2, k.w*0.8), y: k.h+10,
  11. vx: U.rand(-30,30), vy: U.rand(-520,-380),
  12. tgtY: U.rand(k.h*0.15, k.h*0.45),
  13. c: pal[(Math.random()*pal.length)|0]
  14. });
  15. };
  16. const burst = (x, y, c) => {
  17. const n = 70;
  18. for (let i=0;i<n;i++){
  19. const a = Math.random()*Math.PI*2;
  20. const s = U.rand(60, 240);
  21. sparks.push({x,y,vx:Math.cos(a)*s,vy:Math.sin(a)*s,life:1,c});
  22. }
  23. };
  24. let last = -1;
  25. const stop = U.loop((t) => {
  26. ctx.fillStyle = 'rgba(0,0,0,0.18)';
  27. ctx.fillRect(0,0,k.w,k.h);
  28. if (t - last > 0.7) { launch(); last = t; }
  29. const dt = 1/60;
  30. rockets = rockets.filter(r => {
  31. r.x += r.vx*dt; r.y += r.vy*dt; r.vy += 260*dt;
  32. ctx.fillStyle = r.c;
  33. ctx.beginPath(); ctx.arc(r.x, r.y, 2.5, 0, Math.PI*2); ctx.fill();
  34. if (r.y <= r.tgtY || r.vy >= 0) { burst(r.x, r.y, r.c); return false; }
  35. return true;
  36. });
  37. sparks = sparks.filter(p => p.life > 0);
  38. for (const p of sparks){
  39. p.vy += 90*dt;
  40. p.vx *= 0.98; p.vy *= 0.98;
  41. p.x += p.vx*dt; p.y += p.vy*dt;
  42. p.life -= 0.012;
  43. ctx.globalAlpha = Math.max(0, p.life);
  44. ctx.fillStyle = p.c;
  45. ctx.beginPath(); ctx.arc(p.x, p.y, 2, 0, Math.PI*2); ctx.fill();
  46. }
  47. ctx.globalAlpha = 1;
  48. });
  49. return { stop(){ stop(); k.destroy(); } };
  50. };
  51. })();