No calculation has been performed.
";
}
break;
// --- Biology PDF ---
case 2:
title = "Genetic Inheritance Report";
const bioInputs = {
"Parent 1 Genotype": this.elements.bioP1.value,
"Parent 2 Genotype": this.elements.bioP2.value,
"Dominant Trait": this.elements.bioTraitDom.value,
"Recessive Trait": this.elements.bioTraitRec.value
};
inputsHtml = this.buildPdfTable(bioInputs, "Cross Inputs");
if (this.elements.bioResults.style.display === 'block') {
resultsHtml = "
Simulation Results
" +
this.elements.bioResSquare.innerHTML +
"
Genotype Ratios
" +
this.elements.bioResGenotype.outerHTML +
"
Phenotype Ratios
" +
this.elements.bioResPhenotype.outerHTML;
} else {
resultsHtml = "
No cross has been generated.
";
}
break;
default:
return null;
}
return `
${title}
${inputsHtml}
${resultsHtml}
`;
},
buildPdfTable: function(data, title) {
let rows = '';
for (const [key, value] of Object.entries(data)) {
rows += `
| ${key} | ${value} |
|---|
`;
}
return `
${title}
`;
},
downloadPDF: function() {
// Get PDF libraries from window object
const { jsPDF } = window.jspdf;
const html2canvas = window.html2canvas;
if (!jsPDF || !html2canvas) {
alert("PDF generation libraries are not loaded. Please try again.");
return;
}
// 1. Generate the clean HTML for the report
const reportHtml = this.generatePdfReportHtml();
if (!reportHtml) return;
// 2. Create a temporary, off-screen element to render this HTML
const pdfContainer = document.createElement('div');
pdfContainer.style.position = 'absolute';
pdfContainer.style.left = '-9999px';
pdfContainer.style.top = '0';
pdfContainer.innerHTML = reportHtml;
document.body.appendChild(pdfContainer);
// Find the .sim-pdf-output element we just created
const contentToCapture = pdfContainer.querySelector('.sim-pdf-output');
if (!contentToCapture) {
document.body.removeChild(pdfContainer);
return;
}
// 3. Use html2canvas to capture the content
html2canvas(contentToCapture, { scale: 2 }) // Higher scale for better quality
.then(canvas => {
// 4. Create jsPDF instance
const doc = new jsPDF({
orientation: 'p',
unit: 'px',
format: 'a4'
});
const imgData = canvas.toDataURL('image/png');
const imgProps = doc.getImageProperties(imgData);
const pdfWidth = doc.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
let heightLeft = pdfHeight;
let position = 0;
// 5. Add image to PDF
doc.addImage(imgData, 'PNG', 0, position, pdfWidth, pdfHeight);
heightLeft -= doc.internal.pageSize.getHeight();
// 6. Handle multi-page content (if report is too long)
while (heightLeft >= 0) {
position = heightLeft - pdfHeight;
doc.addPage();
doc.addImage(imgData, 'PNG', 0, position, pdfWidth, pdfHeight);
heightLeft -= doc.internal.pageSize.getHeight();
}
// 7. Save the PDF
doc.save('Science_Simulator_Report.pdf');
// 8. Clean up the temporary element
document.body.removeChild(pdfContainer);
})
.catch(err => {
console.error("Error generating PDF:", err);
alert("An error occurred while generating the PDF.");
// Ensure cleanup even on error
if (document.body.contains(pdfContainer)) {
document.body.removeChild(pdfContainer);
}
});
},
// --- Initialization ---
init: function() {
// Query elements once
this.elements = {
tabContents: document.querySelectorAll('.sim-tab-content'),
tabButtons: document.querySelectorAll('.sim-tab-button'),
prevButton: document.getElementById('sim-prev-btn'),
nextButton: document.getElementById('sim-next-btn'),
// Physics
physVelocity: document.getElementById('phys-velocity'),
physAngle: document.getElementById('phys-angle'),
physHeight: document.getElementById('phys-height'),
physGravity: document.getElementById('phys-gravity'),
physicsResults: document.getElementById('physics-results'),
physResTime: document.getElementById('phys-res-time'),
physResHeight: document.getElementById('phys-res-height'),
physResRange: document.getElementById('phys-res-range'),
// Chemistry
chemMa: document.getElementById('chem-m-acid'),
chemVa: document.getElementById('chem-v-acid'),
chemMb: document.getElementById('chem-m-base'),
chemResults: document.getElementById('chem-results'),
chemResVolume: document.getElementById('chem-res-volume'),
// Biology
bioP1: document.getElementById('bio-p1'),
bioP2: document.getElementById('bio-p2'),
bioTraitDom: document.getElementById('bio-trait-dom'),
bioTraitRec: document.getElementById('bio-trait-rec'),
bioResults: document.getElementById('bio-results'),
bioResSquare: document.getElementById('bio-res-square'),
bioResGenotype: document.getElementById('bio-res-genotype'),
bioResPhenotype: document.getElementById('bio-res-phenotype')
};
// Set initial state
this.openTab('physics', 0);
}
};
// Run the init function after the DOM is fully loaded
document.addEventListener('DOMContentLoaded', function() {
// Check if the script has already been initialized (for Elementor editor)
if (!document.getElementById('science-simulator-tool').classList.contains('sim-initialized')) {
simApp.init();
document.getElementById('science-simulator-tool').classList.add('sim-initialized');
}
});