// Configuração global do Chart.js Chart.defaults.font.family = "'Inter', sans-serif"; Chart.defaults.color = '#6b7280'; // Dados para os gráficos document.addEventListener('DOMContentLoaded', function() { // Gráfico de Receitas const receitasCtx = document.getElementById('receitasChart').getContext('2d'); const receitasChart = new Chart(receitasCtx, { type: 'doughnut', data: { labels: ['Tráfego', 'Web Design', 'Serviços', 'Financeiras', 'Outras'], datasets: [{ data: [37828, 9165, 2627, 0, 1168], backgroundColor: [ '#10B981', '#3B82F6', '#8B5CF6', '#F59E0B', '#EC4899' ], borderWidth: 0, hoverOffset: 15 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'right', labels: { padding: 20, usePointStyle: true, pointStyle: 'circle' } }, tooltip: { callbacks: { label: function(context) { const label = context.label || ''; const value = context.raw || 0; const total = context.dataset.data.reduce((a, b) => a + b, 0); const percentage = Math.round((value / total) * 100); return `${label}: R$ ${value.toLocaleString('pt-BR')} (${percentage}%)`; } } } }, cutout: '65%' } }); // Gráfico de Despesas const despesasCtx = document.getElementById('despesasChart').getContext('2d'); const despesasChart = new Chart(despesasCtx, { type: 'bar', data: { labels: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov'], datasets: [ { label: 'Custos Fixos', data: [10559, 7062, 11989, 10367, 9224, 11385, 11627, 11298, 15675, 14320, 18201], backgroundColor: '#EF4444', borderRadius: 6, borderSkipped: false, }, { label: 'Custos Variáveis', data: [5444, 8391, 9961, 9016, 9808, 13338, 10839, 11495, 13648, 13959, 11391], backgroundColor: '#F59E0B', borderRadius: 6, borderSkipped: false, }, { label: 'Salários', data: [7811, 2305, 7513, 6909, 5909, 6909, 7465, 7669, 10146, 9690, 11294], backgroundColor: '#3B82F6', borderRadius: 6, borderSkipped: false, }, { label: 'PLR', data: [19396, 19396, 19396, 19396, 19396, 21396, 21396, 21396, 20964, 22964, 22964], backgroundColor: '#8B5CF6', borderRadius: 6, borderSkipped: false, } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top', }, tooltip: { mode: 'index', intersect: false } }, scales: { x: { stacked: true, grid: { display: false } }, y: { stacked: true, grid: { color: 'rgba(0, 0, 0, 0.05)' }, ticks: { callback: function(value) { return 'R$ ' + value.toLocaleString('pt-BR'); } } } } } }); // Gráfico de Fluxo de Caixa const fluxoCtx = document.getElementById('fluxoChart').getContext('2d'); const fluxoChart = new Chart(fluxoCtx, { type: 'line', data: { labels: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], datasets: [ { label: 'Receitas', data: [32757, 36279, 37684, 34902, 34148, 42104, 33888, 44910, 46361, 49334, 51009, 47416], borderColor: '#10B981', backgroundColor: 'rgba(16, 185, 129, 0.1)', fill: true, tension: 0.4, pointRadius: 4, pointBackgroundColor: '#fff', pointBorderWidth: 2 }, { label: 'Despesas', data: [38408, 38022, 41353, 38789, 38435, 46177, 43866, 44193, 50352, 51320, 52617, 50153], borderColor: '#EF4444', backgroundColor: 'rgba(239, 68, 68, 0.1)', fill: true, tension: 0.4, pointRadius: 4, pointBackgroundColor: '#fff', pointBorderWidth: 2 }, { label: 'Saldo Final', data: [52114, 50371, 46703, 42816, 42529, 44457, 36478, 25195, 27204, 27102, 27611, 14874], borderColor: '#3B82F6', backgroundColor: 'rgba(59, 130, 246, 0.1)', borderDash: [5, 5], fill: true, tension: 0.4, pointRadius: 4, pointBackgroundColor: '#fff', pointBorderWidth: 2 } ] }, options: { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false }, plugins: { legend: { position: 'top', }, tooltip: { callbacks: { label: function(context) { return context.dataset.label + ': R$ ' + context.raw.toLocaleString('pt-BR'); } } } }, scales: { y: { grid: { color: 'rgba(0, 0, 0, 0.05)' }, ticks: { callback: function(value) { return 'R$ ' + value.toLocaleString('pt-BR'); } } } } } }); // Animação de entrada const animateOnScroll = () => { const elements = document.querySelectorAll('.animate-fade-in'); elements.forEach(element => { const elementPosition = element.getBoundingClientRect().top; const screenPosition = window.innerHeight / 1.3; if (elementPosition < screenPosition) { element.classList.add('opacity-100'); element.classList.remove('opacity-0'); } }); }; window.addEventListener('scroll', animateOnScroll); animateOnScroll(); });