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
JavaScript
;
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