Science Experiment Simulator

Science Experiment Simulator

This calculates the volume of base needed to reach the equivalence point for a 1:1 monoprotic strong acid/base titration.

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}

${rows}
`; }, 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'); } });