masoneffect 0.1.19 → 0.1.21
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/index.cjs +1 -0
- package/dist/index.mjs +1 -0
- package/dist/react/MasonEffect.cjs +1 -552
- package/dist/react/MasonEffect.d.ts.map +1 -1
- package/dist/react/MasonEffect.mjs +1 -0
- package/dist/react/index.cjs +7 -0
- package/dist/react/index.mjs +1 -0
- package/dist/react/react/MasonEffect.d.ts.map +1 -1
- package/dist/react/vue/index.d.ts +5 -0
- package/dist/react/vue/index.d.ts.map +1 -0
- package/dist/vue/index.cjs +1 -0
- package/dist/vue/index.d.ts +90 -0
- package/{src/core/index.ts → dist/vue/index.mjs} +209 -242
- package/package.json +16 -12
- package/dist/index.esm.js +0 -407
- package/dist/index.esm.js.map +0 -1
- package/dist/index.esm.min.js +0 -1
- package/dist/index.js +0 -412
- package/dist/index.js.map +0 -1
- package/dist/index.min.js +0 -1
- package/dist/index.umd.js +0 -416
- package/dist/index.umd.js.map +0 -1
- package/dist/index.umd.min.js +0 -1
- package/dist/react/MasonEffect.cjs.map +0 -1
- package/dist/react/MasonEffect.js +0 -550
- package/dist/react/MasonEffect.js.map +0 -1
- package/dist/react/MasonEffect.min.cjs +0 -1
- package/dist/react/MasonEffect.min.js +0 -1
- package/dist/react/index.js +0 -549
- package/src/index.ts +0 -14
- package/src/index.umd.ts +0 -10
- package/src/react/MasonEffect.tsx +0 -235
- package/src/react/index.ts +0 -4
- package/src/vue/MasonEffect.vue +0 -140
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vue/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const t=require("vue");function e(t,e){let i=null;return function(...s){null!==i&&clearTimeout(i),i=setTimeout(()=>{i=null,t.apply(this,s)},e)}}class i{constructor(t,i={}){if(this.container="string"==typeof t?document.querySelector(t):t,!this.container)throw new Error("Container element not found");this.config={text:i.text||"mason effect",densityStep:i.densityStep??2,maxParticles:i.maxParticles??3200,pointSize:i.pointSize??.5,ease:i.ease??.05,repelRadius:i.repelRadius??150,repelStrength:i.repelStrength??1,particleColor:i.particleColor||"#fff",fontFamily:i.fontFamily||"Inter, system-ui, Arial",fontSize:i.fontSize||null,width:i.width||null,height:i.height||null,devicePixelRatio:i.devicePixelRatio??null,onReady:i.onReady||null,onUpdate:i.onUpdate||null},this.canvas=document.createElement("canvas");const s=this.canvas.getContext("2d");if(!s)throw new Error("Canvas context not available");this.ctx=s,this.container.appendChild(this.canvas),this.canvas.style.display="block",this.offCanvas=document.createElement("canvas");const n=this.offCanvas.getContext("2d");if(!n)throw new Error("Offscreen canvas context not available");this.offCtx=n,this.W=0,this.H=0,this.DPR=this.config.devicePixelRatio||Math.min(window.devicePixelRatio||1,1.8),this.particles=[],this.mouse={x:0,y:0,down:!1},this.animationId=null,this.isRunning=!1,this.isVisible=!1,this.intersectionObserver=null,this.debounceDelay=i.debounceDelay??150;const o=this.handleResize.bind(this);this.handleResize=e(o,this.debounceDelay),this.handleMouseMove=this.handleMouseMove.bind(this),this.handleMouseLeave=this.handleMouseLeave.bind(this),this.handleMouseDown=this.handleMouseDown.bind(this),this.handleMouseUp=this.handleMouseUp.bind(this),this._debouncedMorph=e(this._morphInternal.bind(this),this.debounceDelay),this._debouncedUpdateConfig=e(this._updateConfigInternal.bind(this),this.debounceDelay),this.init()}init(){this.resize(),this.setupEventListeners(),this.setupIntersectionObserver(),this.config.onReady&&this.config.onReady(this)}setupIntersectionObserver(){if("undefined"==typeof window||void 0===window.IntersectionObserver)return this.isVisible=!0,void this.start();this.intersectionObserver||(this.intersectionObserver=new IntersectionObserver(t=>{for(const e of t)e.target===this.container&&(e.isIntersecting?(this.isVisible=!0,this.start()):(this.isVisible=!1,this.stop()))},{threshold:.1}),this.intersectionObserver.observe(this.container))}resize(){const t=this.config.width||this.container.clientWidth||window.innerWidth,e=this.config.height||this.container.clientHeight||.7*window.innerHeight;if(t<=0||e<=0)return;this.W=Math.floor(t*this.DPR),this.H=Math.floor(e*this.DPR);const i=4096;if(this.W>i||this.H>i){const t=Math.min(i/this.W,i/this.H);this.W=Math.floor(this.W*t),this.H=Math.floor(this.H*t),this.DPR=this.DPR*t}this.canvas.width=this.W,this.canvas.height=this.H,this.canvas.style.width=t+"px",this.canvas.style.height=e+"px",this.W>0&&this.H>0&&(this.buildTargets(),this.particles.length||this.initParticles())}buildTargets(){if(this.W<=0||this.H<=0)return;const t=this.config.text;this.offCanvas.width=this.W,this.offCanvas.height=this.H,this.offCtx.clearRect(0,0,this.offCanvas.width,this.offCanvas.height);const e=Math.min(this.W,this.H),i=this.config.fontSize||Math.max(80,Math.floor(.18*e));this.offCtx.fillStyle="#ffffff",this.offCtx.textAlign="center",this.offCtx.textBaseline="middle",this.offCtx.font=`400 ${i}px ${this.config.fontFamily}`;const s=t.split(""),n=.05*i,o=this.offCtx.measureText(t).width+n*(s.length-1);let a=this.W/2-o/2;for(const d of s)this.offCtx.fillText(d,a+this.offCtx.measureText(d).width/2,this.H/2),a+=this.offCtx.measureText(d).width+n;const h=Math.max(2,this.config.densityStep),l=this.offCtx.getImageData(0,0,this.W,this.H).data,r=[];for(let d=0;d<this.H;d+=h)for(let t=0;t<this.W;t+=h){const e=4*(d*this.W+t);l[e]+l[e+1]+l[e+2]>600&&r.push({x:t,y:d})}for(;r.length>this.config.maxParticles;)r.splice(Math.floor(Math.random()*r.length),1);if(this.particles.length<r.length){const t=r.length-this.particles.length;for(let e=0;e<t;e++)this.particles.push(this.makeParticle())}else this.particles.length>r.length&&(this.particles.length=r.length);for(let d=0;d<this.particles.length;d++){const t=this.particles[d],e=r[d];t.tx=e.x,t.ty=e.y}}makeParticle(){const t=Math.random()*this.W,e=Math.random()*this.H;return{x:t,y:e,vx:0,vy:0,tx:t,ty:e,initialX:t,initialY:e,j:Math.random()*Math.PI*2}}initParticles(){for(const t of this.particles){const e=Math.random()*this.W,i=Math.random()*this.H;t.x=e,t.y=i,t.vx=t.vy=0,t.initialX=e,t.initialY=i}}scatter(){for(const t of this.particles)void 0!==t.initialX&&void 0!==t.initialY?(t.tx=t.initialX,t.ty=t.initialY):(t.initialX=t.x,t.initialY=t.y,t.tx=t.initialX,t.ty=t.initialY)}morph(t){this._debouncedMorph(t)}_morphInternal(t){if(0!==this.W&&0!==this.H||this.resize(),"string"==typeof t)this.config.text=t,this.buildTargets();else if(t&&"object"==typeof t){const e=void 0!==t.text;this.config={...this.config,...t},e&&this.buildTargets()}else this.buildTargets()}update(){this.ctx.clearRect(0,0,this.W,this.H);for(const e of this.particles){let t=(e.tx-e.x)*this.config.ease,i=(e.ty-e.y)*this.config.ease;if(this.mouse.x||this.mouse.y){const s=e.x-this.mouse.x,n=e.y-this.mouse.y,o=s*s+n*n,a=this.config.repelRadius*this.DPR;if(o<a*a){const e=Math.sqrt(o)+1e-4,h=(this.mouse.down?-1:1)*this.config.repelStrength*(1-e/a);t+=s/e*h*6,i+=n/e*h*6}}e.j+=2,t+=.05*Math.cos(e.j),i+=.05*Math.sin(1.3*e.j),e.vx=(e.vx+t)*Math.random(),e.vy=(e.vy+i)*Math.random(),e.x+=e.vx,e.y+=e.vy}this.ctx.fillStyle=this.config.particleColor;const t=this.config.pointSize*this.DPR;for(const e of this.particles)this.ctx.beginPath(),this.ctx.arc(e.x,e.y,t,0,2*Math.PI),this.ctx.fill();this.config.onUpdate&&this.config.onUpdate(this)}animate(){this.isRunning&&(this.update(),this.animationId=requestAnimationFrame(()=>this.animate()))}start(){this.isRunning||(this.isRunning=!0,this.animate())}stop(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}setupEventListeners(){window.addEventListener("resize",this.handleResize),this.canvas.addEventListener("mousemove",this.handleMouseMove),this.canvas.addEventListener("mouseleave",this.handleMouseLeave),this.canvas.addEventListener("mousedown",this.handleMouseDown),window.addEventListener("mouseup",this.handleMouseUp)}removeEventListeners(){window.removeEventListener("resize",this.handleResize),this.canvas.removeEventListener("mousemove",this.handleMouseMove),this.canvas.removeEventListener("mouseleave",this.handleMouseLeave),this.canvas.removeEventListener("mousedown",this.handleMouseDown),window.removeEventListener("mouseup",this.handleMouseUp)}handleResize(){this.resize()}handleMouseMove(t){const e=this.canvas.getBoundingClientRect();this.mouse.x=(t.clientX-e.left)*this.DPR,this.mouse.y=(t.clientY-e.top)*this.DPR}handleMouseLeave(){this.mouse.x=this.mouse.y=0}handleMouseDown(){this.mouse.down=!0}handleMouseUp(){this.mouse.down=!1}updateConfig(t){this._debouncedUpdateConfig(t)}_updateConfigInternal(t){this.config={...this.config,...t},t.text&&this.buildTargets()}destroy(){this.stop(),this.removeEventListeners(),this.intersectionObserver&&(this.intersectionObserver.disconnect(),this.intersectionObserver=null),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}const s=t.defineComponent({__name:"MasonEffect",props:{className:{default:""},style:{default:()=>({})},text:{default:"mason effect"},densityStep:{default:2},maxParticles:{default:3200},pointSize:{default:.5},ease:{default:.05},repelRadius:{default:150},repelStrength:{default:1},particleColor:{default:"#fff"},fontFamily:{default:"Inter, system-ui, Arial"},fontSize:{default:null},width:{default:null},height:{default:null},devicePixelRatio:{default:null},debounceDelay:{},onReady:{type:Function,default:null},onUpdate:{type:Function,default:null}},emits:["ready","update"],setup(e,{expose:s,emit:n}){const o=e,a=n,h=t.ref(null);let l=null;return t.watch(()=>[o.text,o.densityStep,o.maxParticles,o.pointSize,o.ease,o.repelRadius,o.repelStrength,o.particleColor,o.fontFamily,o.fontSize,o.width,o.height,o.devicePixelRatio],()=>{l&&l.updateConfig({text:o.text,densityStep:o.densityStep,maxParticles:o.maxParticles,pointSize:o.pointSize,ease:o.ease,repelRadius:o.repelRadius,repelStrength:o.repelStrength,particleColor:o.particleColor,fontFamily:o.fontFamily,fontSize:o.fontSize,width:o.width,height:o.height,devicePixelRatio:o.devicePixelRatio})}),t.onMounted(()=>{(()=>{if(!h.value)return;const t={text:o.text,densityStep:o.densityStep,maxParticles:o.maxParticles,pointSize:o.pointSize,ease:o.ease,repelRadius:o.repelRadius,repelStrength:o.repelStrength,particleColor:o.particleColor,fontFamily:o.fontFamily,fontSize:o.fontSize,width:o.width,height:o.height,devicePixelRatio:o.devicePixelRatio,onReady:t=>{o.onReady&&o.onReady(t),a("ready",t)},onUpdate:t=>{o.onUpdate&&o.onUpdate(t),a("update",t)}};l=new i(h.value,t)})()}),t.onBeforeUnmount(()=>{l&&(l.destroy(),l=null)}),s({morph:t=>{l&&l.morph(t)},scatter:()=>{l&&l.scatter()},updateConfig:t=>{l&&l.updateConfig(t)},destroy:()=>{l&&(l.destroy(),l=null)}}),(i,s)=>(t.openBlock(),t.createElementBlock("div",{ref_key:"container",ref:h,class:t.normalizeClass(e.className),style:t.normalizeStyle(e.style)},null,6))}});module.exports=s;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
declare class MasonEffect {
|
|
2
|
+
container: HTMLElement;
|
|
3
|
+
config: Required<Omit<MasonEffectOptions, 'onReady' | 'onUpdate' | 'debounceDelay'>> & {
|
|
4
|
+
onReady: MasonEffectOptions['onReady'];
|
|
5
|
+
onUpdate: MasonEffectOptions['onUpdate'];
|
|
6
|
+
};
|
|
7
|
+
canvas: HTMLCanvasElement;
|
|
8
|
+
ctx: CanvasRenderingContext2D;
|
|
9
|
+
offCanvas: HTMLCanvasElement;
|
|
10
|
+
offCtx: CanvasRenderingContext2D;
|
|
11
|
+
W: number;
|
|
12
|
+
H: number;
|
|
13
|
+
DPR: number;
|
|
14
|
+
particles: Particle[];
|
|
15
|
+
mouse: {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
down: boolean;
|
|
19
|
+
};
|
|
20
|
+
animationId: number | null;
|
|
21
|
+
isRunning: boolean;
|
|
22
|
+
isVisible: boolean;
|
|
23
|
+
intersectionObserver: IntersectionObserver | null;
|
|
24
|
+
debounceDelay: number;
|
|
25
|
+
_debouncedMorph: (textOrOptions?: string | Partial<MasonEffectOptions> | null) => void;
|
|
26
|
+
_debouncedUpdateConfig: (newConfig: Partial<MasonEffectOptions>) => void;
|
|
27
|
+
constructor(container: HTMLElement | string, options?: MasonEffectOptions);
|
|
28
|
+
init(): void;
|
|
29
|
+
setupIntersectionObserver(): void;
|
|
30
|
+
resize(): void;
|
|
31
|
+
buildTargets(): void;
|
|
32
|
+
makeParticle(): Particle;
|
|
33
|
+
initParticles(): void;
|
|
34
|
+
scatter(): void;
|
|
35
|
+
morph(textOrOptions?: string | Partial<MasonEffectOptions> | null): void;
|
|
36
|
+
_morphInternal(textOrOptions?: string | Partial<MasonEffectOptions> | null): void;
|
|
37
|
+
update(): void;
|
|
38
|
+
animate(): void;
|
|
39
|
+
start(): void;
|
|
40
|
+
stop(): void;
|
|
41
|
+
setupEventListeners(): void;
|
|
42
|
+
removeEventListeners(): void;
|
|
43
|
+
handleResize(): void;
|
|
44
|
+
handleMouseMove(e: MouseEvent): void;
|
|
45
|
+
handleMouseLeave(): void;
|
|
46
|
+
handleMouseDown(): void;
|
|
47
|
+
handleMouseUp(): void;
|
|
48
|
+
updateConfig(newConfig: Partial<MasonEffectOptions>): void;
|
|
49
|
+
_updateConfigInternal(newConfig: Partial<MasonEffectOptions>): void;
|
|
50
|
+
destroy(): void;
|
|
51
|
+
}
|
|
52
|
+
export { MasonEffect }
|
|
53
|
+
export default MasonEffect;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* MasonEffect - 파티클 모핑 효과 라이브러리
|
|
57
|
+
* 바닐라 JS 코어 클래스
|
|
58
|
+
*/
|
|
59
|
+
export declare interface MasonEffectOptions {
|
|
60
|
+
text?: string;
|
|
61
|
+
densityStep?: number;
|
|
62
|
+
maxParticles?: number;
|
|
63
|
+
pointSize?: number;
|
|
64
|
+
ease?: number;
|
|
65
|
+
repelRadius?: number;
|
|
66
|
+
repelStrength?: number;
|
|
67
|
+
particleColor?: string;
|
|
68
|
+
fontFamily?: string;
|
|
69
|
+
fontSize?: number | null;
|
|
70
|
+
width?: number | null;
|
|
71
|
+
height?: number | null;
|
|
72
|
+
devicePixelRatio?: number | null;
|
|
73
|
+
debounceDelay?: number;
|
|
74
|
+
onReady?: (instance: MasonEffect) => void;
|
|
75
|
+
onUpdate?: (instance: MasonEffect) => void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export declare interface Particle {
|
|
79
|
+
x: number;
|
|
80
|
+
y: number;
|
|
81
|
+
vx: number;
|
|
82
|
+
vy: number;
|
|
83
|
+
tx: number;
|
|
84
|
+
ty: number;
|
|
85
|
+
initialX?: number;
|
|
86
|
+
initialY?: number;
|
|
87
|
+
j: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { }
|