Rock and Mineral Identifier

Rock and Mineral Identifier

1. Select Properties

2. Identification Results

Please select properties above and click "Identify".

Add New Rock/Mineral

Current Database

Name Colors Luster Streak Hardness Action

Colors: ${escapeHTML(rock.colors.join(", "))}

Luster: ${escapeHTML(rock.luster)}

Streak: ${escapeHTML(rock.streak)}

Hardness: ${rock.hardness} (Mohs)

`; } else { resultsArea.innerHTML = '

No matching rocks found in the database for the selected properties.

'; } }); } // --- 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 ); }