/** * Metrics comparison chart - shows L and W for each queue. */ import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend, } from 'chart.js'; import { Bar } from 'react-chartjs-2'; import type { SimulationResults, NetworkAnalytics } from '../../types/simulation'; ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend); interface MetricsComparisonChartProps { simulationResults?: SimulationResults | null; analyticalResults?: NetworkAnalytics | null; metric: 'L' | 'W'; } export default function MetricsComparisonChart({ simulationResults, analyticalResults, metric, }: MetricsComparisonChartProps) { if (!simulationResults && !analyticalResults) { return null; } const labels: string[] = ['Coordinateur']; const simulationData: number[] = []; const analyticalData: number[] = []; // Coordinator data if (simulationResults && metric === 'W') { simulationData.push(simulationResults.coordinator_stats.average_system_time); } if (analyticalResults) { if (metric === 'L') { analyticalData.push(analyticalResults.coordinator.average_customers ?? 0); } else { analyticalData.push(analyticalResults.coordinator.average_time ?? 0); } } // Server data if (simulationResults) { Object.entries(simulationResults.server_stats).forEach(([serverId, stats]) => { const serverNum = serverId.replace('server_', ''); labels.push(`Serveur ${serverNum}`); if (metric === 'W') { simulationData.push(stats.average_system_time); } }); } if (analyticalResults) { Object.entries(analyticalResults.servers).forEach(([_, analytics]) => { if (simulationData.length <= analyticalData.length) { const serverNum = labels.length; labels.push(`Serveur ${serverNum}`); } if (metric === 'L') { analyticalData.push(analytics.average_customers ?? 0); } else { analyticalData.push(analytics.average_time ?? 0); } }); } const data = { labels, datasets: [ ...(simulationResults && metric === 'W' ? [ { label: 'Simulation', data: simulationData, backgroundColor: 'rgba(16, 185, 129, 0.7)', borderColor: 'rgba(16, 185, 129, 1)', borderWidth: 1, }, ] : []), ...(analyticalResults ? [ { label: 'Analytique (Jackson)', data: analyticalData, backgroundColor: 'rgba(245, 158, 11, 0.7)', borderColor: 'rgba(245, 158, 11, 1)', borderWidth: 1, }, ] : []), ], }; const metricLabel = metric === 'L' ? 'Nombre moyen de clients (L)' : 'Temps moyen dans le système (W)'; const yAxisLabel = metric === 'L' ? 'Clients' : 'Unités de temps'; const options = { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' as const, }, title: { display: true, text: metricLabel, font: { size: 14, weight: 'bold' as const, }, }, tooltip: { callbacks: { label: function (context: any) { let label = context.dataset.label || ''; if (label) { label += ': '; } label += context.parsed.y.toFixed(4); return label; }, }, }, }, scales: { y: { beginAtZero: true, title: { display: true, text: yAxisLabel, }, }, x: { title: { display: true, text: 'Files d\'attente', }, }, }, }; return (