Files
Retribusi/public/dashboard/js/charts.js

194 lines
4.9 KiB
JavaScript

// public/dashboard/js/charts.js
// Chart.js helpers: create & update charts without recreating canvases.
let dailyLineChart = null;
let categoryChart = null;
// Export chart instances untuk akses dari dashboard.js
export function getDailyChart() {
return dailyLineChart;
}
export function getCategoryChart() {
return categoryChart;
}
export function initDailyChart(ctx) {
if (dailyLineChart) return dailyLineChart;
dailyLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [
{
label: 'Jumlah',
data: [],
borderColor: '#111827',
backgroundColor: 'rgba(17, 24, 39, 0.06)',
borderWidth: 2,
tension: 0.35,
fill: true,
pointRadius: 2.5,
pointBackgroundColor: '#111827'
},
{
label: 'Pendapatan',
data: [],
borderColor: '#6b7280',
backgroundColor: 'rgba(156, 163, 175, 0.08)',
borderWidth: 2,
tension: 0.35,
fill: true,
pointRadius: 2.5,
pointBackgroundColor: '#6b7280',
yAxisID: 'y1'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false
},
scales: {
y: {
beginAtZero: true,
grid: { color: '#e5e7eb' },
ticks: { font: { size: 11 } }
},
y1: {
beginAtZero: true,
position: 'right',
grid: { drawOnChartArea: false },
ticks: {
font: { size: 11 },
callback: value => 'Rp ' + new Intl.NumberFormat('id-ID').format(value)
}
},
x: {
grid: { display: false },
ticks: { font: { size: 11 } }
}
},
plugins: {
legend: {
position: 'bottom',
labels: {
boxWidth: 14,
boxHeight: 4
}
}
}
}
});
return dailyLineChart;
}
export function updateDailyChart({ labels, counts, amounts }) {
if (!dailyLineChart) {
console.warn('[Charts] Daily chart belum di-init, skip update');
// Try to init if canvas exists
const canvas = document.getElementById('daily-chart');
if (canvas) {
console.log('[Charts] Attempting to init daily chart from update function...');
initDailyChart(canvas.getContext('2d'));
} else {
console.error('[Charts] Daily chart canvas not found!');
return;
}
}
if (!dailyLineChart) {
console.error('[Charts] Failed to init daily chart');
return;
}
dailyLineChart.data.labels = labels || [];
dailyLineChart.data.datasets[0].data = counts || [];
dailyLineChart.data.datasets[1].data = amounts || [];
dailyLineChart.update();
console.log('[Charts] Daily chart updated:', { labelsCount: labels?.length, countsCount: counts?.length, amountsCount: amounts?.length });
}
export function initCategoryChart(ctx) {
if (categoryChart) return categoryChart;
categoryChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [],
datasets: [
{
label: 'Per Kategori',
data: [],
backgroundColor: ['#111827', '#4b5563', '#9ca3af'],
borderWidth: 0
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
cutout: '60%',
plugins: {
legend: {
position: 'bottom',
labels: {
boxWidth: 14,
boxHeight: 6
}
}
}
}
});
return categoryChart;
}
export function updateCategoryChart({ labels, values }) {
if (!categoryChart) {
console.warn('[Charts] Category chart belum di-init, skip update');
// Try to init if canvas exists
const canvas = document.getElementById('category-chart');
if (canvas) {
console.log('[Charts] Attempting to init category chart from update function...');
initCategoryChart(canvas.getContext('2d'));
} else {
console.error('[Charts] Category chart canvas not found!');
return;
}
}
if (!categoryChart) {
console.error('[Charts] Failed to init category chart');
return;
}
// Pastikan labels dan values tidak kosong
const finalLabels = labels && labels.length > 0 ? labels : ['Orang', 'Motor', 'Mobil'];
const finalValues = values && values.length > 0 ? values : [0, 0, 0];
// Pastikan length sama
const minLength = Math.min(finalLabels.length, finalValues.length);
const safeLabels = finalLabels.slice(0, minLength);
const safeValues = finalValues.slice(0, minLength);
categoryChart.data.labels = safeLabels;
categoryChart.data.datasets[0].data = safeValues;
// Update chart dengan mode 'none' untuk animasi halus
categoryChart.update('none');
console.log('[Charts] Category chart updated:', {
labels: safeLabels,
values: safeValues,
total: safeValues.reduce((a, b) => a + b, 0)
});
}