'use client'; import { useEffect, useRef } from 'react'; interface Metric { health: number; // 0.0 to 1.0 throughput: number; // requests per second errorRate: number; // 0.0 to 1.0 } export default function FractalVisualizer({ metrics }: { metrics: Metric }) { const canvasRef = useRef(null); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; let animationFrameId: number; let angleOffset = 0; const drawTree = ( x: number, y: number, length: number, angle: number, depth: number, branchRatio: number ) => { if (depth === 0) return; const endX = x + length * Math.cos(angle); const endY = y + length * Math.sin(angle); ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(endX, endY); // Node health dictates the color opacity const opacity = 0.2 + (metrics.health * 0.8) * (depth / 10); ctx.strokeStyle = `rgba(48, 54, 61, ${opacity})`; // Error rate dictates line thickness and jaggedness ctx.lineWidth = depth * (1 + metrics.errorRate * 5) * 0.3; ctx.stroke(); // Throughput dictates the dynamic sway const sway = Math.sin(angleOffset + depth) * (metrics.throughput / 1000) * 0.1; const newLength = length * branchRatio; drawTree(endX, endY, newLength, angle - Math.PI / 4 + sway, depth - 1, branchRatio); drawTree(endX, endY, newLength, angle + Math.PI / 4 + sway, depth - 1, branchRatio); }; const render = () => { const { width, height } = canvas.getBoundingClientRect(); if (canvas.width !== width || canvas.height !== height) { // Adjust for retina displays const dpr = window.devicePixelRatio || 1; canvas.width = width * dpr; canvas.height = height * dpr; ctx.scale(dpr, dpr); } else { ctx.clearRect(0, 0, width, height); } // Golden ratio branch reduction const GOLDEN_RATIO_INV = 1 / 1.61803398875; drawTree( width / 2, height, height * 0.3, -Math.PI / 2, 10, GOLDEN_RATIO_INV ); angleOffset += 0.02 + (metrics.throughput / 5000); animationFrameId = requestAnimationFrame(render); }; render(); return () => { cancelAnimationFrame(animationFrameId); }; }, [metrics]); return (
); }