`;
// 3. Log Table (Simplified for HTML preview)
if (data.log.length > 0) {
html += `
II. Procedure Log & Observations
`;
let tableHtml = `
| Step # |
Action |
Observation |
Raw Data |
`;
data.log.forEach(row => {
tableHtml += `
| ${row.step} |
${row.action} |
${row.obs} |
${row.data} |
`;
});
tableHtml += `
`;
html += tableHtml;
}
// 4. Conclusion Section
html += `
III. Analysis & Conclusion (To be filled)
`;
html += `
`;
container.innerHTML = html;
}
function vlngSwitchTab(tabId) {
document.querySelectorAll('.vlng-tab-btn').forEach(b => b.classList.remove('active'));
document.querySelectorAll('.vlng-content').forEach(c => c.classList.remove('active'));
const idx = tabId === 'setup' ? 0 : (tabId === 'log' ? 1 : 2);
document.querySelectorAll('.vlng-tab-btn')[idx].classList.add('active');
document.getElementById('vlng-' + tabId).classList.add('active');
if (tabId === 'report') {
vlngRenderReport();
}
}
function vlngLoadExample() {
if(!confirm("Overwrite current data and load example Titration experiment?")) return;
document.getElementById('inp-title').value = "Titration of an Unknown Acid";
document.getElementById('inp-simulator').value = "ChemLab Online v2.1";
document.getElementById('inp-objective').value = "Determine the concentration of an unknown monoprotic acid solution using standard NaOH.";
document.getElementById('inp-hypothesis').value = "The unknown acid concentration is predicted to be approximately 0.1 M, based on source material context.";
// Clear and refill log entries
document.getElementById('vlng-log-rows-container').innerHTML = '';
vlngAddLogRow(1, "Prepare 50 mL of 0.1 M NaOH solution and fill the virtual burette.", "Initial burette volume set to 0.00 mL.", "Volume NaOH: 50 mL");
vlngAddLogRow(2, "Add 3 drops of phenolphthalein indicator to 10 mL acid solution.", "Solution color is clear and colorless.", "Initial pH: 2.3");
vlngAddLogRow(3, "Titrate with NaOH until endpoint (slight pink color).", "Endpoint reached after sustained pink color for 30s.", "Final Burette Reading: 10.55 mL");
vlngAddLogRow(4, "Record NaOH volume used.", "10.55 mL", "Volume used: 0.01055 L");
vlngRenderReport();
vlngSwitchTab('report');
}
/* --- PDF Generation --- */
async function vlngGeneratePDF() {
vlngRenderReport(); // Ensure report is updated
const data = {
title: document.getElementById('inp-title').value || "Experiment Title",
simulator: document.getElementById('inp-simulator').value || "Simulator Used",
objective: document.getElementById('inp-objective').value || "Objective pending.",
hypothesis: document.getElementById('inp-hypothesis').value || "Hypothesis pending.",
log: vlngGetLogData()
};
if (data.log.length === 0) {
alert("Please add procedure steps before generating the PDF.");
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'mm', 'a4');
// Styling
const blue = [70, 130, 180]; // Steel Blue
let y = 20;
// 1. Header
doc.setFillColor(...blue);
doc.rect(0, 0, 210, 20, 'F');
doc.setTextColor(255, 255, 255);
doc.setFontSize(16);
doc.text("Virtual Lab Notes", 14, 13);
doc.setFontSize(10);
doc.text(`Experiment: ${data.title}`, 14, 17);
y = 30;
// 2. Metadata
doc.setTextColor(0, 0, 0);
doc.setFontSize(10);
doc.setFont("helvetica", "bold");
doc.text("Objective:", 14, y);
doc.text("Hypothesis:", 105, y);
y += 5;
doc.setFont("times", "normal");
doc.setTextColor(50, 50, 50);
const splitObj = doc.splitTextToSize(data.objective, 85);
doc.text(splitObj, 14, y);
const splitHyp = doc.splitTextToSize(data.hypothesis, 85);
doc.text(splitHyp, 105, y);
y += Math.max(splitObj.length, splitHyp.length) * 5 + 10;
// 3. Log Table
doc.setFontSize(12);
doc.setFont("helvetica", "bold");
doc.setTextColor(70, 130, 180);
doc.text("Procedure Log & Data", 14, y);
y += 5;
const tableBody = data.log.map(item => [
item.step,
item.action,
item.obs,
item.data
]);
doc.autoTable({
startY: y,
head: [['#', 'Action / Step', 'Observation', 'Raw Data']],
body: tableBody,
theme: 'grid',
headStyles: { fillColor: blue, fontSize: 9 },
styles: { fontSize: 8, overflow: 'linebreak' },
columnStyles: {
0: { cellWidth: 8, halign: 'center', fontStyle: 'bold' },
1: { cellWidth: 50 },
2: { cellWidth: 60 },
3: { cellWidth: 55, font: 'courier' }
}
});
// 4. Conclusion
y = doc.lastAutoTable.finalY + 10;
if (y > 270) { doc.addPage(); y = 20; }
doc.setFontSize(12);
doc.setFont("helvetica", "bold");
doc.text("Analysis & Conclusion", 14, y);
y += 5;
doc.setFontSize(10);
doc.setFont("times", "italic");
doc.text("...", 14, y + 5);
doc.save(`LabNotes_${data.title.replace(/\s/g, '_')}.pdf`);
}