PPM (Project Portfolio Management) Dashboard

PPM Dashboard

Total Projects

0

Total Budget

$0

Overall Budget Spent

0%

Projects At Risk / Off Track

0

Project Status

Budget vs. Spent by Project

Projects by Phase

Project Completion Progress

Status: ${projectData.status}

Phase: ${projectData.phase}

Priority: ${projectData.priority}

Budget: $${projectData.budget.toLocaleString()} | Spent: $${projectData.spent.toLocaleString()} (${budgetStatus}%)

Completion:
${projectData.completionPercentage}%
`; projectDetailsContainer.classList.remove('hidden'); }; // --- IV. EVENT LISTENERS --- tabButtons.forEach((button, index) => button.addEventListener('click', () => showTab(index))); prevBtn.addEventListener('click', () => showTab(currentTabIndex - 1)); nextBtn.addEventListener('click', () => showTab(currentTabIndex + 1)); updateDataBtn.addEventListener('click', () => { try { const newData = JSON.parse(dataInput.value); if (Array.isArray(newData)) { currentProjectData = newData; jsonErrorMsg.classList.add('hidden'); updateDashboard(); alert('Dashboard updated successfully!'); showTab(0); } else { throw new Error("Data is not an array."); } } catch (error) { jsonErrorMsg.classList.remove('hidden'); } }); projectSelect.addEventListener('change', showProjectDetails); // --- REVISED PDF DOWNLOAD FUNCTIONALITY --- downloadPdfBtn.addEventListener('click', async () => { const dashboardArea = getElement('dashboard-export-area'); if (!dashboardArea) { console.error('Dashboard export area not found!'); return; } const originalButtonText = downloadPdfBtn.textContent; downloadPdfBtn.textContent = 'Generating PDF...'; downloadPdfBtn.disabled = true; try { // Use html2canvas to capture the dashboard area const canvas = await html2canvas(dashboardArea, { scale: 2, // Higher scale for better resolution useCORS: true, logging: false, width: dashboardArea.scrollWidth, // Capture full width height: dashboardArea.scrollHeight, // Capture full height windowWidth: dashboardArea.scrollWidth, windowHeight: dashboardArea.scrollHeight }); const imgData = canvas.toDataURL('image/png'); const { jsPDF } = window.jspdf; // A4 paper size in mm: 297mm (L) x 210mm (H) const pdfWidth = 297; const pdfHeight = 210; const margin = 15; // 15mm margin on all sides const imgWidth = canvas.width; const imgHeight = canvas.height; const aspectRatio = imgWidth / imgHeight; // Calculate the scaled image dimensions to fit within the A4 page with margins let scaledWidth = pdfWidth - (margin * 2); let scaledHeight = scaledWidth / aspectRatio; // If the scaled height is too big for the page, recalculate based on height if (scaledHeight > pdfHeight - (margin * 2)) { scaledHeight = pdfHeight - (margin * 2); scaledWidth = scaledHeight * aspectRatio; } // Center the image on the page const xOffset = (pdfWidth - scaledWidth) / 2; const yOffset = (pdfHeight - scaledHeight) / 2; // Create a new PDF in A4 landscape format const pdf = new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'a4' }); // Add the captured image to the PDF pdf.addImage(imgData, 'PNG', xOffset, yOffset, scaledWidth, scaledHeight); pdf.save('PPM_Dashboard.pdf'); } catch (error) { console.error("PDF generation failed:", error); alert("Sorry, there was an error generating the PDF. Please try again."); } finally { // Restore the button to its original state downloadPdfBtn.textContent = originalButtonText; downloadPdfBtn.disabled = false; } }); // --- V. INITIALIZATION CALLS --- dataInput.value = JSON.stringify(initialProjectData, null, 4); updateDashboard(); showTab(0); });
Scroll to Top