Animal Growth Rate Calculator & Visualizer
Please select an animal to begin.
';
if (growthChart) growthChart.destroy();
dataTable.innerHTML = '';
return;
}
renderMetrics();
renderChart();
renderDataTable();
}
function renderMetrics() {
const selectedAnimals = getSelectedAnimals();
const unit = getCurrentUnit();
metricsContainer.innerHTML = selectedAnimals.map(animalName => {
const animal = growthData[animalName];
const data = animal.data;
if (data.length < 2) return '';
const start = data[0];
const end = data[data.length - 1];
const weightGain = end.weightKg - start.weightKg;
const timeSpan = end.age - start.age;
const daysInUnit = animal.timeUnit === 'Weeks' ? 7 : 30.4;
const adg = weightGain / (timeSpan * daysInUnit);
return `
${animalName} - ADG
${convertWeight(adg, unit).toFixed(3)} ${unit}/day
`;
}).join('');
}
function renderChart() {
const selectedAnimals = getSelectedAnimals();
const unit = getCurrentUnit();
const ctx = document.getElementById('growth-chart').getContext('2d');
const chartColors = ['#65a30d', '#f97316', '#2563eb', '#dc2626'];
const datasets = selectedAnimals.map((animalName, index) => {
const animal = growthData[animalName];
return {
label: `${animalName} (${unit})`,
data: animal.data.map(p => ({ x: p.age, y: convertWeight(p.weightKg, unit) })),
borderColor: chartColors[index % chartColors.length],
backgroundColor: chartColors[index % chartColors.length],
tension: 0.1,
fill: false
};
});
// Determine a common time unit for the x-axis label
const commonTimeUnit = selectedAnimals.length > 0 ? growthData[selectedAnimals[0]].timeUnit : 'Time';
if (growthChart) {
growthChart.destroy();
}
growthChart = new Chart(ctx, {
type: 'line',
data: { datasets },
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
type: 'linear',
title: { display: true, text: `Age in ${commonTimeUnit}` },
beginAtZero: true
},
y: {
title: { display: true, text: `Weight (${unit})` },
beginAtZero: true
}
}
}
});
}
function renderDataTable() {
const selectedAnimals = getSelectedAnimals();
const unit = getCurrentUnit();
if (selectedAnimals.length === 0) {
dataTable.innerHTML = '';
return;
}
// Unify data points by age
const allAges = new Set();
selectedAnimals.forEach(name => growthData[name].data.forEach(p => allAges.add(p.age)));
const sortedAges = Array.from(allAges).sort((a, b) => a - b);
const headerTimeUnit = growthData[selectedAnimals[0]].timeUnit;
let tableHTML = `
| Age (${headerTimeUnit}) |
${selectedAnimals.map(name => `${name} (${unit}) | `).join('')}
`;
sortedAges.forEach(age => {
tableHTML += `| ${age} | `;
selectedAnimals.forEach(name => {
const dataPoint = growthData[name].data.find(p => p.age === age);
const value = dataPoint ? convertWeight(dataPoint.weightKg, unit).toFixed(2) : 'N/A';
const editable = dataPoint ? `contenteditable="true" onblur="agr_updateDataPoint('${name}', ${age}, this.innerText)"` : '';
tableHTML += `${value} | `;
});
tableHTML += `
`;
});
tableHTML += ``;
dataTable.innerHTML = tableHTML;
}
window.agr_updateDataPoint = (animalName, age, newValue) => {
const unit = getCurrentUnit();
const numericValue = parseFloat(newValue);
if (isNaN(numericValue)) {
renderAll(); // Revert if input is not a number
return;
}
const weightInKg = unit === 'lbs' ? numericValue / KG_TO_LBS : numericValue;
const dataPoint = growthData[animalName].data.find(p => p.age === age);
if (dataPoint) {
dataPoint.weightKg = weightInKg;
}
renderAll(); // Re-render everything to reflect the change
};
// --- EVENT LISTENERS & INITIALIZATION ---
function initialize() {
animalSelect.innerHTML = Object.keys(growthData).map(name => `
`).join('');
animalSelect.addEventListener('change', renderAll);
unitSelect.addEventListener('change', renderAll);
const downloadBtn = document.getElementById('agr-download-pdf-btn');
if(downloadBtn) {
downloadBtn.addEventListener('click', () => {
const visualizer = document.getElementById('agr-tab-0');
if (!visualizer) return;
html2canvas(visualizer, { scale: 2, useCORS: true }).then(canvas => {
const { jsPDF } = window.jspdf;
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'l', unit: 'mm', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const ratio = canvas.width / canvas.height;
let imgWidth = pdfWidth - 20;
let imgHeight = imgWidth / ratio;
if (imgHeight > pdfHeight - 20) {
imgHeight = pdfHeight - 20;
imgWidth = imgHeight * ratio;
}
pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight);
pdf.save('Animal-Growth-Visualizer.pdf');
});
});
}
renderAll();
}
initialize();
});