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.
- package/dist/timeline/index.cjs +23 -1
- package/dist/timeline/index.d.mts +17 -0
- package/dist/timeline/index.d.ts +17 -0
- package/dist/timeline/index.mjs +23 -1
- package/package.json +1 -1
package/dist/timeline/index.cjs
CHANGED
|
@@ -1 +1,23 @@
|
|
|
1
|
-
'use strict';function
|
|
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
|
package/dist/timeline/index.d.ts
CHANGED
|
@@ -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
|
package/dist/timeline/index.mjs
CHANGED
|
@@ -1 +1,23 @@
|
|
|
1
|
-
function
|
|
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