| import React, { useEffect, useRef } from 'react'; |
|
|
| interface AudioVisualizerProps { |
| isListening: boolean; |
| color: string; |
| } |
|
|
| const AudioVisualizer: React.FC<AudioVisualizerProps> = ({ isListening, color }) => { |
| const canvasRef = useRef<HTMLCanvasElement>(null); |
| const requestRef = useRef<number>(); |
|
|
| useEffect(() => { |
| if (!isListening || !canvasRef.current) return; |
|
|
| const canvas = canvasRef.current; |
| const ctx = canvas.getContext('2d'); |
| if (!ctx) return; |
|
|
| let frame = 0; |
|
|
| const animate = () => { |
| frame++; |
| const width = canvas.width; |
| const height = canvas.height; |
| const centerY = height / 2; |
|
|
| ctx.clearRect(0, 0, width, height); |
|
|
| |
| ctx.shadowBlur = 15; |
| ctx.shadowColor = color.replace('text-', '').replace('bg-', ''); |
| ctx.strokeStyle = '#ffffff'; |
| ctx.lineWidth = 2; |
|
|
| ctx.beginPath(); |
| ctx.moveTo(0, centerY); |
|
|
| for (let i = 0; i < width; i++) { |
| |
| const amplitude = isListening ? 20 : 2; |
| const frequency = 0.05; |
| const y = centerY + Math.sin(i * frequency + frame * 0.1) * amplitude * Math.sin(i * 0.03); |
| ctx.lineTo(i, y); |
| } |
|
|
| ctx.stroke(); |
| requestRef.current = requestAnimationFrame(animate); |
| }; |
|
|
| animate(); |
|
|
| return () => { |
| if (requestRef.current) cancelAnimationFrame(requestRef.current); |
| }; |
| }, [isListening, color]); |
|
|
| return ( |
| <canvas |
| ref={canvasRef} |
| width={300} |
| height={60} |
| className="w-full h-full opacity-80" |
| /> |
| ); |
| }; |
|
|
| export default AudioVisualizer; |
|
|