Project Stakeholder Analysis Generator

Project Stakeholder Analysis Generator

Sample Project Analysis

Stakeholder Matrix (Influence vs. Interest)

Influence → ← Interest → High Low Low High

Stakeholder Details

Name Role/Title Interest Influence Engagement Strategy

Project Information

Add New Stakeholder

Current Stakeholders

No stakeholders added yet.

"; } appState.stakeholders.forEach(sh => { const item = document.createElement("div"); item.className = "psa-stakeholder-item"; item.innerHTML = ` ${sh.name} (${sh.role}) `; stakeholdersList.appendChild(item); }); } function renderDashboardTab() { projectTitleDisplay.textContent = appState.projectName; // Clear previous dots & table rows matrixContainer.querySelectorAll('.psa-stakeholder-dot').forEach(dot => dot.remove()); tableBody.innerHTML = ""; if (appState.stakeholders.length === 0) { tableBody.innerHTML = "No stakeholders configured."; return; } const levelToValue = { low: 1, medium: 2, high: 3 }; const valueToPercent = { 1: 25, 2: 50, 3: 75 }; // Position within quadrant appState.stakeholders.forEach(sh => { // 1. Render Matrix Dot const influenceVal = levelToValue[sh.influence] || 1; const interestVal = levelToValue[sh.interest] || 1; // Y position (Influence): High influence = low Y value (top of div) const yPercent = 100 - valueToPercent[influenceVal]; // X position (Interest): High interest = high X value (right of div) const xPercent = valueToPercent[interestVal]; const dot = document.createElement("div"); dot.className = `psa-stakeholder-dot psa-dot-${sh.influence}`; // Color by influence dot.style.top = `${yPercent}%`; dot.style.left = `${xPercent}%`; dot.innerHTML = `${sh.name}`; matrixContainer.appendChild(dot); // 2. Render Table Row const tr = document.createElement("tr"); tr.innerHTML = ` ${sh.name} ${sh.role} ${sh.interest.charAt(0).toUpperCase() + sh.interest.slice(1)} ${sh.influence.charAt(0).toUpperCase() + sh.influence.slice(1)} ${sh.strategy} `; tableBody.appendChild(tr); }); } // --- Event Handlers --- // Update Dashboard Button updateBtn.addEventListener("click", () => { appState.projectName = projectNameInput.value; // Update project name saveState(); renderDashboardTab(); showTab(0); }); // Add Stakeholder addShBtn.addEventListener("click", () => { const name = shNameInput.value.trim(); const role = shRoleInput.value.trim(); const interest = shInterestSelect.value; const influence = shInfluenceSelect.value; const strategy = shStrategyInput.value.trim(); if (!name || !role) { alert("Please enter both stakeholder name and role."); return; } const newStakeholder = { id: Date.now(), name: name, role: role, interest: interest, influence: influence, strategy: strategy }; appState.stakeholders.push(newStakeholder); saveState(); renderConfigTab(); // Clear form shNameInput.value = ""; shRoleInput.value = ""; shInterestSelect.value = "medium"; shInfluenceSelect.value = "high"; shStrategyInput.value = ""; }); // Remove Stakeholder (Event Delegation) stakeholdersList.addEventListener("click", (e) => { if (e.target.classList.contains("psa-remove-btn")) { const id = parseInt(e.target.dataset.id); appState.stakeholders = appState.stakeholders.filter(s => s.id !== id); saveState(); renderConfigTab(); } }); // PDF Download pdfBtn.addEventListener("click", () => { const { jsPDF } = window.jspdf; const fileName = `${appState.projectName.replace(/ /g, '_')}_Stakeholder_Analysis.pdf`; // Temporarily adjust styles for better PDF layout if needed const matrixOriginalHeight = matrixContainer.style.height; matrixContainer.style.height = 'auto'; // Let it expand if needed for PDF capture html2canvas(exportArea, { scale: 2, useCORS: true, backgroundColor: '#ffffff', // Attempt to capture full height if content overflows default viewport capture windowHeight: exportArea.scrollHeight }).then(canvas => { matrixContainer.style.height = matrixOriginalHeight; // Restore height const imgData = canvas.toDataURL('image/png'); const doc = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); const pdfWidth = doc.internal.pageSize.getWidth(); const pdfHeight = doc.internal.pageSize.getHeight(); const imgProps = doc.getImageProperties(imgData); const imgWidth = imgProps.width; const imgHeight = imgProps.height; const margin = 40; const usableWidth = pdfWidth - (2 * margin); const ratio = usableWidth / imgWidth; let scaledHeight = imgHeight * ratio; let position = margin; // Check if content exceeds page height if (scaledHeight > pdfHeight - (2 * margin)) { // Handle multi-page const pageHeight = pdfHeight - (2 * margin); let heightLeft = scaledHeight; doc.addImage(imgData, 'PNG', margin, position, usableWidth, scaledHeight); heightLeft -= pageHeight; while (heightLeft > 0) { position = margin - heightLeft; // Adjust position for the next page doc.addPage(); doc.addImage(imgData, 'PNG', margin, position, usableWidth, scaledHeight); heightLeft -= pageHeight; } } else { // Single page doc.addImage(imgData, 'PNG', margin, margin, usableWidth, scaledHeight); } doc.save(fileName); }).catch(err => { matrixContainer.style.height = matrixOriginalHeight; // Restore height on error too console.error("PSA PDF Error:", err); // alert("An error occurred while generating the PDF."); // Per spec }); }); // --- Local Storage --- function saveState() { try { localStorage.setItem("psaAppState", JSON.stringify(appState)); } catch (e) { console.warn("PSA: Could not save state."); } } function loadState() { try { const storedState = localStorage.getItem("psaAppState"); if (storedState) appState = JSON.parse(storedState); } catch (e) { console.warn("PSA: Could not load state."); } } // --- Initial Load --- loadState(); renderConfigTab(); // Load state into config first renderDashboardTab(); // Then render dashboard showTab(0); // Start on Dashboard });
Scroll to Top