Land Development Investment Risk Calculator

Land Development Investment Risk Calculator

Project & Land Details

Market & Infrastructure Details

Financial & Team Factors

Risk Assessment Results

Please fill in the details in the previous tabs and click "Calculate Risk" to see the analysis.

${overallRiskPercentage.toFixed(1)}%

${riskLevel.label}

${overallRiskPercentage.toFixed(1)}%

Risk Factor Summary:

`; for (const categoryKey in riskCategories) { const categoryData = riskCategories[categoryKey]; const categoryName = categoryKey.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase()); const categoryScorePercentage = categoryData.maxScore > 0 ? (categoryData.currentScore / categoryData.maxScore) * 100 : 0; const categoryRiskLevel = getRiskLevel(categoryScorePercentage); html += `
${categoryName} (Weight: ${categoryData.weight*100}%) - Risk: ${categoryRiskLevel.label}
    `; categoryData.factors.forEach(factor => { html += `
  • ${factor.label}: ${factor.value} (Risk Points: ${factor.risk})
  • `; }); html += `
`; } resultsOutputElem.innerHTML = html; navigateToTab('tabResults'); } function generatePdf() { const pdf = new jsPDF(); const today = new Date().toLocaleDateString(); const projectName = getElementValue('projectName', false) || "N/A"; pdf.setFontSize(18); pdf.setTextColor(59, 130, 246); // Tailwind blue-600 pdf.text("Land Development Investment Risk Report", 105, 20, null, null, "center"); pdf.setFontSize(10); pdf.setTextColor(100); pdf.text(`Project: ${projectName}`, 14, 30); pdf.text(`Generated on: ${today}`, 105, 30, null, null, "center"); let yPos = 40; const overallRiskPercentage = calculateRiskScore(); // Recalculate to ensure data is fresh const riskLevel = getRiskLevel(overallRiskPercentage); pdf.setFontSize(12); // Removed the problematic setFillColor line that was causing the error. // The text color for the summary block. pdf.setTextColor(riskLevel.color === "#facc15" ? 0 : 255); // Black for yellow, white for others // A simple colored block for summary const rectColor = riskLevel.color; // Use hex color directly // Parse the hex color string into R, G, B components const parts = rectColor.substring(1).match(/.{1,2}/g).map(hex => parseInt(hex, 16)); pdf.setFillColor(parts[0], parts[1], parts[2]); // Set fill color using RGB components pdf.rect(14, yPos, 182, 20, 'F'); // Draw the filled rectangle pdf.setFontSize(14); // Ensure text is visible on the colored rectangle if (riskLevel.color === "#facc15") { // If color is yellow, use black text pdf.setTextColor(0,0,0); } else { // For other colors (greens, oranges, reds), use white text pdf.setTextColor(255,255,255); } pdf.text(`Overall Risk: ${overallRiskPercentage.toFixed(1)}% - ${riskLevel.label}`, 105, yPos + 8, null, null, "center"); yPos += 25; pdf.setTextColor(0); // Reset text color to black for subsequent text for (const categoryKey in riskCategories) { const categoryData = riskCategories[categoryKey]; const categoryName = categoryKey.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase()); const categoryScorePercentage = categoryData.maxScore > 0 ? (categoryData.currentScore / categoryData.maxScore) * 100 : 0; const categoryRiskInfo = getRiskLevel(categoryScorePercentage); pdf.setFontSize(12); pdf.setTextColor(59, 130, 246); pdf.text(`${categoryName} (Weight: ${categoryData.weight*100}%) - Risk: ${categoryRiskInfo.label}`, 14, yPos); yPos += 7; const tableData = categoryData.factors.map(f => [f.label, f.value, f.risk.toString()]); pdf.autoTable({ startY: yPos, head: [['Factor', 'Selected Value', 'Risk Points']], body: tableData, theme: 'grid', headStyles: { fillColor: [229, 231, 235], textColor: [55, 65, 81] }, // gray-200, gray-700 styles: { fontSize: 9, cellPadding: 2 }, margin: { left: 14, right: 14 } }); yPos = pdf.lastAutoTable.finalY + 8; } // Add informational inputs to PDF yPos += 5; pdf.setFontSize(12); pdf.setTextColor(59, 130, 246); pdf.text("Additional Project Information", 14, yPos); yPos += 7; const additionalInfo = [ ["Land Cost ($)", getElementValue('landCost').toLocaleString()], ["Land Size (Acres)", getElementValue('landSize').toLocaleString()], ["Est. Dev Costs (Excl. Land) ($)", getElementValue('devCosts').toLocaleString()] ]; pdf.autoTable({ startY: yPos, head: [['Item', 'Value']], body: additionalInfo, theme: 'grid', headStyles: { fillColor: [229, 231, 235], textColor: [55, 65, 81] }, styles: { fontSize: 9, cellPadding: 2 }, margin: { left: 14, right: 14 } }); pdf.save(`Land_Dev_Risk_Report_${projectName.replace(/[^a-zA-Z0-9]/g, '_')}.pdf`); } // Event Listeners & Initialization document.addEventListener('DOMContentLoaded', () => { // Assign elements projectNameElem = document.getElementById('projectName'); landCostElem = document.getElementById('landCost'); landSizeElem = document.getElementById('landSize'); zoningStatusElem = document.getElementById('zoningStatus'); environmentalConcernsElem = document.getElementById('environmentalConcerns'); siteConditionsElem = document.getElementById('siteConditions'); marketDemandElem = document.getElementById('marketDemand'); economicOutlookElem = document.getElementById('economicOutlook'); infraAvailabilityElem = document.getElementById('infraAvailability'); roadAccessElem = document.getElementById('roadAccess'); proximityAmenitiesElem = document.getElementById('proximityAmenities'); devCostsElem = document.getElementById('devCosts'); fundingSourceElem = document.getElementById('fundingSource'); contingencyBudgetElem = document.getElementById('contingencyBudget'); devTimelineElem = document.getElementById('devTimeline'); teamExperienceElem = document.getElementById('teamExperience'); profitMarginElem = document.getElementById('profitMargin'); resultsOutputElem = document.getElementById('resultsOutput'); calculateRiskButtonElem = document.getElementById('calculateRiskButton'); downloadPdfButtonElem = document.getElementById('downloadPdfButton'); // Null checks for critical elements if (!calculateRiskButtonElem) { console.error("Calculate Risk button not found!"); } else { calculateRiskButtonElem.addEventListener('click', displayResults); } if (!downloadPdfButtonElem) { console.error("Download PDF button not found!"); } else { downloadPdfButtonElem.addEventListener('click', generatePdf); } // Initialize with the first tab active const firstTabButton = document.querySelector('.tab-button'); if (firstTabButton) { changeTab({ currentTarget: firstTabButton }, 'tabProjectLand'); } });
Scroll to Top