UNPKG

v12-ui

Version:

A React component library with a focus on utility-first design and accessibility.

2 lines (1 loc) 7.38 kB
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("react/jsx-runtime"),w=require("react"),E=require("../utils/utils.cjs");class M{canvas;ctx;particles=[];mouse=null;animationId=null;dpr;config;imageElement=null;constructor(e,s){this.canvas=e;const i=e.getContext("2d",{willReadFrequently:!0});if(!i)throw new Error("No se pudo obtener el contexto 2D del canvas");this.ctx=i,this.dpr=window.devicePixelRatio||1,this.config=s,this.setupCanvas(),this.initializeEffect()}async initializeEffect(){try{this.config.imageUrl?(console.log("MagicLogo: Cargando imagen desde URL:",this.config.imageUrl),await this.loadImage(this.config.imageUrl)):this.config.svgContent?(console.log("MagicLogo: Cargando SVG como imagen"),await this.loadSVGAsImage(this.config.svgContent)):this.config.imageElement&&(console.log("MagicLogo: Cargando elemento de imagen existente"),await this.loadImageElement(this.config.imageElement)),console.log("MagicLogo: Imagen cargada exitosamente, generando partículas..."),this.generateParticles(),this.setupEventListeners(),this.animate=this.animate.bind(this),this.animate()}catch(e){console.error("MagicLogo: Error al inicializar el efecto:",e)}}async loadImage(e){return await new Promise((s,i)=>{const t=new Image,o=()=>{this.imageElement=t,t.removeEventListener("load",o),t.removeEventListener("error",a),s()},a=r=>{t.removeEventListener("load",o),t.removeEventListener("error",a),i(new Error(`Error al cargar la imagen desde URL: ${e} - ${r.type}`))};t.addEventListener("load",o),t.addEventListener("error",a),t.crossOrigin="anonymous",t.src=e,setTimeout(()=>{t.removeEventListener("load",o),t.removeEventListener("error",a),i(new Error(`Timeout: La imagen desde URL ${e} tardó demasiado en cargar`))},1e4)})}async loadImageElement(e){return await new Promise((s,i)=>{if(e.complete&&e.naturalWidth>0)this.imageElement=e,s();else{const t=()=>{this.imageElement=e,e.removeEventListener("load",t),e.removeEventListener("error",o),s()},o=a=>{e.removeEventListener("load",t),e.removeEventListener("error",o),i(new Error(`Error al cargar la imagen: ${a.type}`))};e.addEventListener("load",t),e.addEventListener("error",o),setTimeout(()=>{e.removeEventListener("load",t),e.removeEventListener("error",o),i(new Error("Timeout: La imagen tardó demasiado en cargar"))},1e4)}})}async loadSVGAsImage(e){return await new Promise((s,i)=>{const t=new Blob([e],{type:"image/svg+xml"}),o=URL.createObjectURL(t),a=new Image,r=()=>{this.imageElement=a,URL.revokeObjectURL(o),a.removeEventListener("load",r),a.removeEventListener("error",n),s()},n=c=>{URL.revokeObjectURL(o),a.removeEventListener("load",r),a.removeEventListener("error",n),i(new Error(`Error al cargar SVG como imagen: ${c.type}`))};a.addEventListener("load",r),a.addEventListener("error",n),a.crossOrigin="anonymous",a.src=o,setTimeout(()=>{URL.revokeObjectURL(o),a.removeEventListener("load",r),a.removeEventListener("error",n),i(new Error("Timeout: El SVG tardó demasiado en cargar"))},1e4)})}setupCanvas(){const e=this.canvas.getBoundingClientRect();this.canvas.width=e.width*this.dpr,this.canvas.height=e.height*this.dpr,this.canvas.style.width=`${e.width}px`,this.canvas.style.height=`${e.height}px`,this.ctx.scale(this.dpr,this.dpr),this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality&&(this.ctx.imageSmoothingQuality="high")}createImageMask(){return this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.imageElement&&this.drawImageToCanvas(this.imageElement),this.ctx.getImageData(0,0,this.canvas.width,this.canvas.height)}drawImageToCanvas(e){const s=this.canvas.width/this.dpr,i=this.canvas.height/this.dpr,o=Math.min(s/e.naturalWidth,i/e.naturalHeight)*.8,a=e.naturalWidth*o,r=e.naturalHeight*o,n=(s-a)/2,c=(i-r)/2;this.ctx.drawImage(e,n,c,a,r)}extractPositions(e){const s=[],{data:i,width:t,height:o}=e,r=Math.max(1,4);let n=0;for(let h=0;h<i.length;h+=4){const[d,u,g,m]=i.slice(h,h+4);m>50&&(d<220||u<220||g<220)&&n++}const c=Math.max(1,Math.floor(Math.sqrt(n/(this.config.particles||6e3)))),l=Math.min(r,c);for(let h=0;h<o;h+=l)for(let d=0;d<t;d+=l){const u=(h*t+d)*4,[g,m,v,x]=i.slice(u,u+4);x>50&&(g<220||m<220||v<220)&&s.push({x:d/this.dpr,y:h/this.dpr,color:`rgb(${g},${m},${v})`})}return s}generateParticles(){if(!this.imageElement){console.warn("No hay imagen cargada para generar partículas");return}const e=this.createImageMask(),s=this.extractPositions(e);if(s.length===0){console.warn("No se encontraron píxeles visibles en la imagen");return}const i=Math.max(this.canvas.width,this.canvas.height)*2;this.particles=s.map(t=>({tx:t.x,ty:t.y,x:t.x+(Math.random()-.5)*i,y:t.y+(Math.random()-.5)*i,vx:0,vy:0,color:t.color,phase:Math.random()*Math.PI*2,age:0,isImmune:Math.random()<.05}))}updateParticle(e){const s=e.tx-e.x,i=e.ty-e.y;if(this.mouse&&this.config.attractMode){const a=this.mouse.x-e.x,r=this.mouse.y-e.y,n=Math.hypot(a,r);if(n<this.config.repulsion&&n>0){const l=10*Math.max(0,1-n/this.config.repulsion);e.vx+=a/n*l,e.vy+=r/n*l}}else if(this.mouse&&!this.config.attractMode){const a=this.mouse.x-e.x,r=this.mouse.y-e.y,n=Math.hypot(a,r);if(n<this.config.repulsion&&n>0){let c;this.config.trace?e.isImmune?c=(this.config.repulsion-n)/this.config.repulsion*.1:c=Math.max(0,1-n/this.config.repulsion):c=Math.max(0,1-n/this.config.repulsion);const l=20*c;e.vx-=a/n*l,e.vy-=r/n*l}}const t=.04,o=.73;e.vx+=s*t,e.vy+=i*t,e.vx*=o,e.vy*=o,e.x+=e.vx,e.y+=e.vy}drawParticles(){const e=this.canvas.width/this.dpr,s=this.canvas.height/this.dpr;this.ctx.clearRect(0,0,e,s);for(const i of this.particles){this.updateParticle(i),i.age+=1;const t=(Math.sin(i.phase+i.age*.15)+1)/2;this.ctx.fillStyle=this.config.color||i.color||"#fff",this.config.glow&&(this.ctx.globalAlpha=t),this.ctx.beginPath(),this.ctx.arc(i.x,i.y,this.config.dotSize,0,Math.PI*2),this.ctx.fill()}this.ctx.globalAlpha=1}handleMouseMove=e=>{const s=this.canvas.getBoundingClientRect();this.mouse={x:(e.clientX-s.left)*(this.canvas.width/this.dpr/s.width),y:(e.clientY-s.top)*(this.canvas.height/this.dpr/s.height)}};handleMouseLeave=()=>{this.mouse=null};animate(){this.drawParticles(),this.animationId=requestAnimationFrame(this.animate)}setupEventListeners(){this.canvas.addEventListener("mousemove",this.handleMouseMove),this.canvas.addEventListener("mouseleave",this.handleMouseLeave)}destroy(){this.canvas.removeEventListener("mousemove",this.handleMouseMove),this.canvas.removeEventListener("mouseleave",this.handleMouseLeave),this.animationId&&cancelAnimationFrame(this.animationId)}}function p({imageUrl:f,imageElement:e,svgContent:s,particles:i=750,dotSize:t=.9,repulsion:o=80,friction:a=.82,returnSpeed:r=.01,color:n,glow:c=!0,trace:l=!0,attractMode:h=!1,className:d,...u}){const g=w.useRef(null);return w.useEffect(()=>{const m=g.current;if(!m)return;if(e&&(!e.complete||e.naturalWidth===0)){console.warn("MagicLogo: imageElement no está completamente cargado");return}let v;if(f!=null)v={imageUrl:f};else if(e!=null)v={imageElement:e};else if(s!=null)v={svgContent:s};else{console.warn("MagicLogo: falta una fuente de imagen");return}const x={particles:i,dotSize:t,repulsion:o,friction:a,returnSpeed:r,color:n,glow:c,trace:l,attractMode:h,...v},L=new M(m,x);return()=>{L&&L.destroy()}},[f,e,s,i,t,o,a,r,n,c,l,h]),y.jsx("canvas",{ref:g,...u,className:E.cn("block mx-auto overflow-visible z-0 w-auto h-auto",d)})}exports.MagicLogo=p;