Target Budget: $${targetBudget.toLocaleString()} | Target Output: ${targetEnergy.toLocaleString()} kWh/yr
Plan Details
This plan allocates the $${totalCost.toLocaleString()} budget to achieve an estimated ${totalOutput.toLocaleString()} kWh/yr.
${planDetails.map(tech => `
- ${tech.name}: Contributes ${tech.output.toLocaleString()} kWh/yr at an estimated cost of $${tech.cost.toLocaleString()} (for ${tech.units} ${tech.unitName}).
`).join('')}
Recommendations
- Conduct site-specific feasibility studies for all selected technologies.
- Verify local (USA) rebates and incentives which may reduce the final cost.
- Consult with a qualified installation professional.
`;
pdfContent.innerHTML = html;
// Render Charts
renderMixChart(planDetails);
renderCostChart(planDetails);
pdfDownloadBtn.style.display = 'inline-block';
}
function renderMixChart(planDetails) {
if (!mixChartCanvas) return;
const labels = planDetails.map(tech => tech.name);
const data = planDetails.map(tech => tech.output);
if (mixChartInstance) mixChartInstance.destroy();
mixChartInstance = new Chart(mixChartCanvas.getContext('2d'), {
type: 'doughnut',
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: ['#166534', '#15803d', '#22c55e', '#4ade80', '#86efac'],
borderColor: '#ffffff',
borderWidth: 3
}]
},
options: {
responsive: true,
maintainAspectRatio: false, // Per spec
plugins: {
legend: { position: 'bottom' },
tooltip: {
callbacks: {
label: (context) => `${context.label}: ${context.raw.toLocaleString()} kWh/yr`
}
}
}
}
});
}
function renderCostChart(planDetails) {
if (!costChartCanvas) return;
const labels = planDetails.map(tech => tech.name);
const costData = planDetails.map(tech => tech.cost);
const outputData = planDetails.map(tech => tech.output);
if (costChartInstance) costChartInstance.destroy();
costChartInstance = new Chart(costChartCanvas.getContext('2d'), {
type: 'bar',
data: {
labels: labels,
datasets: [
{
label: 'Est. Cost ($)',
data: costData,
backgroundColor: '#737373', // stone-500
yAxisID: 'yCost',
},
{
label: 'Est. Output (kWh)',
data: outputData,
backgroundColor: '#15803d', // green-700
yAxisID: 'yOutput',
}
]
},
options: {
responsive: true,
maintainAspectRatio: false, // Per spec
scales: {
yCost: {
type: 'linear',
display: true,
position: 'left',
title: { display: true, text: 'Cost ($)' }
},
yOutput: {
type: 'linear',
display: true,
position: 'right',
title: { display: true, text: 'Output (kWh)' },
grid: { drawOnChartArea: false }
}
}
}
});
}
// --- Utility Functions ---
function showMessageModal(message) {
let modal = document.getElementById('repg-modal');
if (!modal) {
modal = document.createElement('div');
modal.id = 'repg-modal';
modal.className = 'repg-pdf-hide fixed inset-0 bg-gray-800 bg-opacity-50 flex items-center justify-center p-4';
modal.style.zIndex = '1000';
modal.innerHTML = `
`;
document.body.appendChild(modal);
modal.querySelector('#repg-modal-close').addEventListener('click', () => {
modal.style.display = 'none';
});
}
modal.querySelector('#repg-modal-message').textContent = message;
modal.style.display = 'flex';
}
async function downloadPDF() {
// Per user request, ensuring this is robust
pdfTarget.classList.add('repg-pdf-view');
try {
const canvas = await html2canvas(pdfTarget, {
scale: 2,
logging: false,
useCORS: true,
onclone: (doc) => {
// Copy both live chart canvases to the cloned document
const originalMix = mixChartCanvas;
const clonedMix = doc.getElementById('repg-mix-chart');
if (clonedMix) {
clonedMix.getContext('2d').drawImage(originalMix, 0, 0);
}
const originalCost = costChartCanvas;
const clonedCost = doc.getElementById('repg-cost-chart');
if (clonedCost) {
clonedCost.getContext('2d').drawImage(originalCost, 0, 0);
}
}
});
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF('p', 'mm', 'a4');
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (canvas.height * pdfWidth) / canvas.width;
const pageMargin = 15;
const contentWidth = pdfWidth - (pageMargin * 2);
const contentHeight = (canvas.height * contentWidth) / canvas.width;
pdf.addImage(imgData, 'PNG', pageMargin, pageMargin, contentWidth, contentHeight);
pdf.save(`${generatedPlan.projectName || 'Renewable_Plan'}.pdf`);
} catch (error) {
console.error("Error generating PDF:", error);
showMessageModal("An error occurred while generating the PDF. Please try again.");
} finally {
pdfTarget.classList.remove('repg-pdf-view');
}
}
function renderAll() {
renderConfig();
populateTechChecklist();
renderGeneratedPlan();
}
function loadSampleData() {
db.technologies = [
{ id: 1, name: "Solar Panels (Rooftop)", unit: "kWp", cost: 2800, output: 1300 },
{ id: 2, name: "Small Wind Turbine (10kW)", unit: "turbine", cost: 45000, output: 30000 },
{ id: 3, name: "Geothermal Heat Pump", unit: "system", cost: 20000, output: 15000 }
];
// Sample data is USA-centric (Spec 7)
projectNameInput.value = "USA Farmstead Project";
targetBudgetInput.value = 100000;
targetEnergyInput.value = 50000;
renderAll();
}
// --- 4. EVENT BINDING & INITIALIZATION ---
navTabs.forEach((tab, index) => {
tab.addEventListener('click', () => showTab(index));
});
addTechForm.addEventListener('submit', handleAddTech);
planForm.addEventListener('submit', handleGeneratePlan);
pdfDownloadBtn.addEventListener('click', downloadPDF);
// Initial Load
loadSampleData();
showTab(1); // Start on the input tab
});