'use client'; import { useEffect, useRef, useCallback, useState } from 'react'; interface Particle { x: number; y: number; targetX: number; targetY: number; vx: number; vy: number; size: number; opacity: number; color: string; life: number; maxLife: number; stage: 'idle' | 'dispersing' | 'reforming'; } interface SealAnimationEnhancedProps { width?: number; height?: number; particleCount?: number; colors?: string[]; sealText?: string; animationStages?: boolean; onStageChange?: (stage: string) => void; className?: string; } export function SealAnimationEnhanced({ width = 300, height = 300, particleCount = 150, colors = ['#C41E3A', '#D4A574', '#8B4513'], sealText: _sealText = '睿新', animationStages = true, onStageChange, className = '', }: SealAnimationEnhancedProps) { const canvasRef = useRef(null); const particlesRef = useRef([]); const animationRef = useRef(null); const [_currentStage, setCurrentStage] = useState<'idle' | 'dispersing' | 'reforming'>('idle'); const stageTimerRef = useRef(null); const createSealShape = useCallback((width: number, height: number) => { const centerX = width / 2; const centerY = height / 2; const sealSize = Math.min(width, height) * 0.35; const particles: { x: number; y: number }[] = []; for (let i = 0; i < particleCount; i++) { const angle = (i / particleCount) * Math.PI * 2; const radius = sealSize * (0.8 + Math.random() * 0.4); particles.push({ x: centerX + Math.cos(angle) * radius * (Math.random() > 0.5 ? 1 : 0.8), y: centerY + Math.sin(angle) * radius * (Math.random() > 0.5 ? 1 : 0.8), }); } return particles; }, [particleCount]); const createParticle = useCallback( (x: number, y: number, targetX: number, targetY: number): Particle => { const color = colors[Math.floor(Math.random() * colors.length)] ?? '#C41E3A'; const size = 2 + Math.random() * 3; const maxLife = 200 + Math.random() * 100; return { x, y, targetX, targetY, vx: (Math.random() - 0.5) * 2, vy: (Math.random() - 0.5) * 2, size, opacity: 0.6 + Math.random() * 0.4, color, life: 0, maxLife, stage: 'idle', }; }, [colors] ); useEffect(() => { const canvas = canvasRef.current; if (!canvas) {return;} const ctx = canvas.getContext('2d'); if (!ctx) {return;} canvas.width = width; canvas.height = height; const sealPositions = createSealShape(width, height); particlesRef.current = sealPositions.map((pos) => createParticle(pos.x, pos.y, pos.x, pos.y) ); if (animationStages) { stageTimerRef.current = setTimeout(() => { setCurrentStage('dispersing'); onStageChange?.('dispersing'); particlesRef.current.forEach(p => { p.vx = (Math.random() - 0.5) * 4; p.vy = (Math.random() - 0.5) * 4; p.stage = 'dispersing'; }); setTimeout(() => { setCurrentStage('reforming'); onStageChange?.('reforming'); particlesRef.current.forEach(p => { p.stage = 'reforming'; }); setTimeout(() => { setCurrentStage('idle'); onStageChange?.('idle'); }, 3000); }, 2000); }, 3000); } const animate = () => { ctx.clearRect(0, 0, width, height); particlesRef.current.forEach((particle) => { if (particle.stage === 'reforming') { const dx = particle.targetX - particle.x; const dy = particle.targetY - particle.y; particle.vx += dx * 0.02; particle.vy += dy * 0.02; particle.vx *= 0.95; particle.vy *= 0.95; } particle.x += particle.vx; particle.y += particle.vy; particle.life++; ctx.beginPath(); ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2); ctx.fillStyle = particle.color; ctx.globalAlpha = particle.opacity; ctx.fill(); ctx.globalAlpha = 1; }); animationRef.current = requestAnimationFrame(animate); }; animate(); return () => { if (animationRef.current) { cancelAnimationFrame(animationRef.current); } if (stageTimerRef.current) { clearTimeout(stageTimerRef.current); } }; }, [width, height, createSealShape, createParticle, animationStages, onStageChange]); return ( ); }