219 lines
7.4 KiB
JavaScript
219 lines
7.4 KiB
JavaScript
// resources/js/charts.js
|
|
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) 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' }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
createPieChart(data) {
|
|
const canvas = document.getElementById('pieChart');
|
|
if (!canvas) 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%'
|
|
}
|
|
});
|
|
}
|
|
|
|
createScoreChart(data) {
|
|
const canvas = document.getElementById('scoreChart');
|
|
if (!canvas) 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' }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
createMetricsChart(data) {
|
|
const canvas = document.getElementById('groupedMetricsChart');
|
|
if (!canvas) 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' }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Export untuk digunakan di view
|
|
window.ChartManager = ChartManager; |