Tree Identification Guide

Tree Identification Guide

Follow the Guide

Answer the questions to identify your tree.

Tree Identification Wizard

Click "Start" to begin the identification process.

Identification Result

Please complete the guide on the "Identification Guide" tab to see your result.

Data Configuration

Manage the guide's questions and final tree identifications.

Manage Trees (Final Results)

IDNameActions

Manage Questions (Wizard Logic)

The "Link ID" must match a Unique ID from the Trees or Questions tables.
IDQuestion TextActions

Key Features:

${featuresHtml} `; // Auto-navigate to result tab (Spec II.B.4.o) tig_showTab(1); } /** * Handles the PDF download request. */ function tig_downloadPDF() { const element = tig_container.querySelector('#tig-result-pdf-output'); // Check if there is a result to download if (element.querySelector('.tig-no-results')) { alert("No result to download. Please complete the identification guide first."); return; } // Clone the element to style it for PDF const elementToPrint = element.cloneNode(true); const pdfContainer = document.createElement('div'); const pdfTitle = document.createElement('h1'); pdfTitle.textContent = 'Tree Identification Result'; pdfTitle.style.textAlign = 'center'; pdfTitle.style.color = '#2c3e50'; pdfTitle.style.fontSize = '24px'; pdfTitle.style.marginBottom = '20px'; pdfContainer.appendChild(pdfTitle); pdfContainer.appendChild(elementToPrint); pdfContainer.style.padding = '20px'; pdfContainer.style.fontFamily = 'Arial, sans-serif'; // Apply styles directly to the clone for PDF consistency elementToPrint.style.color = '#333'; elementToPrint.style.border = 'none'; elementToPrint.style.backgroundColor = '#fff'; elementToPrint.style.padding = '0'; elementToPrint.querySelectorAll('h2').forEach(h2 => { h2.style.color = '#3498db'; h2.style.textAlign = 'center'; }); elementToPrint.querySelectorAll('p').forEach(p => { p.style.textAlign = 'center'; p.style.fontSize = '14px'; }); elementToPrint.querySelectorAll('h3').forEach(h3 => { h3.style.color = '#34495e'; h3.style.textAlign = 'left'; h3.style.borderBottom = '1px solid #ccc'; }); elementToPrint.querySelectorAll('ul').forEach(ul => { ul.style.marginLeft = '20px'; }); const options = { margin: 1, // in filename: 'tree_identification_result.pdf', image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2 }, jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' } }; if (typeof html2pdf === 'function') { html2pdf().from(pdfContainer).set(options).save(); } else { console.error("TIG Tool: html2pdf.js library is not loaded."); alert("Error: PDF generation library is missing."); } } // --- TAB 3 (CONFIG) FUNCTIONS --- // --- Tree Management --- function tig_renderTreeTable() { if (!tig_treeTableBody) return; tig_treeTableBody.innerHTML = ''; tig_trees.forEach(tree => { const row = document.createElement('tr'); row.innerHTML = ` ${tree.id} ${tree.name} `; tig_treeTableBody.appendChild(row); }); } function tig_handleTreeFormSubmit(e) { e.preventDefault(); if (!tig_treeId || !tig_treeName || !tig_treeDesc || !tig_treeFeatures) return; const id = tig_treeId.value.trim(); if (!id) { alert("Unique ID is required."); return; } // Check for duplicate ID const idExists = tig_trees.some(t => t.id === id) || tig_questions.some(q => q.id === id); if (idExists && id !== tig_editingTreeId) { alert("Error: This Unique ID is already in use by another tree or question. Please choose a different one."); return; } const treeData = { id: id, name: tig_treeName.value.trim(), desc: tig_treeDesc.value.trim(), features: tig_treeFeatures.value.trim().split('\n').filter(f => f) }; if (tig_editingTreeId) { tig_trees = tig_trees.map(t => t.id === tig_editingTreeId ? treeData : t); } else { tig_trees.push(treeData); } tig_renderTreeTable(); tig_resetTreeForm(); } window.tig_editTree = function(id) { const tree = tig_trees.find(t => t.id === id); if (!tree) return; if (!tig_treeEditId || !tig_treeId || !tig_treeName || !tig_treeDesc || !tig_treeFeatures || !tig_treeCancelBtn) return; tig_editingTreeId = id; tig_treeEditId.value = id; tig_treeId.value = tree.id; tig_treeId.disabled = true; // Don't allow editing ID tig_treeName.value = tree.name; tig_treeDesc.value = tree.desc; tig_treeFeatures.value = tree.features.join('\n'); tig_treeCancelBtn.classList.remove('tig-hidden'); } function tig_resetTreeForm() { if (!tig_treeForm || !tig_treeCancelBtn || !tig_treeId) return; tig_editingTreeId = null; tig_treeForm.reset(); tig_treeId.disabled = false; tig_treeCancelBtn.classList.add('tig-hidden'); } window.tig_deleteTree = function(id) { if (confirm(`Are you sure you want to delete the tree "${id}"? This could break the guide logic if any question links to it.`)) { tig_trees = tig_trees.filter(t => t.id !== id); tig_renderTreeTable(); tig_resetGuide(); // Reset guide in case data changed } } // --- Question Management --- function tig_renderQuestionTable() { if (!tig_questionTableBody) return; tig_questionTableBody.innerHTML = ''; tig_questions.forEach(q => { const row = document.createElement('tr'); row.innerHTML = ` ${q.id} ${q.text} `; tig_questionTableBody.appendChild(row); }); } function tig_handleQuestionFormSubmit(e) { e.preventDefault(); if (!tig_questionId || !tig_questionTextEl || !tig_questionAnswers) return; const id = tig_questionId.value.trim(); if (!id) { alert("Unique ID is required."); return; } // Check for duplicate ID const idExists = tig_trees.some(t => t.id === id) || tig_questions.some(q => q.id === id); if (idExists && id !== tig_editingQuestionId) { alert("Error: This Unique ID is already in use by another tree or question. Please choose a different one."); return; } // Parse answers (Manual Input format: Text|LinkID) const answerLines = tig_questionAnswers.value.trim().split('\n'); const answers = answerLines.map(line => { const parts = line.split('|'); if (parts.length !== 2) return null; return { text: parts[0].trim(), next: parts[1].trim() }; }).filter(a => a && a.text && a.next); if (answers.length === 0) { alert("Please provide at least one valid answer in the format 'Answer Text|Link ID'."); return; } const questionData = { id: id, text: tig_questionTextEl.value.trim(), answers: answers }; if (tig_editingQuestionId) { tig_questions = tig_questions.map(q => q.id === tig_editingQuestionId ? questionData : q); } else { tig_questions.push(questionData); } tig_renderQuestionTable(); tig_resetQuestionForm(); tig_resetGuide(); // Reset guide as logic may have changed } window.tig_editQuestion = function(id) { const q = tig_questions.find(q => q.id === id); if (!q) return; if (!tig_questionEditId || !tig_questionId || !tig_questionTextEl || !tig_questionAnswers || !tig_questionCancelBtn) return; tig_editingQuestionId = id; tig_questionEditId.value = id; tig_questionId.value = q.id; tig_questionId.disabled = true; tig_questionTextEl.value = q.text; // Re-format answers array back into string for textarea tig_questionAnswers.value = q.answers.map(a => `${a.text}|${a.next}`).join('\n'); tig_questionCancelBtn.classList.remove('tig-hidden'); } function tig_resetQuestionForm() { if (!tig_questionForm || !tig_questionCancelBtn || !tig_questionId) return; tig_editingQuestionId = null; tig_questionForm.reset(); tig_questionId.disabled = false; tig_questionCancelBtn.classList.add('tig-hidden'); } window.tig_deleteQuestion = function(id) { if (id === TIG_START_NODE_ID) { alert(`Cannot delete the starting question ("${TIG_START_NODE_ID}").`); return; } if (confirm(`Are you sure you want to delete the question "${id}"? This could break the guide logic if any other question links to it.`)) { tig_questions = tig_questions.filter(q => q.id !== id); tig_renderQuestionTable(); tig_resetGuide(); // Reset guide in case data changed } } // --- IV. INITIALIZE THE TOOL --- tig_init(); }); // End of DOMContentLoaded