diff --git a/iframe.html b/iframe.html
index 0d63585..b370e17 100644
--- a/iframe.html
+++ b/iframe.html
@@ -2171,11 +2171,12 @@ const CALCULATOR_CONFIG = {
// Seed three sources for Kaya's transition
const gc = {
id: this.generateFoodSourceId(),
- name: 'Fred & Felia, gently cooked',
+ name: 'Fred & Felia (Junior Huhn)',
energy: '115',
energyUnit: 'kcal100g',
percentage: 5,
- isLocked: false
+ isLocked: false,
+ chartType: 'gc'
};
this.foodSources.push(gc);
this.renderFoodSource(gc);
@@ -2183,11 +2184,12 @@ const CALCULATOR_CONFIG = {
const kibble = {
id: this.generateFoodSourceId(),
- name: 'Eukanuba, kibble',
+ name: 'Eukanuba (Large Breed Fresh Chicken)',
energy: '372',
energyUnit: 'kcal100g',
percentage: 95,
- isLocked: false
+ isLocked: false,
+ chartType: 'kibble'
};
this.foodSources.push(kibble);
this.renderFoodSource(kibble);
@@ -2199,7 +2201,8 @@ const CALCULATOR_CONFIG = {
energy: '',
energyUnit: 'kcal100g',
percentage: 0,
- isLocked: false
+ isLocked: false,
+ chartType: null
};
this.foodSources.push(treats);
this.renderFoodSource(treats);
@@ -3239,58 +3242,29 @@ const CALCULATOR_CONFIG = {
}
updateCalorieCalculations() {
- // Kaya-specific: compute daily kcal target from age + kibble energy
+ // Kaya-specific: only track age and trigger recompute
const ageInput = document.getElementById('ageMonths');
const ageClampNote = document.getElementById('ageClampNote');
- // Default: hide clamp note
if (ageClampNote) ageClampNote.classList.add('dog-calculator-hidden');
- if (!ageInput || !ageInput.value) {
- this.currentMER = 0;
- this.currentMERMin = 0;
- this.currentMERMax = 0;
+ if (!ageInput || ageInput.value === '') {
+ this.currentAge = null;
+ this.updateFoodCalculations();
return;
}
let age = parseFloat(ageInput.value);
if (isNaN(age)) {
- this.currentMER = 0;
- this.currentMERMin = 0;
- this.currentMERMax = 0;
+ this.currentAge = null;
+ this.updateFoodCalculations();
return;
}
- // Clamp age to [2, 12]
if (age < 2) { age = 2; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
if (age > 12) { age = 12; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
- // Bucket pills removed
-
- // Calculate interpolated kibble grams/day for 30 kg at this age
- const kibbleGrams = this.getKayaKibbleGramsForAge(age);
-
- // Get kibble reference energy density in kcal/100g
- let kibbleEnergyPer100g = null;
- if (this.kibbleRefId) {
- const kibbleRef = this.foodSources.find(fs => fs.id === this.kibbleRefId);
- kibbleEnergyPer100g = kibbleRef ? this.getFoodSourceEnergyPer100g(kibbleRef) : null;
- }
-
- if (!kibbleEnergyPer100g || kibbleEnergyPer100g <= 0) {
- // Cannot compute without kibble energy density
- this.currentMER = 0;
- this.currentMERMin = 0;
- this.currentMERMax = 0;
- return;
- }
-
- const kcalPerGram = kibbleEnergyPer100g / 100.0;
- const dailyKcal = kibbleGrams * kcalPerGram;
- this.currentMER = dailyKcal;
- this.currentMERMin = dailyKcal;
- this.currentMERMax = dailyKcal;
-
+ this.currentAge = age;
this.updateFoodCalculations();
}
@@ -3321,38 +3295,38 @@ const CALCULATOR_CONFIG = {
return lowerVal + (upperVal - lowerVal) * t;
}
-
-
- updateCupsButtonState() {
- const cupsButton = document.getElementById('cupsButton');
- if (!cupsButton) return;
-
- // Check if any food source has kcal/cup selected
- const hasKcalCup = this.foodSources.some(fs =>
- fs.energyUnit === 'kcalcup' && fs.energy && parseFloat(fs.energy) > 0
- );
-
- if (hasKcalCup) {
- cupsButton.disabled = false;
- cupsButton.title = 'Show amounts in cups';
+ // Kaya: GC chart interpolation across buckets
+ getGCChartGramsForAge(ageMonths) {
+ // Buckets per guideline with boundary rule (5.0 → later bucket, 7.0 → later bucket)
+ // <5 mo (2.0–<5.0): 950→1350
+ // 5–6 mo (5.0–6.0): 1250→1550; (6.0–<7.0): hold 1550
+ // 7–12 mo (7.0–12.0): 1300→1500
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
+ const age = clamp(ageMonths, 2, 12);
+ if (age < 5) {
+ const t = (age - 2) / (5 - 2);
+ return 950 + t * (1350 - 950);
+ } else if (age < 6) {
+ const t = (age - 5) / (6 - 5);
+ return 1250 + t * (1550 - 1250);
+ } else if (age < 7) {
+ return 1550; // hold upper value until 7.0
} else {
- cupsButton.disabled = true;
- cupsButton.title = 'Available when using kcal/cup measurement';
-
- // If cups was selected, switch back to grams
- const unitSelect = document.getElementById('unit');
- if (unitSelect && unitSelect.value === 'cups') {
- unitSelect.value = 'g';
- this.setActiveUnitButton('g');
- }
+ const t = (age - 7) / (12 - 7);
+ return 1300 + t * (1500 - 1300);
}
}
+
+
+ updateCupsButtonState() {
+ // Cups UI is not used in this configuration
+ return;
+ }
+
updateFoodCalculations() {
- if (this.currentMER === 0) return;
-
- // Check if we have a range
- const hasRange = this.currentMERMin !== this.currentMERMax;
+ // Chart-first: no MER check
+ const hasRange = false;
const daysInput = document.getElementById('days');
const unitSelect = document.getElementById('unit');
@@ -3415,102 +3389,81 @@ const CALCULATOR_CONFIG = {
}
const numDays = parseInt(days);
-
- // Calculate per-food breakdown
+
+ // Require a valid age for chart-first outputs
+ const ageInput = document.getElementById('ageMonths');
+ let age = ageInput && ageInput.value !== '' ? parseFloat(ageInput.value) : null;
+ if (age !== null) {
+ if (isNaN(age)) age = null;
+ if (age !== null) {
+ if (age < 2) age = 2;
+ if (age > 12) age = 12;
+ }
+ }
+
+ // Calculate per-food breakdown (chart-first)
const foodBreakdowns = [];
let totalDailyGrams = 0;
let hasValidFoods = false;
+ // First pass: charted baseline
+ let chartedKcal = 0;
+ let chartedPercent = 0;
+ const firstPass = [];
this.foodSources.forEach(fs => {
const energyPer100g = this.getFoodSourceEnergyPer100g(fs);
-
- if (energyPer100g && energyPer100g > 0.1 && fs.percentage > 0) {
- const dailyCaloriesForThisFood = (this.currentMER * fs.percentage) / 100;
- // Calculate range values if applicable
- const dailyCaloriesMin = hasRange ? (this.currentMERMin * fs.percentage) / 100 : dailyCaloriesForThisFood;
- const dailyCaloriesMax = hasRange ? (this.currentMERMax * fs.percentage) / 100 : dailyCaloriesForThisFood;
-
- let dailyGramsForThisFood;
- let dailyGramsMin, dailyGramsMax;
- let dailyCupsForThisFood = null;
- let dailyCupsMin, dailyCupsMax;
-
- // For kcal/cup, calculate cups directly from calories
- if (fs.energyUnit === 'kcalcup' && fs.energy) {
- const caloriesPerCup = parseFloat(fs.energy);
- dailyCupsForThisFood = dailyCaloriesForThisFood / caloriesPerCup;
- dailyCupsMin = dailyCaloriesMin / caloriesPerCup;
- dailyCupsMax = dailyCaloriesMax / caloriesPerCup;
- // We still need grams for total calculation, use approximation
- dailyGramsForThisFood = (dailyCaloriesForThisFood / energyPer100g) * 100;
- dailyGramsMin = (dailyCaloriesMin / energyPer100g) * 100;
- dailyGramsMax = (dailyCaloriesMax / energyPer100g) * 100;
- } else {
- // For other units, calculate grams normally
- dailyGramsForThisFood = (dailyCaloriesForThisFood / energyPer100g) * 100;
- dailyGramsMin = (dailyCaloriesMin / energyPer100g) * 100;
- dailyGramsMax = (dailyCaloriesMax / energyPer100g) * 100;
- }
-
- // Calculate per-meal amounts if needed
- const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
- const displayGramsMin = this.showPerMeal ? dailyGramsMin / this.mealsPerDay : dailyGramsMin;
- const displayGramsMax = this.showPerMeal ? dailyGramsMax / this.mealsPerDay : dailyGramsMax;
-
- const displayCups = dailyCupsForThisFood !== null ?
- (this.showPerMeal ? dailyCupsForThisFood / this.mealsPerDay : dailyCupsForThisFood) : null;
- const displayCupsMin = dailyCupsMin !== undefined ?
- (this.showPerMeal ? dailyCupsMin / this.mealsPerDay : dailyCupsMin) : null;
- const displayCupsMax = dailyCupsMax !== undefined ?
- (this.showPerMeal ? dailyCupsMax / this.mealsPerDay : dailyCupsMax) : null;
-
- const displayCalories = this.showPerMeal ? dailyCaloriesForThisFood / this.mealsPerDay : dailyCaloriesForThisFood;
- const displayCaloriesMin = this.showPerMeal ? dailyCaloriesMin / this.mealsPerDay : dailyCaloriesMin;
- const displayCaloriesMax = this.showPerMeal ? dailyCaloriesMax / this.mealsPerDay : dailyCaloriesMax;
-
- foodBreakdowns.push({
- name: fs.name,
- percentage: fs.percentage,
- dailyGrams: dailyGramsForThisFood,
- dailyGramsMin: dailyGramsMin,
- dailyGramsMax: dailyGramsMax,
- displayGrams: displayGrams,
- displayGramsMin: displayGramsMin,
- displayGramsMax: displayGramsMax,
- dailyCups: dailyCupsForThisFood,
- dailyCupsMin: dailyCupsMin,
- dailyCupsMax: dailyCupsMax,
- displayCups: displayCups,
- displayCupsMin: displayCupsMin,
- displayCupsMax: displayCupsMax,
- calories: dailyCaloriesForThisFood,
- displayCalories: displayCalories,
- displayCaloriesMin: displayCaloriesMin,
- displayCaloriesMax: displayCaloriesMax,
- isLocked: fs.isLocked,
- hasEnergyContent: true,
- hasRange: hasRange,
- foodSource: fs // Store reference for cups conversion
- });
-
- totalDailyGrams += dailyGramsForThisFood;
- hasValidFoods = true;
- } else if (fs.percentage > 0) {
- // Include food sources without energy content but show them as needing energy content
- foodBreakdowns.push({
- name: fs.name,
- percentage: fs.percentage,
- dailyGrams: 0,
- displayGrams: 0,
- dailyCups: null,
- displayCups: null,
- calories: 0,
- displayCalories: 0,
- isLocked: fs.isLocked,
- hasEnergyContent: false,
- foodSource: fs // Store reference for cups conversion
- });
+ let chartGrams = null;
+ if (fs.chartType === 'gc') {
+ chartGrams = age !== null ? this.getGCChartGramsForAge(age) : null;
+ } else if (fs.chartType === 'kibble') {
+ chartGrams = age !== null ? this.getKayaKibbleGramsForAge(age) : null;
}
+ const gramsPortion = (chartGrams !== null && chartGrams !== undefined) ? (chartGrams * (fs.percentage || 0) / 100) : null;
+ if (gramsPortion !== null && energyPer100g && energyPer100g > 0) {
+ chartedKcal += gramsPortion * (energyPer100g / 100);
+ chartedPercent += (fs.percentage || 0);
+ }
+ firstPass.push({ fs, energyPer100g, gramsPortion });
+ });
+
+ const kcalPerPercent = chartedPercent > 0 ? (chartedKcal / chartedPercent) : null;
+
+ // Second pass: finalize amounts
+ firstPass.forEach(({ fs, energyPer100g, gramsPortion }) => {
+ let dailyGramsForThisFood = 0;
+ let hasEnergyContent = !!(energyPer100g && energyPer100g > 0);
+ if ((fs.chartType === 'gc' || fs.chartType === 'kibble')) {
+ if (gramsPortion !== null) {
+ dailyGramsForThisFood = gramsPortion;
+ }
+ } else {
+ if (hasEnergyContent && kcalPerPercent && (fs.percentage || 0) > 0) {
+ const perGramKcal = energyPer100g / 100;
+ const kcalForFood = (fs.percentage || 0) * kcalPerPercent;
+ dailyGramsForThisFood = kcalForFood / perGramKcal;
+ } else {
+ hasEnergyContent = false;
+ dailyGramsForThisFood = 0;
+ }
+ }
+
+ const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
+
+ foodBreakdowns.push({
+ name: fs.name,
+ percentage: fs.percentage,
+ dailyGrams: dailyGramsForThisFood,
+ displayGrams: displayGrams,
+ dailyCups: null,
+ displayCups: null,
+ calories: hasEnergyContent ? (dailyGramsForThisFood * (energyPer100g / 100)) : 0,
+ displayCalories: hasEnergyContent ? (this.showPerMeal ? (dailyGramsForThisFood * (energyPer100g / 100)) / this.mealsPerDay : (dailyGramsForThisFood * (energyPer100g / 100))) : 0,
+ isLocked: fs.isLocked,
+ hasEnergyContent: hasEnergyContent,
+ foodSource: fs
+ });
+ totalDailyGrams += dailyGramsForThisFood;
+ if (dailyGramsForThisFood > 0) hasValidFoods = true;
});
if (!hasValidFoods) {
diff --git a/src/js/calculator.js b/src/js/calculator.js
index 40e1fe6..b6f6f31 100644
--- a/src/js/calculator.js
+++ b/src/js/calculator.js
@@ -75,11 +75,12 @@
// Seed three sources for Kaya's transition
const gc = {
id: this.generateFoodSourceId(),
- name: 'Fred & Felia, gently cooked',
+ name: 'Fred & Felia (Junior Huhn)',
energy: '115',
energyUnit: 'kcal100g',
percentage: 5,
- isLocked: false
+ isLocked: false,
+ chartType: 'gc'
};
this.foodSources.push(gc);
this.renderFoodSource(gc);
@@ -87,11 +88,12 @@
const kibble = {
id: this.generateFoodSourceId(),
- name: 'Eukanuba, kibble',
+ name: 'Eukanuba (Large Breed Fresh Chicken)',
energy: '372',
energyUnit: 'kcal100g',
percentage: 95,
- isLocked: false
+ isLocked: false,
+ chartType: 'kibble'
};
this.foodSources.push(kibble);
this.renderFoodSource(kibble);
@@ -103,7 +105,8 @@
energy: '',
energyUnit: 'kcal100g',
percentage: 0,
- isLocked: false
+ isLocked: false,
+ chartType: null
};
this.foodSources.push(treats);
this.renderFoodSource(treats);
@@ -1143,58 +1146,29 @@
}
updateCalorieCalculations() {
- // Kaya-specific: compute daily kcal target from age + kibble energy
+ // Kaya-specific: only track age and trigger recompute
const ageInput = document.getElementById('ageMonths');
const ageClampNote = document.getElementById('ageClampNote');
- // Default: hide clamp note
if (ageClampNote) ageClampNote.classList.add('dog-calculator-hidden');
- if (!ageInput || !ageInput.value) {
- this.currentMER = 0;
- this.currentMERMin = 0;
- this.currentMERMax = 0;
+ if (!ageInput || ageInput.value === '') {
+ this.currentAge = null;
+ this.updateFoodCalculations();
return;
}
let age = parseFloat(ageInput.value);
if (isNaN(age)) {
- this.currentMER = 0;
- this.currentMERMin = 0;
- this.currentMERMax = 0;
+ this.currentAge = null;
+ this.updateFoodCalculations();
return;
}
- // Clamp age to [2, 12]
if (age < 2) { age = 2; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
if (age > 12) { age = 12; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
- // Bucket pills removed
-
- // Calculate interpolated kibble grams/day for 30 kg at this age
- const kibbleGrams = this.getKayaKibbleGramsForAge(age);
-
- // Get kibble reference energy density in kcal/100g
- let kibbleEnergyPer100g = null;
- if (this.kibbleRefId) {
- const kibbleRef = this.foodSources.find(fs => fs.id === this.kibbleRefId);
- kibbleEnergyPer100g = kibbleRef ? this.getFoodSourceEnergyPer100g(kibbleRef) : null;
- }
-
- if (!kibbleEnergyPer100g || kibbleEnergyPer100g <= 0) {
- // Cannot compute without kibble energy density
- this.currentMER = 0;
- this.currentMERMin = 0;
- this.currentMERMax = 0;
- return;
- }
-
- const kcalPerGram = kibbleEnergyPer100g / 100.0;
- const dailyKcal = kibbleGrams * kcalPerGram;
- this.currentMER = dailyKcal;
- this.currentMERMin = dailyKcal;
- this.currentMERMax = dailyKcal;
-
+ this.currentAge = age;
this.updateFoodCalculations();
}
@@ -1225,38 +1199,38 @@
return lowerVal + (upperVal - lowerVal) * t;
}
-
-
- updateCupsButtonState() {
- const cupsButton = document.getElementById('cupsButton');
- if (!cupsButton) return;
-
- // Check if any food source has kcal/cup selected
- const hasKcalCup = this.foodSources.some(fs =>
- fs.energyUnit === 'kcalcup' && fs.energy && parseFloat(fs.energy) > 0
- );
-
- if (hasKcalCup) {
- cupsButton.disabled = false;
- cupsButton.title = 'Show amounts in cups';
+ // Kaya: GC chart interpolation across buckets
+ getGCChartGramsForAge(ageMonths) {
+ // Buckets per guideline with boundary rule (5.0 → later bucket, 7.0 → later bucket)
+ // <5 mo (2.0–<5.0): 950→1350
+ // 5–6 mo (5.0–6.0): 1250→1550; (6.0–<7.0): hold 1550
+ // 7–12 mo (7.0–12.0): 1300→1500
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
+ const age = clamp(ageMonths, 2, 12);
+ if (age < 5) {
+ const t = (age - 2) / (5 - 2);
+ return 950 + t * (1350 - 950);
+ } else if (age < 6) {
+ const t = (age - 5) / (6 - 5);
+ return 1250 + t * (1550 - 1250);
+ } else if (age < 7) {
+ return 1550; // hold upper value until 7.0
} else {
- cupsButton.disabled = true;
- cupsButton.title = 'Available when using kcal/cup measurement';
-
- // If cups was selected, switch back to grams
- const unitSelect = document.getElementById('unit');
- if (unitSelect && unitSelect.value === 'cups') {
- unitSelect.value = 'g';
- this.setActiveUnitButton('g');
- }
+ const t = (age - 7) / (12 - 7);
+ return 1300 + t * (1500 - 1300);
}
}
+
+
+ updateCupsButtonState() {
+ // Cups UI is not used in this configuration
+ return;
+ }
+
updateFoodCalculations() {
- if (this.currentMER === 0) return;
-
- // Check if we have a range
- const hasRange = this.currentMERMin !== this.currentMERMax;
+ // Chart-first: no MER check
+ const hasRange = false;
const daysInput = document.getElementById('days');
const unitSelect = document.getElementById('unit');
@@ -1319,102 +1293,81 @@
}
const numDays = parseInt(days);
-
- // Calculate per-food breakdown
+
+ // Require a valid age for chart-first outputs
+ const ageInput = document.getElementById('ageMonths');
+ let age = ageInput && ageInput.value !== '' ? parseFloat(ageInput.value) : null;
+ if (age !== null) {
+ if (isNaN(age)) age = null;
+ if (age !== null) {
+ if (age < 2) age = 2;
+ if (age > 12) age = 12;
+ }
+ }
+
+ // Calculate per-food breakdown (chart-first)
const foodBreakdowns = [];
let totalDailyGrams = 0;
let hasValidFoods = false;
+ // First pass: charted baseline
+ let chartedKcal = 0;
+ let chartedPercent = 0;
+ const firstPass = [];
this.foodSources.forEach(fs => {
const energyPer100g = this.getFoodSourceEnergyPer100g(fs);
-
- if (energyPer100g && energyPer100g > 0.1 && fs.percentage > 0) {
- const dailyCaloriesForThisFood = (this.currentMER * fs.percentage) / 100;
- // Calculate range values if applicable
- const dailyCaloriesMin = hasRange ? (this.currentMERMin * fs.percentage) / 100 : dailyCaloriesForThisFood;
- const dailyCaloriesMax = hasRange ? (this.currentMERMax * fs.percentage) / 100 : dailyCaloriesForThisFood;
-
- let dailyGramsForThisFood;
- let dailyGramsMin, dailyGramsMax;
- let dailyCupsForThisFood = null;
- let dailyCupsMin, dailyCupsMax;
-
- // For kcal/cup, calculate cups directly from calories
- if (fs.energyUnit === 'kcalcup' && fs.energy) {
- const caloriesPerCup = parseFloat(fs.energy);
- dailyCupsForThisFood = dailyCaloriesForThisFood / caloriesPerCup;
- dailyCupsMin = dailyCaloriesMin / caloriesPerCup;
- dailyCupsMax = dailyCaloriesMax / caloriesPerCup;
- // We still need grams for total calculation, use approximation
- dailyGramsForThisFood = (dailyCaloriesForThisFood / energyPer100g) * 100;
- dailyGramsMin = (dailyCaloriesMin / energyPer100g) * 100;
- dailyGramsMax = (dailyCaloriesMax / energyPer100g) * 100;
- } else {
- // For other units, calculate grams normally
- dailyGramsForThisFood = (dailyCaloriesForThisFood / energyPer100g) * 100;
- dailyGramsMin = (dailyCaloriesMin / energyPer100g) * 100;
- dailyGramsMax = (dailyCaloriesMax / energyPer100g) * 100;
- }
-
- // Calculate per-meal amounts if needed
- const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
- const displayGramsMin = this.showPerMeal ? dailyGramsMin / this.mealsPerDay : dailyGramsMin;
- const displayGramsMax = this.showPerMeal ? dailyGramsMax / this.mealsPerDay : dailyGramsMax;
-
- const displayCups = dailyCupsForThisFood !== null ?
- (this.showPerMeal ? dailyCupsForThisFood / this.mealsPerDay : dailyCupsForThisFood) : null;
- const displayCupsMin = dailyCupsMin !== undefined ?
- (this.showPerMeal ? dailyCupsMin / this.mealsPerDay : dailyCupsMin) : null;
- const displayCupsMax = dailyCupsMax !== undefined ?
- (this.showPerMeal ? dailyCupsMax / this.mealsPerDay : dailyCupsMax) : null;
-
- const displayCalories = this.showPerMeal ? dailyCaloriesForThisFood / this.mealsPerDay : dailyCaloriesForThisFood;
- const displayCaloriesMin = this.showPerMeal ? dailyCaloriesMin / this.mealsPerDay : dailyCaloriesMin;
- const displayCaloriesMax = this.showPerMeal ? dailyCaloriesMax / this.mealsPerDay : dailyCaloriesMax;
-
- foodBreakdowns.push({
- name: fs.name,
- percentage: fs.percentage,
- dailyGrams: dailyGramsForThisFood,
- dailyGramsMin: dailyGramsMin,
- dailyGramsMax: dailyGramsMax,
- displayGrams: displayGrams,
- displayGramsMin: displayGramsMin,
- displayGramsMax: displayGramsMax,
- dailyCups: dailyCupsForThisFood,
- dailyCupsMin: dailyCupsMin,
- dailyCupsMax: dailyCupsMax,
- displayCups: displayCups,
- displayCupsMin: displayCupsMin,
- displayCupsMax: displayCupsMax,
- calories: dailyCaloriesForThisFood,
- displayCalories: displayCalories,
- displayCaloriesMin: displayCaloriesMin,
- displayCaloriesMax: displayCaloriesMax,
- isLocked: fs.isLocked,
- hasEnergyContent: true,
- hasRange: hasRange,
- foodSource: fs // Store reference for cups conversion
- });
-
- totalDailyGrams += dailyGramsForThisFood;
- hasValidFoods = true;
- } else if (fs.percentage > 0) {
- // Include food sources without energy content but show them as needing energy content
- foodBreakdowns.push({
- name: fs.name,
- percentage: fs.percentage,
- dailyGrams: 0,
- displayGrams: 0,
- dailyCups: null,
- displayCups: null,
- calories: 0,
- displayCalories: 0,
- isLocked: fs.isLocked,
- hasEnergyContent: false,
- foodSource: fs // Store reference for cups conversion
- });
+ let chartGrams = null;
+ if (fs.chartType === 'gc') {
+ chartGrams = age !== null ? this.getGCChartGramsForAge(age) : null;
+ } else if (fs.chartType === 'kibble') {
+ chartGrams = age !== null ? this.getKayaKibbleGramsForAge(age) : null;
}
+ const gramsPortion = (chartGrams !== null && chartGrams !== undefined) ? (chartGrams * (fs.percentage || 0) / 100) : null;
+ if (gramsPortion !== null && energyPer100g && energyPer100g > 0) {
+ chartedKcal += gramsPortion * (energyPer100g / 100);
+ chartedPercent += (fs.percentage || 0);
+ }
+ firstPass.push({ fs, energyPer100g, gramsPortion });
+ });
+
+ const kcalPerPercent = chartedPercent > 0 ? (chartedKcal / chartedPercent) : null;
+
+ // Second pass: finalize amounts
+ firstPass.forEach(({ fs, energyPer100g, gramsPortion }) => {
+ let dailyGramsForThisFood = 0;
+ let hasEnergyContent = !!(energyPer100g && energyPer100g > 0);
+ if ((fs.chartType === 'gc' || fs.chartType === 'kibble')) {
+ if (gramsPortion !== null) {
+ dailyGramsForThisFood = gramsPortion;
+ }
+ } else {
+ if (hasEnergyContent && kcalPerPercent && (fs.percentage || 0) > 0) {
+ const perGramKcal = energyPer100g / 100;
+ const kcalForFood = (fs.percentage || 0) * kcalPerPercent;
+ dailyGramsForThisFood = kcalForFood / perGramKcal;
+ } else {
+ hasEnergyContent = false;
+ dailyGramsForThisFood = 0;
+ }
+ }
+
+ const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
+
+ foodBreakdowns.push({
+ name: fs.name,
+ percentage: fs.percentage,
+ dailyGrams: dailyGramsForThisFood,
+ displayGrams: displayGrams,
+ dailyCups: null,
+ displayCups: null,
+ calories: hasEnergyContent ? (dailyGramsForThisFood * (energyPer100g / 100)) : 0,
+ displayCalories: hasEnergyContent ? (this.showPerMeal ? (dailyGramsForThisFood * (energyPer100g / 100)) / this.mealsPerDay : (dailyGramsForThisFood * (energyPer100g / 100))) : 0,
+ isLocked: fs.isLocked,
+ hasEnergyContent: hasEnergyContent,
+ foodSource: fs
+ });
+ totalDailyGrams += dailyGramsForThisFood;
+ if (dailyGramsForThisFood > 0) hasValidFoods = true;
});
if (!hasValidFoods) {