Net Profit Margin Dashboard

Net Profit Margin Dashboard

Analyze profitability trends over time.

Overall Performance Summary

Revenue vs. Net Profit Margin

Financial Breakdown by Period

Period Revenue Net Profit Net Profit Margin

Enter Financial Data by Period

${formatPercent(averageMargin)}

Latest Margin

${formatPercent(latestMargin)}

`; }; const renderDataTable = () => { dataTableBody.innerHTML = ''; state.timePeriods.forEach(p => { const { netProfit, netProfitMargin } = calculateMetrics(p); const row = ` ${p.period} ${formatCurrency(p.revenue)} ${formatCurrency(netProfit)} ${formatPercent(netProfitMargin)} `; dataTableBody.innerHTML += row; }); }; const renderChart = () => { if (profitMarginChart) { profitMarginChart.destroy(); } const labels = state.timePeriods.map(p => p.period); const revenueData = state.timePeriods.map(p => p.revenue); const marginData = state.timePeriods.map(p => calculateMetrics(p).netProfitMargin); profitMarginChart = new Chart(chartCanvas.getContext('2d'), { type: 'line', data: { labels: labels, datasets: [ { type: 'bar', label: 'Revenue', data: revenueData, backgroundColor: 'rgba(59, 130, 246, 0.5)', // Blue-500 borderColor: 'rgba(59, 130, 246, 1)', yAxisID: 'yRevenue', }, { type: 'line', label: 'Net Profit Margin (%)', data: marginData, backgroundColor: 'rgba(13, 148, 136, 1)', // Teal-600 borderColor: 'rgba(13, 148, 136, 1)', tension: 0.2, fill: false, yAxisID: 'yMargin', } ] }, options: { responsive: true, maintainAspectRatio: false, scales: { yRevenue: { type: 'linear', display: true, position: 'left', title: { display: true, text: 'Revenue ($)' }, ticks: { callback: (value) => formatCurrency(value) } }, yMargin: { type: 'linear', display: true, position: 'right', title: { display: true, text: 'Net Profit Margin (%)' }, grid: { drawOnChartArea: false }, ticks: { callback: (value) => `${value}%` } } } } }); }; const renderConfigRows = () => { configRowsContainer.innerHTML = ''; state.timePeriods.forEach(p => { const row = `
`; configRowsContainer.innerHTML += row; }); addConfigEventListeners(); }; // --- EVENT HANDLERS --- const handleConfigChange = (e) => { const id = parseInt(e.target.dataset.id); const field = e.target.dataset.field; const value = field === 'period' ? e.target.value : parseFloat(e.target.value) || 0; const period = state.timePeriods.find(p => p.id === id); if (period) { period[field] = value; } renderAll(); }; const handleAddPeriod = () => { const newId = state.timePeriods.length > 0 ? Math.max(...state.timePeriods.map(p => p.id)) + 1 : 1; state.timePeriods.push({ id: newId, period: "New Period", revenue: 0, cogs: 0, opEx: 0, interestAndTax: 0 }); renderAll(); }; const handleRemovePeriod = (e) => { const id = parseInt(e.target.dataset.id); state.timePeriods = state.timePeriods.filter(p => p.id !== id); renderAll(); }; const addConfigEventListeners = () => { document.querySelectorAll('.config-input').forEach(input => input.addEventListener('change', handleConfigChange)); document.querySelectorAll('.remove-period-btn').forEach(button => button.addEventListener('click', handleRemovePeriod)); }; const handleDownloadPdf = () => { const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content'); document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'hidden'); Chart.defaults.animation = false; html2canvas(pdfContent, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => { document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'visible'); Chart.defaults.animation = true; const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const imgWidth = pdfWidth - 20; const imgHeight = canvas.height * imgWidth / canvas.width; pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight); pdf.save('Net-Profit-Margin-Dashboard.pdf'); }); }; // --- TABBING LOGIC --- let currentTabIndex = 0; const updateTabButtons = () => { prevTabBtn.disabled = currentTabIndex === 0; nextTabBtn.disabled = currentTabIndex === tabContents.length - 1; }; const switchTab = (index) => { tabButtons.forEach(btn => btn.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); tabButtons[index].classList.add('active'); tabContents[index].classList.add('active'); currentTabIndex = index; updateTabButtons(); }; tabButtons.forEach((button, index) => button.addEventListener('click', () => switchTab(index))); prevTabBtn.addEventListener('click', () => { if (currentTabIndex > 0) switchTab(currentTabIndex - 1); }); nextTabBtn.addEventListener('click', () => { if (currentTabIndex < tabContents.length - 1) switchTab(currentTabIndex + 1); }); // --- INITIALIZATION --- if (kpiCardsContainer && addPeriodBtn && downloadPdfBtn) { addPeriodBtn.addEventListener('click', handleAddPeriod); downloadPdfBtn.addEventListener('click', handleDownloadPdf); renderAll(); updateTabButtons(); } else { console.error("Essential dashboard elements could not be found."); } });
Scroll to Top