svg-scroll-draw 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,23 @@
1
- 'use strict';function U({bounces:e=3,decay:t=.5}={}){let r=Math.max(1,Math.round(e)),o=Math.max(.01,Math.min(.99,t)),u=Math.sqrt(o),c=0,d=[];for(let s=0;s<r;s++){let i=Math.pow(u,s);d.push(i),c+=i;}let f=[0],b=0;for(let s=0;s<r;s++)b+=d[s]/c,f.push(b);return s=>{if(s<=0)return 0;if(s>=1)return 1;for(let i=0;i<r;i++)if(s<=f[i+1]){let w=(s-f[i])/(f[i+1]-f[i]);if(i===0)return w*(2-w);let M=1-Math.pow(o,i);return M+(1-M)*(2*w-1)*(2*w-1)}return 1}}function Z({amplitude:e=1,period:t=.4}={}){let r=Math.max(1,e),o=Math.max(.1,t),u=r<=1?o/4:o/(2*Math.PI)*Math.asin(1/r);return c=>c<=0?0:c>=1?1:r*Math.pow(2,-10*c)*Math.sin((c-u)*(2*Math.PI)/o)+1}var $={linear:e=>e,"ease-in":e=>e*e,"ease-out":e=>e*(2-e),"ease-in-out":e=>e<.5?2*e*e:-1+(4-2*e)*e,spring:e=>1-Math.cos(e*Math.PI*2.5)*Math.pow(1-e,2.2),bounce:U(),elastic:Z()};function F(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[r="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function V(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function B(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function P(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function _(e,t,r){return Math.min(r,Math.max(t,e))}function W(e,t,r,o){return r===t?0:_((e-t)/(r-t)*o,0,1)}function X(e,t,r,o,u){let c=V(e.top,e.height,t,o.element)-B(o.viewport,r),d=V(e.top,e.height,t,u.element)-B(u.viewport,r);return {tStart:c,tEnd:d}}function ee(e,t){let r={destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};if(typeof window>"u")return r;let o=typeof e=="string"?document.querySelector(e):e;if(!o)return console.warn("[svg-scroll-draw/timeline] Container not found:",e),r;let u=o,{trigger:c={},speed:d=1,once:f=false,axis:b="y",tracks:s,onComplete:i}=t,w=F(c.start??"top bottom"),M=F(c.end??"bottom top"),A=s.map(n=>{let m=typeof n.easing=="function"?n.easing:$[n.easing??"linear"]??$.linear,l=Array.from(u.querySelectorAll(n.selector)),a=l.map(p=>P(p));return l.forEach((p,S)=>{p.style.strokeDasharray=`${a[S]}`,p.style.strokeDashoffset=`${a[S]}`,n.fade&&(p.style.opacity="0");}),{...n,elements:l,lengths:a,easeFn:m}}),L=0,k=0,E=false,h=false,g=0,I=false,y=-1,x=0;function q(){return b==="x"?window.scrollX:window.scrollY}function j(){return b==="x"?window.innerWidth:window.innerHeight}function z(){let n=u.getBoundingClientRect(),m=q(),l=b==="x"?n.left:n.top,a=b==="x"?n.width:n.height,p=X({top:l,height:a},m,j(),w,M);L=p.tStart,k=p.tEnd;}function C(n){u.style.setProperty("--scroll-draw-progress",String(n)),A.forEach(({elements:m,lengths:l,from:a,to:p,easeFn:S,fade:J})=>{let N=p-a,K=N>0?Math.min(1,Math.max(0,(n-a)/N)):0,R=S(K);m.forEach((O,Q)=>{O.style.strokeDashoffset=`${l[Q]*(1-R)}`,J&&(O.style.opacity=String(R));});});}function v(){if(!E||h)return;let n=W(q(),L,k,d);f&&(y=Math.max(y,n),n=y),x=n,C(n),n>=1&&!I?(I=true,i?.()):n<1&&!f&&(I=false),g=requestAnimationFrame(v);}z();let G=new IntersectionObserver(n=>{n.forEach(m=>{E=m.isIntersecting,E&&!h?g=requestAnimationFrame(v):cancelAnimationFrame(g);});},{threshold:0});G.observe(u);let D;function T(){clearTimeout(D),D=setTimeout(()=>{A.forEach(({elements:n,lengths:m})=>{n.forEach((l,a)=>{m[a]=P(l),l.style.strokeDasharray=`${m[a]}`;});}),z();},150);}return window.addEventListener("resize",T),window.addEventListener("orientationchange",T),{destroy(){cancelAnimationFrame(g),clearTimeout(D),G.disconnect(),window.removeEventListener("resize",T),window.removeEventListener("orientationchange",T);},replay(){y=-1,I=false,h=false,A.forEach(({elements:n,lengths:m,fade:l})=>{n.forEach((a,p)=>{a.style.strokeDashoffset=`${m[p]}`,l&&(a.style.opacity="0");});}),u.style.setProperty("--scroll-draw-progress","0");},pause(){h=true,cancelAnimationFrame(g);},resume(){h&&(h=false,E&&(g=requestAnimationFrame(v)));},seek(n){x=Math.min(1,Math.max(0,n)),y=x,h=true,cancelAnimationFrame(g),C(x);},getProgress(){return x}}}exports.scrollDrawTimeline=ee;
1
+ 'use strict';function ie({bounces:e=3,decay:n=.5}={}){let r=Math.max(1,Math.round(e)),o=Math.max(.01,Math.min(.99,n)),p=Math.sqrt(o),m=0,y=[];for(let a=0;a<r;a++){let c=Math.pow(p,a);y.push(c),m+=c;}let d=[0],h=0;for(let a=0;a<r;a++)h+=y[a]/m,d.push(h);return a=>{if(a<=0)return 0;if(a>=1)return 1;for(let c=0;c<r;c++)if(a<=d[c+1]){let f=(a-d[c])/(d[c+1]-d[c]);if(c===0)return f*(2-f);let T=1-Math.pow(o,c);return T+(1-T)*(2*f-1)*(2*f-1)}return 1}}function se({amplitude:e=1,period:n=.4}={}){let r=Math.max(1,e),o=Math.max(.1,n),p=r<=1?o/4:o/(2*Math.PI)*Math.asin(1/r);return m=>m<=0?0:m>=1?1:r*Math.pow(2,-10*m)*Math.sin((m-p)*(2*Math.PI)/o)+1}var R={linear:e=>e,"ease-in":e=>e*e,"ease-out":e=>e*(2-e),"ease-in-out":e=>e<.5?2*e*e:-1+(4-2*e)*e,spring:e=>1-Math.cos(e*Math.PI*2.5)*Math.pow(1-e,2.2),bounce:ie(),elastic:se()};function G(e="top bottom"){let n=e.trim();if(/^\d+(\.\d+)?%$/.test(n))return {element:"top",viewport:n};let[r="top",o="bottom"]=n.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function X(e,n,r,o){switch(o){case "top":return e+r;case "center":return e+r+n/2;case "bottom":return e+r+n;default:return e+r}}function _(e,n){if(/^\d+(\.\d+)?%$/.test(e))return n*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return n/2;case "bottom":return n;default:return n}}function q(e){let n=e.tagName.toLowerCase();if(n==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(n==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ae(e,n,r){return Math.min(r,Math.max(n,e))}function J(e,n,r,o){return r===n?0:ae((e-n)/(r-n)*o,0,1)}function K(e,n,r,o,p){let m=X(e.top,e.height,n,o.element)-_(o.viewport,r),y=X(e.top,e.height,n,p.element)-_(p.viewport,r);return {tStart:m,tEnd:y}}var Q=["#ff90e8","#ffc900","#5865F2","#22c55e","#f59e0b","#ef4444","#aaa","#60a5fa"];function ce(e,n){let r={destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};if(typeof window>"u")return r;let o=typeof e=="string"?document.querySelector(e):e;if(!o)return console.warn("[svg-scroll-draw/timeline] Container not found:",e),r;let p=o,{trigger:m={},speed:y=1,once:d=false,axis:h="y",tracks:a,onComplete:c,repeat:f,repeatDelay:T=0,debug:Z=false,label:Y}=n,ee=G(m.start??"top bottom"),te=G(m.end??"bottom top"),I=f==="infinite"?1/0:f??0,k,L=a.map(t=>{let u=typeof t.easing=="function"?t.easing:R[t.easing??"linear"]??R.linear,l=Array.from(p.querySelectorAll(t.selector)),s=l.map(i=>q(i));return l.forEach((i,b)=>{i.style.strokeDasharray=`${s[b]}`,i.style.strokeDashoffset=`${s[b]}`,t.fade&&(i.style.opacity="0");}),{...t,elements:l,lengths:s,easeFn:u}}),O=0,N=0,$=false,x=false,w=0,S=false,M=-1,E=0,g=null;Z&&(g=document.createElement("div"),Object.assign(g.style,{position:"fixed",bottom:"16px",left:"16px",zIndex:"9999",background:"rgba(0,0,0,0.88)",backdropFilter:"blur(8px)",border:"1px solid rgba(255,255,255,0.1)",borderRadius:"10px",padding:"10px 14px",fontFamily:"monospace",fontSize:"11px",color:"#fff",minWidth:"240px",pointerEvents:"none",lineHeight:"1.4"}),document.body.appendChild(g));function ne(t){if(!g)return;let u=Y??(typeof e=="string"?e:"timeline"),l=a.map(({selector:s,from:i,to:b},C)=>{let v=Q[C%Q.length],A=b>i?Math.min(1,Math.max(0,(t-i)/(b-i))):0,F=Math.round(A*100);return `<div style="margin:4px 0">
2
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:2px">
3
+ <span style="color:${v};max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${s}</span>
4
+ <span style="color:#666;margin-left:8px">${F}%</span>
5
+ </div>
6
+ <div style="height:3px;background:#2a2a2a;border-radius:2px;position:relative;overflow:hidden">
7
+ <div style="position:absolute;left:${i*100}%;width:${(b-i)*100}%;height:100%;background:${v}33;border-radius:2px"></div>
8
+ <div style="position:absolute;left:${i*100}%;width:${(b-i)*A*100}%;height:100%;background:${v};border-radius:2px;transition:width 0.05s linear"></div>
9
+ </div>
10
+ </div>`}).join("");g.innerHTML=`
11
+ <div style="color:#555;margin-bottom:8px;font-size:10px;text-transform:uppercase;letter-spacing:0.12em;border-bottom:1px solid rgba(255,255,255,0.06);padding-bottom:6px">
12
+ scrollDrawTimeline \xB7 ${u}
13
+ </div>
14
+ ${l}
15
+ <div style="margin-top:6px;padding-top:6px;border-top:1px solid rgba(255,255,255,0.06)">
16
+ <div style="display:flex;justify-content:space-between;margin-bottom:2px">
17
+ <span style="color:#555">scroll</span>
18
+ <span style="color:#666">${Math.round(t*100)}%</span>
19
+ </div>
20
+ <div style="height:2px;background:#2a2a2a;border-radius:1px;overflow:hidden">
21
+ <div style="height:100%;background:#fff;border-radius:1px;width:${t*100}%;transition:width 0.05s linear"></div>
22
+ </div>
23
+ </div>`;}function j(){return h==="x"?window.scrollX:window.scrollY}function re(){return h==="x"?window.innerWidth:window.innerHeight}function B(){let t=p.getBoundingClientRect(),u=j(),l=h==="x"?t.left:t.top,s=h==="x"?t.width:t.height,i=K({top:l,height:s},u,re(),ee,te);O=i.tStart,N=i.tEnd;}function V(t){p.style.setProperty("--scroll-draw-progress",String(t)),L.forEach(({elements:u,lengths:l,from:s,to:i,easeFn:b,fade:C})=>{let v=i-s,A=v>0?Math.min(1,Math.max(0,(t-s)/v)):0,F=b(A);u.forEach((U,oe)=>{U.style.strokeDashoffset=`${l[oe]*(1-F)}`,C&&(U.style.opacity=String(F));});}),ne(t);}function W(){M=-1,S=false,L.forEach(({elements:t,lengths:u,fade:l})=>{t.forEach((s,i)=>{s.style.strokeDashoffset=`${u[i]}`,l&&(s.style.opacity="0");});}),p.style.setProperty("--scroll-draw-progress","0");}function P(){if(!$||x)return;let t=J(j(),O,N,y);d&&(M=Math.max(M,t),t=M),E=t,V(t),t>=1&&!S?(S=true,c?.(),I>0&&d&&(k=setTimeout(()=>{I!==1/0&&I--,W();},T))):t<1&&!d&&(S=false),w=requestAnimationFrame(P);}B();let H=new IntersectionObserver(t=>{t.forEach(u=>{$=u.isIntersecting,$&&!x?w=requestAnimationFrame(P):cancelAnimationFrame(w);});},{threshold:0});H.observe(p);let z;function D(){clearTimeout(z),z=setTimeout(()=>{L.forEach(({elements:t,lengths:u})=>{t.forEach((l,s)=>{u[s]=q(l),l.style.strokeDasharray=`${u[s]}`;});}),B();},150);}return window.addEventListener("resize",D),window.addEventListener("orientationchange",D),{destroy(){cancelAnimationFrame(w),clearTimeout(z),clearTimeout(k),H.disconnect(),window.removeEventListener("resize",D),window.removeEventListener("orientationchange",D),g&&(g.remove(),g=null);},replay(){I=f==="infinite"?1/0:f??0,clearTimeout(k),W(),x=false;},pause(){x=true,cancelAnimationFrame(w);},resume(){x&&(x=false,$&&(w=requestAnimationFrame(P)));},seek(t){E=Math.min(1,Math.max(0,t)),M=E,x=true,cancelAnimationFrame(w),V(E);},getProgress(){return E}}}exports.scrollDrawTimeline=ce;
@@ -41,6 +41,23 @@ interface ScrollDrawTimelineOptions {
41
41
  tracks: TimelineTrack[];
42
42
  /** Fires when all tracks have reached their full draw progress. */
43
43
  onComplete?: () => void;
44
+ /**
45
+ * Replay the timeline N times (or 'infinite') after it completes. Works with
46
+ * `once: true` — after completion + delay, paths reset and the animation plays
47
+ * again on the next scroll-into-view. With `once: false` (default) the timeline
48
+ * already reverses naturally on scroll-up, so repeat is a no-op.
49
+ */
50
+ repeat?: number | 'infinite';
51
+ /** Milliseconds to wait before each repeat. Default 0. */
52
+ repeatDelay?: number;
53
+ /**
54
+ * Show a developer overlay panel visualising each track's window and live
55
+ * fill progress. Injected into document.body as a fixed HUD, removed on destroy().
56
+ * Useful for tuning `from`/`to` values without guessing.
57
+ */
58
+ debug?: boolean;
59
+ /** Label shown in the debug panel header. Defaults to the target selector string. */
60
+ label?: string;
44
61
  }
45
62
  /**
46
63
  * Animate multiple path groups with independent start/end windows within a
@@ -41,6 +41,23 @@ interface ScrollDrawTimelineOptions {
41
41
  tracks: TimelineTrack[];
42
42
  /** Fires when all tracks have reached their full draw progress. */
43
43
  onComplete?: () => void;
44
+ /**
45
+ * Replay the timeline N times (or 'infinite') after it completes. Works with
46
+ * `once: true` — after completion + delay, paths reset and the animation plays
47
+ * again on the next scroll-into-view. With `once: false` (default) the timeline
48
+ * already reverses naturally on scroll-up, so repeat is a no-op.
49
+ */
50
+ repeat?: number | 'infinite';
51
+ /** Milliseconds to wait before each repeat. Default 0. */
52
+ repeatDelay?: number;
53
+ /**
54
+ * Show a developer overlay panel visualising each track's window and live
55
+ * fill progress. Injected into document.body as a fixed HUD, removed on destroy().
56
+ * Useful for tuning `from`/`to` values without guessing.
57
+ */
58
+ debug?: boolean;
59
+ /** Label shown in the debug panel header. Defaults to the target selector string. */
60
+ label?: string;
44
61
  }
45
62
  /**
46
63
  * Animate multiple path groups with independent start/end windows within a
@@ -1 +1,23 @@
1
- function U({bounces:e=3,decay:t=.5}={}){let r=Math.max(1,Math.round(e)),o=Math.max(.01,Math.min(.99,t)),u=Math.sqrt(o),c=0,d=[];for(let s=0;s<r;s++){let i=Math.pow(u,s);d.push(i),c+=i;}let f=[0],b=0;for(let s=0;s<r;s++)b+=d[s]/c,f.push(b);return s=>{if(s<=0)return 0;if(s>=1)return 1;for(let i=0;i<r;i++)if(s<=f[i+1]){let w=(s-f[i])/(f[i+1]-f[i]);if(i===0)return w*(2-w);let M=1-Math.pow(o,i);return M+(1-M)*(2*w-1)*(2*w-1)}return 1}}function Z({amplitude:e=1,period:t=.4}={}){let r=Math.max(1,e),o=Math.max(.1,t),u=r<=1?o/4:o/(2*Math.PI)*Math.asin(1/r);return c=>c<=0?0:c>=1?1:r*Math.pow(2,-10*c)*Math.sin((c-u)*(2*Math.PI)/o)+1}var $={linear:e=>e,"ease-in":e=>e*e,"ease-out":e=>e*(2-e),"ease-in-out":e=>e<.5?2*e*e:-1+(4-2*e)*e,spring:e=>1-Math.cos(e*Math.PI*2.5)*Math.pow(1-e,2.2),bounce:U(),elastic:Z()};function F(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[r="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function V(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function B(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function P(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function _(e,t,r){return Math.min(r,Math.max(t,e))}function W(e,t,r,o){return r===t?0:_((e-t)/(r-t)*o,0,1)}function X(e,t,r,o,u){let c=V(e.top,e.height,t,o.element)-B(o.viewport,r),d=V(e.top,e.height,t,u.element)-B(u.viewport,r);return {tStart:c,tEnd:d}}function ee(e,t){let r={destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};if(typeof window>"u")return r;let o=typeof e=="string"?document.querySelector(e):e;if(!o)return console.warn("[svg-scroll-draw/timeline] Container not found:",e),r;let u=o,{trigger:c={},speed:d=1,once:f=false,axis:b="y",tracks:s,onComplete:i}=t,w=F(c.start??"top bottom"),M=F(c.end??"bottom top"),A=s.map(n=>{let m=typeof n.easing=="function"?n.easing:$[n.easing??"linear"]??$.linear,l=Array.from(u.querySelectorAll(n.selector)),a=l.map(p=>P(p));return l.forEach((p,S)=>{p.style.strokeDasharray=`${a[S]}`,p.style.strokeDashoffset=`${a[S]}`,n.fade&&(p.style.opacity="0");}),{...n,elements:l,lengths:a,easeFn:m}}),L=0,k=0,E=false,h=false,g=0,I=false,y=-1,x=0;function q(){return b==="x"?window.scrollX:window.scrollY}function j(){return b==="x"?window.innerWidth:window.innerHeight}function z(){let n=u.getBoundingClientRect(),m=q(),l=b==="x"?n.left:n.top,a=b==="x"?n.width:n.height,p=X({top:l,height:a},m,j(),w,M);L=p.tStart,k=p.tEnd;}function C(n){u.style.setProperty("--scroll-draw-progress",String(n)),A.forEach(({elements:m,lengths:l,from:a,to:p,easeFn:S,fade:J})=>{let N=p-a,K=N>0?Math.min(1,Math.max(0,(n-a)/N)):0,R=S(K);m.forEach((O,Q)=>{O.style.strokeDashoffset=`${l[Q]*(1-R)}`,J&&(O.style.opacity=String(R));});});}function v(){if(!E||h)return;let n=W(q(),L,k,d);f&&(y=Math.max(y,n),n=y),x=n,C(n),n>=1&&!I?(I=true,i?.()):n<1&&!f&&(I=false),g=requestAnimationFrame(v);}z();let G=new IntersectionObserver(n=>{n.forEach(m=>{E=m.isIntersecting,E&&!h?g=requestAnimationFrame(v):cancelAnimationFrame(g);});},{threshold:0});G.observe(u);let D;function T(){clearTimeout(D),D=setTimeout(()=>{A.forEach(({elements:n,lengths:m})=>{n.forEach((l,a)=>{m[a]=P(l),l.style.strokeDasharray=`${m[a]}`;});}),z();},150);}return window.addEventListener("resize",T),window.addEventListener("orientationchange",T),{destroy(){cancelAnimationFrame(g),clearTimeout(D),G.disconnect(),window.removeEventListener("resize",T),window.removeEventListener("orientationchange",T);},replay(){y=-1,I=false,h=false,A.forEach(({elements:n,lengths:m,fade:l})=>{n.forEach((a,p)=>{a.style.strokeDashoffset=`${m[p]}`,l&&(a.style.opacity="0");});}),u.style.setProperty("--scroll-draw-progress","0");},pause(){h=true,cancelAnimationFrame(g);},resume(){h&&(h=false,E&&(g=requestAnimationFrame(v)));},seek(n){x=Math.min(1,Math.max(0,n)),y=x,h=true,cancelAnimationFrame(g),C(x);},getProgress(){return x}}}export{ee as scrollDrawTimeline};
1
+ function ie({bounces:e=3,decay:n=.5}={}){let r=Math.max(1,Math.round(e)),o=Math.max(.01,Math.min(.99,n)),p=Math.sqrt(o),m=0,y=[];for(let a=0;a<r;a++){let c=Math.pow(p,a);y.push(c),m+=c;}let d=[0],h=0;for(let a=0;a<r;a++)h+=y[a]/m,d.push(h);return a=>{if(a<=0)return 0;if(a>=1)return 1;for(let c=0;c<r;c++)if(a<=d[c+1]){let f=(a-d[c])/(d[c+1]-d[c]);if(c===0)return f*(2-f);let T=1-Math.pow(o,c);return T+(1-T)*(2*f-1)*(2*f-1)}return 1}}function se({amplitude:e=1,period:n=.4}={}){let r=Math.max(1,e),o=Math.max(.1,n),p=r<=1?o/4:o/(2*Math.PI)*Math.asin(1/r);return m=>m<=0?0:m>=1?1:r*Math.pow(2,-10*m)*Math.sin((m-p)*(2*Math.PI)/o)+1}var R={linear:e=>e,"ease-in":e=>e*e,"ease-out":e=>e*(2-e),"ease-in-out":e=>e<.5?2*e*e:-1+(4-2*e)*e,spring:e=>1-Math.cos(e*Math.PI*2.5)*Math.pow(1-e,2.2),bounce:ie(),elastic:se()};function G(e="top bottom"){let n=e.trim();if(/^\d+(\.\d+)?%$/.test(n))return {element:"top",viewport:n};let[r="top",o="bottom"]=n.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function X(e,n,r,o){switch(o){case "top":return e+r;case "center":return e+r+n/2;case "bottom":return e+r+n;default:return e+r}}function _(e,n){if(/^\d+(\.\d+)?%$/.test(e))return n*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return n/2;case "bottom":return n;default:return n}}function q(e){let n=e.tagName.toLowerCase();if(n==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(n==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ae(e,n,r){return Math.min(r,Math.max(n,e))}function J(e,n,r,o){return r===n?0:ae((e-n)/(r-n)*o,0,1)}function K(e,n,r,o,p){let m=X(e.top,e.height,n,o.element)-_(o.viewport,r),y=X(e.top,e.height,n,p.element)-_(p.viewport,r);return {tStart:m,tEnd:y}}var Q=["#ff90e8","#ffc900","#5865F2","#22c55e","#f59e0b","#ef4444","#aaa","#60a5fa"];function ce(e,n){let r={destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};if(typeof window>"u")return r;let o=typeof e=="string"?document.querySelector(e):e;if(!o)return console.warn("[svg-scroll-draw/timeline] Container not found:",e),r;let p=o,{trigger:m={},speed:y=1,once:d=false,axis:h="y",tracks:a,onComplete:c,repeat:f,repeatDelay:T=0,debug:Z=false,label:Y}=n,ee=G(m.start??"top bottom"),te=G(m.end??"bottom top"),I=f==="infinite"?1/0:f??0,k,L=a.map(t=>{let u=typeof t.easing=="function"?t.easing:R[t.easing??"linear"]??R.linear,l=Array.from(p.querySelectorAll(t.selector)),s=l.map(i=>q(i));return l.forEach((i,b)=>{i.style.strokeDasharray=`${s[b]}`,i.style.strokeDashoffset=`${s[b]}`,t.fade&&(i.style.opacity="0");}),{...t,elements:l,lengths:s,easeFn:u}}),O=0,N=0,$=false,x=false,w=0,S=false,M=-1,E=0,g=null;Z&&(g=document.createElement("div"),Object.assign(g.style,{position:"fixed",bottom:"16px",left:"16px",zIndex:"9999",background:"rgba(0,0,0,0.88)",backdropFilter:"blur(8px)",border:"1px solid rgba(255,255,255,0.1)",borderRadius:"10px",padding:"10px 14px",fontFamily:"monospace",fontSize:"11px",color:"#fff",minWidth:"240px",pointerEvents:"none",lineHeight:"1.4"}),document.body.appendChild(g));function ne(t){if(!g)return;let u=Y??(typeof e=="string"?e:"timeline"),l=a.map(({selector:s,from:i,to:b},C)=>{let v=Q[C%Q.length],A=b>i?Math.min(1,Math.max(0,(t-i)/(b-i))):0,F=Math.round(A*100);return `<div style="margin:4px 0">
2
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:2px">
3
+ <span style="color:${v};max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${s}</span>
4
+ <span style="color:#666;margin-left:8px">${F}%</span>
5
+ </div>
6
+ <div style="height:3px;background:#2a2a2a;border-radius:2px;position:relative;overflow:hidden">
7
+ <div style="position:absolute;left:${i*100}%;width:${(b-i)*100}%;height:100%;background:${v}33;border-radius:2px"></div>
8
+ <div style="position:absolute;left:${i*100}%;width:${(b-i)*A*100}%;height:100%;background:${v};border-radius:2px;transition:width 0.05s linear"></div>
9
+ </div>
10
+ </div>`}).join("");g.innerHTML=`
11
+ <div style="color:#555;margin-bottom:8px;font-size:10px;text-transform:uppercase;letter-spacing:0.12em;border-bottom:1px solid rgba(255,255,255,0.06);padding-bottom:6px">
12
+ scrollDrawTimeline \xB7 ${u}
13
+ </div>
14
+ ${l}
15
+ <div style="margin-top:6px;padding-top:6px;border-top:1px solid rgba(255,255,255,0.06)">
16
+ <div style="display:flex;justify-content:space-between;margin-bottom:2px">
17
+ <span style="color:#555">scroll</span>
18
+ <span style="color:#666">${Math.round(t*100)}%</span>
19
+ </div>
20
+ <div style="height:2px;background:#2a2a2a;border-radius:1px;overflow:hidden">
21
+ <div style="height:100%;background:#fff;border-radius:1px;width:${t*100}%;transition:width 0.05s linear"></div>
22
+ </div>
23
+ </div>`;}function j(){return h==="x"?window.scrollX:window.scrollY}function re(){return h==="x"?window.innerWidth:window.innerHeight}function B(){let t=p.getBoundingClientRect(),u=j(),l=h==="x"?t.left:t.top,s=h==="x"?t.width:t.height,i=K({top:l,height:s},u,re(),ee,te);O=i.tStart,N=i.tEnd;}function V(t){p.style.setProperty("--scroll-draw-progress",String(t)),L.forEach(({elements:u,lengths:l,from:s,to:i,easeFn:b,fade:C})=>{let v=i-s,A=v>0?Math.min(1,Math.max(0,(t-s)/v)):0,F=b(A);u.forEach((U,oe)=>{U.style.strokeDashoffset=`${l[oe]*(1-F)}`,C&&(U.style.opacity=String(F));});}),ne(t);}function W(){M=-1,S=false,L.forEach(({elements:t,lengths:u,fade:l})=>{t.forEach((s,i)=>{s.style.strokeDashoffset=`${u[i]}`,l&&(s.style.opacity="0");});}),p.style.setProperty("--scroll-draw-progress","0");}function P(){if(!$||x)return;let t=J(j(),O,N,y);d&&(M=Math.max(M,t),t=M),E=t,V(t),t>=1&&!S?(S=true,c?.(),I>0&&d&&(k=setTimeout(()=>{I!==1/0&&I--,W();},T))):t<1&&!d&&(S=false),w=requestAnimationFrame(P);}B();let H=new IntersectionObserver(t=>{t.forEach(u=>{$=u.isIntersecting,$&&!x?w=requestAnimationFrame(P):cancelAnimationFrame(w);});},{threshold:0});H.observe(p);let z;function D(){clearTimeout(z),z=setTimeout(()=>{L.forEach(({elements:t,lengths:u})=>{t.forEach((l,s)=>{u[s]=q(l),l.style.strokeDasharray=`${u[s]}`;});}),B();},150);}return window.addEventListener("resize",D),window.addEventListener("orientationchange",D),{destroy(){cancelAnimationFrame(w),clearTimeout(z),clearTimeout(k),H.disconnect(),window.removeEventListener("resize",D),window.removeEventListener("orientationchange",D),g&&(g.remove(),g=null);},replay(){I=f==="infinite"?1/0:f??0,clearTimeout(k),W(),x=false;},pause(){x=true,cancelAnimationFrame(w);},resume(){x&&(x=false,$&&(w=requestAnimationFrame(P)));},seek(t){E=Math.min(1,Math.max(0,t)),M=E,x=true,cancelAnimationFrame(w),V(E);},getProgress(){return E}}}export{ce as scrollDrawTimeline};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svg-scroll-draw",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Scroll-driven SVG path drawing animation library — zero dependencies, ~4.4 KB gzipped, works with React, Vue, and vanilla JS",
5
5
  "keywords": [
6
6
  "svg",