letter-explode.js 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. (function(){
  2. window.HPX = window.HPX || {};
  3. window.HPX['letter-explode'] = function(el){
  4. const U = window.HPX._u;
  5. if (getComputedStyle(el).position === 'static') el.style.position = 'relative';
  6. const src = el.querySelector('[data-fx-text]') || el;
  7. const text = (el.getAttribute('data-fx-text-value') || src.textContent || 'EXPLODE').trim();
  8. // Build a container, hide source text
  9. const wrap = document.createElement('div');
  10. wrap.style.cssText = 'position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;';
  11. const inner = document.createElement('div');
  12. inner.style.cssText = 'font-size:64px;font-weight:900;letter-spacing:0.02em;color:var(--text-1,#fff);white-space:nowrap;';
  13. wrap.appendChild(inner);
  14. el.appendChild(wrap);
  15. const spans = [];
  16. for (const ch of text){
  17. const s = document.createElement('span');
  18. s.textContent = ch === ' ' ? '\u00A0' : ch;
  19. s.style.display='inline-block';
  20. s.style.transform='translate(0,0)';
  21. s.style.transition='transform 900ms cubic-bezier(.2,.9,.3,1), opacity 900ms';
  22. s.style.opacity='0';
  23. inner.appendChild(s);
  24. spans.push(s);
  25. }
  26. let stopped = false;
  27. const run = () => {
  28. if (stopped) return;
  29. spans.forEach((s,i) => {
  30. const dx = U.rand(-400, 400), dy = U.rand(-300, 300);
  31. s.style.transition='none';
  32. s.style.transform=`translate(${dx}px,${dy}px) rotate(${U.rand(-180,180)}deg)`;
  33. s.style.opacity='0';
  34. });
  35. // force reflow
  36. void inner.offsetWidth;
  37. spans.forEach((s,i) => {
  38. setTimeout(() => {
  39. if (stopped) return;
  40. s.style.transition='transform 900ms cubic-bezier(.2,.9,.3,1), opacity 900ms';
  41. s.style.transform='translate(0,0) rotate(0deg)';
  42. s.style.opacity='1';
  43. }, i*35);
  44. });
  45. };
  46. run();
  47. const iv = setInterval(run, 4500);
  48. return { stop(){ stopped=true; clearInterval(iv); if (wrap.parentNode) wrap.parentNode.removeChild(wrap); } };
  49. };
  50. })();