`;
} else {
resultsArea.innerHTML = '
';
}
});
}
// --- PDF Download Function ---
if (pdfDownloadBtn) {
pdfDownloadBtn.addEventListener("click", () => {
// II.C & V.A: PDF Download
if (
typeof window.jspdf === "undefined" ||
typeof window.jspdf.jsPDF === "undefined"
) {
alert(
"Error: PDF library (jsPDF) is not loaded. Please check your internet connection."
);
return;
}
if (typeof window.jspdf.plugin.autotable === "undefined") {
alert(
"Error: PDF library (jsPDF-AutoTable) is not loaded. Please check your internet connection."
);
return;
}
if (!lastIdentification.inputs) {
alert("Please run an identification first before downloading.");
return;
}
generatePDF();
});
}
function generatePDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const { inputs, bestMatch } = lastIdentification;
const primaryColor =
getComputedStyle(container).getPropertyValue(
"--rmi-primary-color"
) || "#4a5568";
const headStyles = {
fillColor: primaryColor,
textColor: "#ffffff",
fontStyle: "bold",
};
// Title
doc.setFont("helvetica", "bold");
doc.setFontSize(18);
doc.setTextColor(primaryColor);
doc.text("Rock Identification Report", 105, 20, {
align: "center",
});
doc.setFontSize(10);
doc.setTextColor("#888");
doc.text(
`Report Generated: ${new Date().toLocaleDateString()}`,
105,
26,
{ align: "center" }
);
// 1. User Input Table
const inputHead = [["Property", "Selected Value"]];
const inputBody = [
["Color", inputs.color || "Not specified"],
["Luster", inputs.luster || "Not specified"],
["Streak", inputs.streak || "Not specified"],
["Hardness", inputs.hardness || "Not specified"],
];
doc.autoTable({
startY: 40,
head: inputHead,
body: inputBody,
theme: "striped",
headStyles: headStyles,
});
// 2. Results Table
let lastY = doc.autoTable.previous.finalY;
if (bestMatch && bestMatch.score > 0) {
const rock = bestMatch.rock;
const resultHead = [[
{ content: `Best Match: ${rock.name}`, colSpan: 2, styles: { halign: 'center' } }
]];
const resultBody = [
["Colors", rock.colors.join(", ")],
["Luster", rock.luster],
["Streak", rock.streak],
["Hardness", `${rock.hardness} (Mohs)`],
];
doc.autoTable({
startY: lastY + 15,
head: resultHead,
body: resultBody,
theme: "grid",
headStyles: headStyles
});
} else {
doc.setFont("helvetica", "normal");
doc.setFontSize(12);
doc.text("No matching rocks were found for the selected properties.", 15, lastY + 15);
}
doc.save("Rock-Identification-Report.pdf");
}
// --- Utility Function ---
function escapeHTML(str) {
if (!str) return "";
return str
.toString()
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"g, """)
.replace(/'/g, "'");
}
// --- Initial Load ---
function loadSampleData() {
// Per spec: USA-relevant sample data
const sampleData = [
{ id: "rock_1", name: "Quartz", colors: ["White", "Clear", "Pink", "Gray", "Purple"], luster: "Glassy", streak: "White", hardness: 7 },
{ id: "rock_2", name: "Pyrite", colors: ["Gold", "Brass-Yellow"], luster: "Metallic", streak: "Greenish-Black", hardness: 6.5 },
{ id: "rock_3", name: "Hematite", colors: ["Red", "Brown", "Black", "Silver"], luster: "Metallic", streak: "Red-Brown", hardness: 6 },
{ id: "rock_4", name: "Calcite", colors: ["White", "Clear", "Yellow", "Blue"], luster: "Glassy", streak: "White", hardness: 3 },
{ id: "rock_5", name: "Talc", colors: ["White", "Green", "Gray"], luster: "Pearly", streak: "White", hardness: 1 },
{ id: "rock_6", name: "Gypsum (Alabaster)", colors: ["White", "Clear"], luster: "Pearly", streak: "White", hardness: 2 },
{ id: "rock_7", name: "Feldspar (Orthoclase)", colors: ["Pink", "White", "Gray"], luster: "Glassy", streak: "White", hardness: 6 },
{ id: "rock_8", name: "Magnetite", colors: ["Black"], luster: "Metallic", streak: "Black", hardness: 6 },
];
sampleData.forEach((rock) => {
db.rocks[rock.id] = rock;
});
}
loadSampleData();
renderDatabaseTable();
updatePropertyDropdowns();
updateNavButtons(); // Set initial state
} // --- End of initializeRockIdentifier() function ---
/*
* This new logic checks if the page is already loaded (common in Elementor).
* If it is, it runs the setup function immediately.
* If it's still loading (rare), it waits for the DOM event.
*/
if (
document.readyState === "complete" ||
document.readyState === "interactive"
) {
// DOM is already ready, run the function now.
initializeRockIdentifier();
} else {
// Still loading, wait for the event
document.addEventListener(
"DOMContentLoaded",
initializeRockIdentifier
);
}
No matching rocks found in the database for the selected properties.
