UNPKG

lightswind

Version:

A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.

134 lines 5.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const framer_motion_1 = require("framer-motion"); const utils_1 = require("@/components/lib/utils"); const MagicLoader = ({ size = 200, particleCount = 1, speed = 1, hueRange = [0, 360], className }) => { const canvasRef = (0, react_1.useRef)(null); const animationRef = (0, react_1.useRef)(undefined); const particlesRef = (0, react_1.useRef)([]); const tickRef = (0, react_1.useRef)(0); const globalAngleRef = (0, react_1.useRef)(0); const globalRotationRef = (0, react_1.useRef)(0); const createParticle = (0, react_1.useCallback)((centerX, centerY, tick, minSize) => { return { radius: 7, x: centerX + Math.cos(tick / 20) * minSize / 2, y: centerY + Math.sin(tick / 20) * minSize / 2, angle: globalRotationRef.current + globalAngleRef.current, speed: 0, accel: 0.01, decay: 0.01, life: 1 }; }, []); const stepParticle = (0, react_1.useCallback)((particle, index) => { particle.speed += particle.accel; particle.x += Math.cos(particle.angle) * particle.speed * speed; particle.y += Math.sin(particle.angle) * particle.speed * speed; particle.angle += Math.PI / 64; particle.accel *= 1.01; particle.life -= particle.decay; if (particle.life <= 0) { particlesRef.current.splice(index, 1); } }, [speed]); const drawParticle = (0, react_1.useCallback)((ctx, particle, index, tick) => { const hue = hueRange[0] + ((tick + (particle.life * 120)) % (hueRange[1] - hueRange[0])); ctx.fillStyle = ctx.strokeStyle = `hsla(${hue}, 100%, 60%, ${particle.life})`; // Draw line to previous particle ctx.beginPath(); if (particlesRef.current[index - 1]) { ctx.moveTo(particle.x, particle.y); ctx.lineTo(particlesRef.current[index - 1].x, particlesRef.current[index - 1].y); } ctx.stroke(); // Draw main particle circle ctx.beginPath(); ctx.arc(particle.x, particle.y, Math.max(0.001, particle.life * particle.radius), 0, Math.PI * 2); ctx.fill(); // Draw sparkle effects const sparkleSize = Math.random() * 1.25; const sparkleX = particle.x + ((Math.random() - 0.5) * 35) * particle.life; const sparkleY = particle.y + ((Math.random() - 0.5) * 35) * particle.life; ctx.fillRect(Math.floor(sparkleX), Math.floor(sparkleY), sparkleSize, sparkleSize); }, [hueRange]); const visibilityRef = (0, react_1.useRef)(true); const containerRef = (0, react_1.useRef)(null); const isInView = (0, framer_motion_1.useInView)(containerRef); (0, react_1.useEffect)(() => { visibilityRef.current = isInView; }, [isInView]); const animate = (0, react_1.useCallback)(() => { if (!visibilityRef.current) { animationRef.current = requestAnimationFrame(animate); return; } const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; const rect = canvas.getBoundingClientRect(); const centerX = rect.width / 2; const centerY = rect.height / 2; const minSize = Math.min(rect.width, rect.height) * 0.5; // Add new particles for (let i = 0; i < particleCount; i++) { particlesRef.current.push(createParticle(centerX, centerY, tickRef.current, minSize)); } // Update particles particlesRef.current.forEach((particle, index) => { stepParticle(particle, index); }); // Clear canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw particles particlesRef.current.forEach((particle, index) => { drawParticle(ctx, particle, index, tickRef.current); }); // Update global rotation globalRotationRef.current += Math.PI / 6 * speed; globalAngleRef.current += Math.PI / 6 * speed; tickRef.current++; animationRef.current = requestAnimationFrame(animate); }, [createParticle, stepParticle, drawParticle, particleCount, speed]); const setupCanvas = (0, react_1.useCallback)(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; // Set canvas size const dpr = window.devicePixelRatio || 1; canvas.width = size * dpr; canvas.height = size * dpr; canvas.style.width = `${size}px`; canvas.style.height = `${size}px`; ctx.scale(dpr, dpr); ctx.globalCompositeOperation = 'lighter'; // Reset animation state particlesRef.current = []; tickRef.current = 0; globalAngleRef.current = 0; globalRotationRef.current = 0; }, [size]); (0, react_1.useEffect)(() => { setupCanvas(); animate(); return () => { if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, [setupCanvas, animate]); return ((0, jsx_runtime_1.jsx)("div", { ref: containerRef, className: (0, utils_1.cn)("flex items-center justify-center", className), children: (0, jsx_runtime_1.jsx)("canvas", { ref: canvasRef, className: "max-w-full max-h-full", style: { width: size, height: size } }) })); }; exports.default = MagicLoader; //# sourceMappingURL=magic-loader.js.map