Food Chain Diagram Generator

Food Chain Diagram Generator

Generated Food Chain

Your food chain will appear here. Add an organism to start.

Manage Organism Database

Organism database is empty.

'; } } function renderOrganismDropdown() { if (!fcdgSelectOrganism) return; fcdgSelectOrganism.innerHTML = ''; let hasData = false; Object.keys(fcdgTypeLabels).forEach(type => { const label = fcdgTypeLabels[type]; const organisms = fcdgOrganismData[type]; if (organisms.length > 0) { hasData = true; const optgroup = document.createElement('optgroup'); optgroup.label = label; organisms.forEach(org => { const option = document.createElement('option'); option.value = `${type}|${org.id}|${org.name}`; option.textContent = org.name; optgroup.appendChild(option); }); fcdgSelectOrganism.appendChild(optgroup); } }); if (!hasData) { fcdgSelectOrganism.innerHTML = ''; } } function renderFoodChainDiagram() { if (!fcdgDiagramOutput || !fcdgEmptyMsg) return; fcdgDiagramOutput.innerHTML = ''; if (fcdgCurrentChain.length === 0) { fcdgDiagramOutput.appendChild(fcdgEmptyMsg); } else { fcdgCurrentChain.forEach((org, index) => { // Add arrow if (index > 0) { const arrow = document.createElement('span'); arrow.className = 'fcdg-arrow'; arrow.innerHTML = '→'; fcdgDiagramOutput.appendChild(arrow); } // Add node const node = document.createElement('div'); node.className = `fcdg-node fcdg-type-${org.type}`; node.innerHTML = `
${org.name}
${fcdgTypeLabels[org.type]}
`; fcdgDiagramOutput.appendChild(node); }); } } // --- Event Handlers --- function handleAddOrganismToDB(e) { e.preventDefault(); const name = fcdgNewNameInput.value.trim(); const type = fcdgNewTypeSelect.value; if (name && type) { fcdgOrganismData[type].push({ id: fcdgNextOrganismId++, name: name }); renderOrganismDatabase(); renderOrganismDropdown(); fcdgNewNameInput.value = ''; } } function handleDeleteOrganismFromDB(e) { if (e.target.matches('.fcdg-delete-btn')) { const id = parseInt(e.target.dataset.id, 10); const type = e.target.dataset.type; if (id && type && fcdgOrganismData[type]) { fcdgOrganismData[type] = fcdgOrganismData[type].filter(org => org.id !== id); renderOrganismDatabase(); renderOrganismDropdown(); } } } function addOrganismToChain() { const selected = fcdgSelectOrganism.value; if (!selected) return; const [type, id, name] = selected.split('|'); if (type && id && name) { fcdgCurrentChain.push({ id: parseInt(id, 10), name: name, type: type }); renderFoodChainDiagram(); } } function removeLastFromChain() { fcdgCurrentChain.pop(); renderFoodChainDiagram(); } function clearChain() { fcdgCurrentChain = []; renderFoodChainDiagram(); } /** * Generates and downloads a PDF of the food chain diagram. */ async function downloadPDF() { if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') { console.error("jsPDF or html2canvas library not loaded."); alert("Error: PDF generation libraries not loaded."); return; } const { jsPDF } = window.jspdf; fcdgPdfBtn.textContent = 'Generating...'; fcdgPdfBtn.disabled = true; const contentToExport = document.getElementById('fcdg-pdf-content'); if (!contentToExport) { console.error("PDF content area not found."); fcdgPdfBtn.textContent = 'Download Diagram as PDF'; fcdgPdfBtn.disabled = false; return; } // Add a class to hide the empty message in the PDF if (fcdgEmptyMsg) fcdgEmptyMsg.classList.add('fcdg-pdf-hide'); try { const canvas = await html2canvas(contentToExport, { scale: 2, useCORS: true, logging: false, backgroundColor: '#ffffff' // Ensure white background }); const imgData = canvas.toDataURL('image/png'); // Use PDF dimensions that respect the canvas aspect ratio const pdf = new jsPDF({ orientation: 'l', // Landscape unit: 'px', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const canvasWidth = canvas.width; const canvasHeight = canvas.height; // Calculate ratio to fit const ratio = Math.min(pdfWidth / canvasWidth, pdfHeight / canvasHeight); const imgWidth = canvasWidth * ratio; const imgHeight = canvasHeight * ratio; // Center image const x = (pdfWidth - imgWidth) / 2; const y = (pdfHeight - imgHeight) / 2; pdf.addImage(imgData, 'PNG', x, y, imgWidth, imgHeight); pdf.save('food_chain_diagram.pdf'); } catch (error) { console.error("Error during PDF generation:", error); alert("An error occurred while generating the PDF."); } finally { if (fcdgEmptyMsg) fcdgEmptyMsg.classList.remove('fcdg-pdf-hide'); fcdgPdfBtn.textContent = 'Download Diagram as PDF'; fcdgPdfBtn.disabled = false; } } // --- Tab Navigation Functions --- window.fcdgOpenTab = function(evt, tabName) { if (!fcdgTabContents.length || !fcdgTabLinks.length) return; fcdgTabContents.forEach(tabcontent => { tabcontent.style.display = "none"; tabcontent.classList.remove('fcdg-active'); }); fcdgTabLinks.forEach(tablink => { tablink.classList.remove('fcdg-active'); }); const currentTabContent = document.getElementById(tabName); if (currentTabContent) { currentTabContent.style.display = "block"; currentTabContent.classList.add('fcdg-active'); } if (evt && evt.currentTarget) { evt.currentTarget.classList.add('fcdg-active'); } fcdgCurrentTab = fcdgTabLinks.indexOf(evt.currentTarget); updateNavButtons(); } window.fcdgNavTab = function(n) { const newIndex = fcdgCurrentTab + n; if (newIndex >= 0 && newIndex < fcdgTabLinks.length) { fcdgTabLinks[newIndex].click(); } } function updateNavButtons() { if (fcdgPrevBtn) fcdgPrevBtn.disabled = (fcdgCurrentTab === 0); if (fcdgNextBtn) fcdgNextBtn.disabled = (fcdgCurrentTab === fcdgTabLinks.length - 1); } })();
Scroll to Top