// resources/js/charts.js export class ChartManager { constructor() { this.charts = {}; } init(data) { console.log('ChartManager initialized with data:', data); this.destroyAll(); this.createBarChart(data); this.createPieChart(data); this.createScoreChart(data); this.createMetricsChart(data); } destroyAll() { Object.values(this.charts).forEach(chart => { if (chart) chart.destroy(); }); this.charts = {}; } createBarChart(data) { const canvas = document.getElementById('barChart'); if (!canvas) { console.warn('Canvas barChart tidak ditemukan'); return; } const ctx = canvas.getContext('2d'); const total = data.positif + data.negatif; const positifPercent = total > 0 ? ((data.positif / total) * 100).toFixed(1) : 0; const negatifPercent = total > 0 ? ((data.negatif / total) * 100).toFixed(1) : 0; this.charts.barChart = new Chart(ctx, { type: 'bar', data: { labels: ['Positif', 'Negatif'], datasets: [{ label: 'Jumlah Sentimen', data: [data.positif, data.negatif], backgroundColor: ['#10b981', '#ef4444'], borderColor: ['#059669', '#dc2626'], borderWidth: 2, borderRadius: 8, barPercentage: 0.7 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { callbacks: { label: (context) => { const value = context.raw; const percentage = context.dataIndex === 0 ? positifPercent : negatifPercent; return `Jumlah: ${value} (${percentage}%)`; } } } }, scales: { y: { beginAtZero: true, grid: { color: 'rgba(255, 255, 255, 0.1)' }, ticks: { color: '#ffffff' } }, x: { grid: { display: false }, ticks: { color: '#ffffff' } } } } }); console.log('Bar chart created'); } createPieChart(data) { const canvas = document.getElementById('pieChart'); if (!canvas) { console.warn('Canvas pieChart tidak ditemukan'); return; } const ctx = canvas.getContext('2d'); const total = data.positif + data.negatif; const positifPercent = total > 0 ? ((data.positif / total) * 100).toFixed(1) : 0; const negatifPercent = total > 0 ? ((data.negatif / total) * 100).toFixed(1) : 0; this.charts.pieChart = new Chart(ctx, { type: 'doughnut', data: { labels: [`Positif (${positifPercent}%)`, `Negatif (${negatifPercent}%)`], datasets: [{ data: [data.positif, data.negatif], backgroundColor: ['#10b981', '#ef4444'], borderColor: 'rgba(255, 255, 255, 0.2)', borderWidth: 2, hoverOffset: 8 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom', labels: { color: '#ffffff', font: { size: 12 }, padding: 20 } } }, cutout: '60%' } }); console.log('Pie chart created'); } createScoreChart(data) { const canvas = document.getElementById('scoreChart'); if (!canvas) { console.warn('Canvas scoreChart tidak ditemukan'); return; } const ctx = canvas.getContext('2d'); this.charts.scoreChart = new Chart(ctx, { type: 'line', data: { labels: ['0-20', '21-40', '41-60', '61-80', '81-100'], datasets: [{ label: 'Distribusi Score', data: data.scoreDistribution, borderColor: '#3b82f6', backgroundColor: 'rgba(59, 130, 246, 0.1)', borderWidth: 3, pointBackgroundColor: '#3b82f6', pointBorderColor: '#ffffff', pointBorderWidth: 2, pointRadius: 6, pointHoverRadius: 8, tension: 0.3, fill: true }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { callbacks: { label: (context) => `Jumlah: ${context.raw} data` } } }, scales: { y: { beginAtZero: true, grid: { color: 'rgba(255, 255, 255, 0.1)' }, ticks: { color: '#ffffff' } }, x: { grid: { display: false }, ticks: { color: '#ffffff' } } } } }); console.log('Score chart created'); } createMetricsChart(data) { const canvas = document.getElementById('groupedMetricsChart'); if (!canvas) { console.warn('Canvas groupedMetricsChart tidak ditemukan'); return; } const ctx = canvas.getContext('2d'); this.charts.metricsChart = new Chart(ctx, { type: 'bar', data: { labels: ['Precision', 'Recall', 'F1-Score'], datasets: [ { label: 'Negatif', data: data.metrics.negatif, backgroundColor: '#ef4444', borderRadius: 6 }, { label: 'Positif', data: data.metrics.positif, backgroundColor: '#10b981', borderRadius: 6 } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#ffffff' } }, tooltip: { callbacks: { label: (context) => `${context.dataset.label}: ${(context.raw * 100).toFixed(1)}%` } } }, scales: { y: { beginAtZero: true, max: 1, grid: { color: 'rgba(255, 255, 255, 0.1)' }, ticks: { color: '#ffffff', callback: (value) => (value * 100) + '%' } }, x: { grid: { display: false }, ticks: { color: '#ffffff' } } } } }); console.log('Metrics chart created'); } }