// Chart Utilities for Dashboard import { CountUp } from 'countup.js'; /** * Initialize animated counter for metric cards */ export function initCounter(element, endValue, options = {}) { const defaultOptions = { duration: 2, useEasing: true, useGrouping: true, separator: ',', decimal: '.', prefix: '', suffix: '' }; const countUp = new CountUp(element, endValue, { ...defaultOptions, ...options }); if (!countUp.error) { countUp.start(); } else { console.error('CountUp error:', countUp.error); element.textContent = endValue; } return countUp; } /** * Format currency values */ export function formatCurrency(value, currency = '฿') { return `${currency}${value.toLocaleString()}`; } /** * Format percentage values */ export function formatPercentage(value, decimals = 2) { return `${value.toFixed(decimals)}%`; } /** * Get trend indicator HTML */ export function getTrendIndicator(percentage, showValue = true) { const isPositive = percentage >= 0; const icon = isPositive ? '↗' : '↘'; const colorClass = isPositive ? 'text-emerald-400' : 'text-red-400'; const bgClass = isPositive ? 'bg-emerald-400/10' : 'bg-red-400/10'; const valueText = showValue ? `${Math.abs(percentage).toFixed(1)}%` : ''; return `
${icon} ${valueText ? `${valueText}` : ''}
`; } /** * Update chart data with smooth animation */ export function updateChartData(chart, newData, newLabels = null) { if (newLabels) { chart.data.labels = newLabels; } // Update datasets newData.forEach((dataset, index) => { if (chart.data.datasets[index]) { chart.data.datasets[index].data = dataset.data; if (dataset.label) { chart.data.datasets[index].label = dataset.label; } } }); chart.update('active'); } /** * Resize chart to fit container */ export function resizeChart(chart) { if (chart && chart.canvas) { chart.resize(); } } /** * Destroy chart safely */ export function destroyChart(chart) { if (chart && typeof chart.destroy === 'function') { chart.destroy(); } } /** * Create loading skeleton for charts */ export function createChartSkeleton(container) { container.innerHTML = `
`; } /** * Show error state for charts */ export function showChartError(container, message = 'Failed to load chart data') { container.innerHTML = `

${message}

`; } /** * Debounce function for performance */ export function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } /** * Throttle function for performance */ export function throttle(func, limit) { let inThrottle; return function() { const args = arguments; const context = this; if (!inThrottle) { func.apply(context, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } /** * Format time labels based on period */ export function formatTimeLabel(value, period) { switch (period) { case 'daily': return `${value}:00`; case 'weekly': return value; // Day name case 'monthly': return `Day ${value}`; default: return value; } } /** * Generate random data for demo purposes */ export function generateDemoData(length, min = 0, max = 1000) { return Array.from({ length }, () => Math.floor(Math.random() * (max - min + 1)) + min); } /** * Calculate percentage change */ export function calculatePercentageChange(current, previous) { if (previous === 0) return current > 0 ? 100 : 0; return ((current - previous) / previous) * 100; } /** * Get responsive chart height based on screen size */ export function getResponsiveHeight() { const width = window.innerWidth; if (width < 640) return 250; // Mobile if (width < 1024) return 300; // Tablet return 350; // Desktop } /** * Initialize chart container with glassmorphic styling */ export function initChartContainer(container) { container.classList.add( 'bg-white/5', 'backdrop-blur-2xl', 'border', 'border-white/10', 'rounded-2xl', 'p-6', 'shadow-2xl' ); // Add glow effect container.style.boxShadow = ` 0 25px 50px -12px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05), inset 0 1px 0 rgba(255, 255, 255, 0.1) `; } // Make functions globally available for inline scripts window.createChartSkeleton = createChartSkeleton; window.showChartError = showChartError; window.initChartContainer = initChartContainer; window.formatCurrency = formatCurrency; window.formatPercentage = formatPercentage; window.getTrendIndicator = getTrendIndicator; window.calculatePercentageChange = calculatePercentageChange; window.updateChartData = updateChartData; window.resizeChart = resizeChart; window.destroyChart = destroyChart;