返回 html-ppt-skill
fx-runtime.js
根目录 / assets / animations / fx-runtime.js
1 /* html-ppt :: fx-runtime.js
2 * Canvas FX autoloader + lifecycle manager.
3 * - Dynamically loads all fx modules listed in FX_LIST
4 * - Initializes [data-fx] elements when their slide becomes active
5 * - Calls handle.stop() when the slide leaves
6 */
7 (function(){
8 'use strict';
9
10 const FX_LIST = [
11 '_util',
12 'particle-burst','confetti-cannon','firework','starfield','matrix-rain',
13 'knowledge-graph','neural-net','constellation','orbit-ring','galaxy-swirl',
14 'word-cascade','letter-explode','chain-react','magnetic-field','data-stream',
15 'gradient-blob','sparkle-trail','shockwave','typewriter-multi','counter-explosion'
16 ];
17
18 // Resolve base path of this script so it works from any page location.
19 const myScript = document.currentScript || (function(){
20 const all = document.getElementsByTagName('script');
21 for (const s of all){ if (s.src && s.src.indexOf('fx-runtime.js')>-1) return s; }
22 return null;
23 })();
24 const base = myScript ? myScript.src.replace(/fx-runtime\.js.*$/, 'fx/') : 'assets/animations/fx/';
25
26 let loaded = 0;
27 const total = FX_LIST.length;
28 const ready = new Promise((resolve) => {
29 if (!total) return resolve();
30 FX_LIST.forEach((name) => {
31 const s = document.createElement('script');
32 s.src = base + name + '.js';
33 s.async = false;
34 s.onload = s.onerror = () => { if (++loaded >= total) resolve(); };
35 document.head.appendChild(s);
36 });
37 });
38
39 window.__hpxActive = window.__hpxActive || new Map();
40
41 function initFxIn(root){
42 if (!window.HPX) return;
43 const els = root.querySelectorAll('[data-fx]');
44 els.forEach((el) => {
45 if (window.__hpxActive.has(el)) return;
46 const name = el.getAttribute('data-fx');
47 const fn = window.HPX[name];
48 if (typeof fn !== 'function') return;
49 try {
50 const handle = fn(el, {}) || { stop(){} };
51 window.__hpxActive.set(el, handle);
52 } catch(e){ console.warn('[hpx-fx]', name, e); }
53 });
54 }
55
56 function stopFxIn(root){
57 const els = root.querySelectorAll('[data-fx]');
58 els.forEach((el) => {
59 const h = window.__hpxActive.get(el);
60 if (h && typeof h.stop === 'function'){
61 try{ h.stop(); }catch(e){}
62 }
63 window.__hpxActive.delete(el);
64 });
65 }
66
67 function reinitFxIn(root){
68 stopFxIn(root);
69 initFxIn(root);
70 }
71 window.__hpxReinit = reinitFxIn;
72
73 function boot(){
74 ready.then(() => {
75 const active = document.querySelector('.slide.is-active') || document.querySelector('.slide');
76 if (active) initFxIn(active);
77
78 // Watch all slides for class changes
79 const slides = document.querySelectorAll('.slide');
80 slides.forEach((sl) => {
81 const mo = new MutationObserver((muts) => {
82 for (const m of muts){
83 if (m.attributeName === 'class'){
84 if (sl.classList.contains('is-active')) initFxIn(sl);
85 else stopFxIn(sl);
86 }
87 }
88 });
89 mo.observe(sl, { attributes: true, attributeFilter: ['class'] });
90 });
91 });
92 }
93
94 if (document.readyState === 'loading'){
95 document.addEventListener('DOMContentLoaded', boot);
96 } else {
97 boot();
98 }
99 })();
100
100 lines JAVASCRIPT