Timberland Investment ROI Calculator
Investment & Land Details
Timber Details & Growth Projection
This is the overall increase in the standing timber's market value per year, combining growth and price changes.
Enter if you plan to replant immediately after final harvest, affecting final year cash flow.
Annual Operational Costs
Harvest & Sale Projections (at end of Investment Horizon)
This is the estimated gross value of timber at harvest time. If you used the appreciation rate, this should reflect that appreciated value.
Financial Parameters for Analysis
Timberland Investment Analysis Results
Please complete all previous sections and click "Calculate ROI & Metrics".
Total Initial Investment: ${timroi_formatCurrency(timroi_analysisData.results.totalInitialInvestment)}
Total Net Profit over ${inputs.investmentHorizonYears} Years: ${timroi_formatCurrency(timroi_analysisData.results.totalNetProfit)}
Return on Investment (ROI): ${timroi_analysisData.results.roi.toFixed(2)}%
Simple Payback Period: ${timroi_analysisData.results.simplePaybackPeriod}
Net Present Value (NPV) @ ${(inputs.discountRate*100).toFixed(1)}%: ${timroi_formatCurrency(timroi_analysisData.results.npv)}
Internal Rate of Return (IRR): ${timroi_analysisData.results.irr}
`; dlButton.style.display = 'block'; resTabLink.disabled = false; resTabLink.click(); } } window.timroi_downloadPDF = function() { const { jsPDF } = window.jspdf; if (!jsPDF || !timroi_analysisData.inputs || Object.keys(timroi_analysisData.inputs).length === 0) { alert("PDF library not loaded or no data to export. Please analyze first."); return; } const doc = new jsPDF(); let yPos = 20; const lineHeight = 7; const indent = 5; const pageMargin = 15; const pageWidth = doc.internal.pageSize.getWidth(); const usableWidth = pageWidth - 2 * pageMargin; doc.setFontSize(18); doc.setTextColor(44, 62, 80); // #2c3e50 doc.text("Timberland Investment ROI Analysis", pageWidth / 2, yPos, { align: 'center' }); yPos += lineHeight * 2.5; function addSection(title, dataObj, isList = false) { if (yPos > doc.internal.pageSize.getHeight() - pageMargin - 30) { doc.addPage(); yPos = pageMargin; } doc.setFontSize(13); doc.setFont(undefined, 'bold'); doc.setTextColor(85, 107, 47); // #556b2f doc.text(title, pageMargin, yPos); yPos += lineHeight * 1.5; doc.setFontSize(10); doc.setFont(undefined, 'normal'); doc.setTextColor(51,51,51); if (isList) { dataObj.forEach(item => { if (yPos > doc.internal.pageSize.getHeight() - pageMargin - lineHeight) { doc.addPage(); yPos = pageMargin; } doc.text(item, pageMargin + indent, yPos); yPos += lineHeight; }); } else { for (const [key, value] of Object.entries(dataObj)) { if (yPos > doc.internal.pageSize.getHeight() - pageMargin - lineHeight) { doc.addPage(); yPos = pageMargin; } let formattedKey = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase()); let valStr = String(value); if (typeof value === 'number') { if (key.toLowerCase().includes('rate') || key.toLowerCase().includes('percent') || key.toLowerCase().includes('escalation') || key.toLowerCase().includes('roi') || key.toLowerCase().includes('appreciation')) { valStr = value.toFixed(2) + '%'; } else { valStr = timroi_formatCurrency(value); } } else if (key === 'irr' || key === 'simplePaybackPeriod') { valStr = String(value); } doc.text(`${formattedKey}:`, pageMargin + indent, yPos); doc.text(valStr, pageMargin + indent + 85, yPos, {align: 'left', maxWidth: usableWidth - (indent + 85)}); yPos += lineHeight * 1.1; } } yPos += lineHeight * 0.5; } const inputSummaryForPdf = { "Property Name": timroi_analysisData.inputs.propertyName, "Location Scope": timroi_analysisData.inputs.locationScope, "Land Area (Acres)": timroi_analysisData.inputs.landAreaAcres, "Land Purchase Cost": timroi_analysisData.inputs.landPurchaseCost, "Initial Timber Value": timroi_analysisData.inputs.initialTimberValue, "Acquisition Costs": timroi_analysisData.inputs.acquisitionCosts, "Investment Horizon (Years)": timroi_analysisData.inputs.investmentHorizonYears, "Primary Timber Species": timroi_analysisData.inputs.primarySpecies, "Timber Value Appreciation Rate (% p.a.)": (timroi_analysisData.inputs.timberValueAppreciationPa * 100), "Replanting Cost (End of Horizon)": timroi_analysisData.inputs.replantingCost, "Annual Property Taxes": timroi_analysisData.inputs.propertyTaxesAnnual, "Annual Management Fees": timroi_analysisData.inputs.managementFeesAnnual, "Other Annual Costs": timroi_analysisData.inputs.otherCostsAnnual, "Annual Costs Escalation Rate (%)": (timroi_analysisData.inputs.annualCostsEscalation * 100), "Projected Timber Sale Value (Gross)": timroi_analysisData.inputs.projectedTimberSaleValue, "Harvesting Costs (% of Sale)": (timroi_analysisData.inputs.harvestingCostsPercent * 100), "Projected Land Sale Value (Gross)": timroi_analysisData.inputs.projectedLandSaleValue, "Land Sale Costs (% of Sale)": (timroi_analysisData.inputs.landSaleCostsPercent*100), "Discount Rate (%)": (timroi_analysisData.inputs.discountRate * 100) }; addSection("Input Parameters Summary", inputSummaryForPdf); const resultsSummaryForPdf = { "Total Initial Investment": timroi_analysisData.results.totalInitialInvestment, "Total Net Profit": timroi_analysisData.results.totalNetProfit, "Return on Investment (ROI)": timroi_analysisData.results.roi, "Simple Payback Period": timroi_analysisData.results.simplePaybackPeriod, "Net Present Value (NPV)": timroi_analysisData.results.npv, "Internal Rate of Return (IRR)": timroi_analysisData.results.irr }; addSection("Key Investment Metrics", resultsSummaryForPdf); let cashFlowSampleForPdf = ["Year | Op. Costs ($) | Net Harvest ($) | Net Land Sale ($) | Replant ($) | Net CF ($)"]; cashFlowSampleForPdf.push(`0 | --- | --- | --- | --- | ${timroi_formatCurrency(-timroi_analysisData.results.totalInitialInvestment)}`); const yearsToShowInPdf = Math.min(timroi_analysisData.annual_cash_flows.length, 5); for(let i = 0; i < yearsToShowInPdf; i++) { const cf = timroi_analysisData.annual_cash_flows[i]; // Only show harvest/land sale/replant for the final year in this simplified sample let harvestText = (cf.year === timroi_analysisData.inputs.investmentHorizonYears) ? timroi_formatCurrency(cf.netTimberRevenue) : "---"; let landSaleText = (cf.year === timroi_analysisData.inputs.investmentHorizonYears) ? timroi_formatCurrency(cf.netLandSaleRevenue) : "---"; let replantText = (cf.year === timroi_analysisData.inputs.investmentHorizonYears) ? timroi_formatCurrency(-cf.replantingCost) : "---"; cashFlowSampleForPdf.push( `${cf.year} | ` + `${timroi_formatCurrency(cf.operatingCosts)} | ` + `${harvestText} | ` + `${landSaleText} | ` + `${replantText} | ` + `${timroi_formatCurrency(cf.netCashFlow)}` ); } if (timroi_analysisData.annual_cash_flows.length > 5) { // If more than 5 years, show ellipsis and last year cashFlowSampleForPdf.push("..."); const lastCf = timroi_analysisData.annual_cash_flows[timroi_analysisData.annual_cash_flows.length - 1]; cashFlowSampleForPdf.push( `${lastCf.year} | ` + `${timroi_formatCurrency(lastCf.operatingCosts)} | ` + `${timroi_formatCurrency(lastCf.netTimberRevenue)} | ` + `${timroi_formatCurrency(lastCf.netLandSaleRevenue)} | ` + `${timroi_formatCurrency(-lastCf.replantingCost)} | ` + `${timroi_formatCurrency(lastCf.netCashFlow)}` ); } if (yPos > doc.internal.pageSize.getHeight() - pageMargin - (cashFlowSampleForPdf.length * lineHeight) - (lineHeight*2.5) ) { doc.addPage(); yPos = pageMargin; } doc.setFont(undefined,'normal'); doc.setFontSize(8); addSection("Annual Cash Flow Summary (Sample)", cashFlowSampleForPdf, true); doc.save('Timberland_Investment_ROI_Analysis.pdf'); }