- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경 - DB 연결 하드코딩 → .env 기반으로 변경 - MySQL strict mode DATE 오류 수정
82 lines
2.2 KiB
TypeScript
82 lines
2.2 KiB
TypeScript
import React, { useEffect, useRef } from 'react';
|
|
|
|
interface VisualizerProps {
|
|
analyser: AnalyserNode | null;
|
|
active: boolean;
|
|
}
|
|
|
|
const Visualizer: React.FC<VisualizerProps> = ({ analyser, active }) => {
|
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (!canvasRef.current) return;
|
|
const canvas = canvasRef.current;
|
|
const ctx = canvas.getContext('2d');
|
|
if (!ctx) return;
|
|
|
|
let animationId: number;
|
|
const bufferLength = analyser ? analyser.frequencyBinCount : 0;
|
|
const dataArray = new Uint8Array(bufferLength);
|
|
|
|
const draw = () => {
|
|
animationId = requestAnimationFrame(draw);
|
|
|
|
const width = canvas.width;
|
|
const height = canvas.height;
|
|
ctx.clearRect(0, 0, width, height);
|
|
|
|
if (!active || !analyser) {
|
|
// Idle state: gentle pulse
|
|
const time = Date.now() / 1000;
|
|
ctx.beginPath();
|
|
ctx.arc(width / 2, height / 2, 20 + Math.sin(time * 2) * 2, 0, Math.PI * 2);
|
|
ctx.fillStyle = 'rgba(99, 102, 241, 0.5)';
|
|
ctx.fill();
|
|
return;
|
|
}
|
|
|
|
analyser.getByteFrequencyData(dataArray);
|
|
|
|
const barWidth = (width / bufferLength) * 2.5;
|
|
let barHeight;
|
|
let x = 0;
|
|
|
|
// Draw mirrored spectrum from center
|
|
const centerX = width / 2;
|
|
|
|
for (let i = 0; i < bufferLength; i++) {
|
|
barHeight = dataArray[i] / 2;
|
|
|
|
// Gradient color
|
|
const gradient = ctx.createLinearGradient(0, height / 2 - barHeight, 0, height / 2 + barHeight);
|
|
gradient.addColorStop(0, '#818cf8'); // indigo-400
|
|
gradient.addColorStop(1, '#c084fc'); // purple-400
|
|
|
|
ctx.fillStyle = gradient;
|
|
|
|
// Right side
|
|
ctx.fillRect(centerX + x, height / 2 - barHeight / 2, barWidth, barHeight);
|
|
// Left side
|
|
ctx.fillRect(centerX - x - barWidth, height / 2 - barHeight / 2, barWidth, barHeight);
|
|
|
|
x += barWidth + 1;
|
|
}
|
|
};
|
|
|
|
draw();
|
|
|
|
return () => cancelAnimationFrame(animationId);
|
|
}, [analyser, active]);
|
|
|
|
return (
|
|
<canvas
|
|
ref={canvasRef}
|
|
width={300}
|
|
height={100}
|
|
className="w-full h-full"
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default Visualizer;
|