diff --git a/iframe.html b/iframe.html
index 983d804..2db4ceb 100644
--- a/iframe.html
+++ b/iframe.html
@@ -32,7 +32,7 @@
}
.dog-calculator-container {
- max-width: 600px;
+ max-width: 640px;
margin: 0 auto;
padding: 24px;
box-sizing: border-box;
@@ -213,6 +213,7 @@
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
+ gap: 10px; /* Add gap between label and value */
}
.dog-calculator-result-item:last-child {
@@ -232,6 +233,7 @@
padding: 4px 12px;
background: rgba(241, 154, 95, 0.15);
border-radius: 4px;
+ white-space: nowrap; /* Prevent text from wrapping to multiple lines */
}
.dog-calculator-collapsible {
@@ -543,6 +545,24 @@
flex-direction: column;
align-items: flex-start;
}
+
+ /* Stack result items vertically on small screens */
+ .dog-calculator-result-item {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 8px;
+ }
+
+ .dog-calculator-result-label {
+ margin-right: 0;
+ font-size: 0.9rem;
+ }
+
+ .dog-calculator-result-value {
+ font-size: 1rem;
+ align-self: stretch;
+ text-align: center;
+ }
}
/* Dark theme - manual override */
@@ -2288,6 +2308,8 @@ const CALCULATOR_CONFIG = {
class DogCalorieCalculator {
constructor() {
this.currentMER = 0;
+ this.currentMERMin = 0; // For range calculations
+ this.currentMERMax = 0; // For range calculations
this.isImperial = false;
this.theme = this.getThemeFromURL() || CALCULATOR_CONFIG.defaultTheme;
this.scale = this.getScaleFromURL() || CALCULATOR_CONFIG.defaultScale;
@@ -3335,6 +3357,25 @@ const CALCULATOR_CONFIG = {
return rer * factor;
}
+ // Get the range multipliers for each life stage
+ getLifeStageRange(factor) {
+ // Define ranges based on the reference image
+ const ranges = {
+ '3.0': { min: 3.0, max: 3.0 }, // Puppy 0-4 months (no range)
+ '2.0': { min: 2.0, max: 2.0 }, // Puppy 4m-adult OR Working light (no range for puppies)
+ '1.2': { min: 1.2, max: 1.4 }, // Adult inactive/obese
+ '1.6': { min: 1.4, max: 1.6 }, // Adult neutered/spayed
+ '1.8': { min: 1.6, max: 1.8 }, // Adult intact
+ '1.0': { min: 1.0, max: 1.0 }, // Weight loss (fixed)
+ '1.7': { min: 1.2, max: 1.8 }, // Weight gain (wide range)
+ '5.0': { min: 5.0, max: 5.0 }, // Working heavy (upper bound)
+ '1.1': { min: 1.1, max: 1.1 } // Senior (no range)
+ };
+
+ const key = factor.toFixed(1);
+ return ranges[key] || { min: factor, max: factor };
+ }
+
validateInput(value, min = 0, isInteger = false) {
const num = parseFloat(value);
if (isNaN(num) || num < min) return false;
@@ -3466,10 +3507,21 @@ const CALCULATOR_CONFIG = {
const rer = this.calculateRER(weightKg);
const mer = this.calculateMER(rer, factor);
- this.currentMER = mer;
+ // Calculate range for MER
+ const range = this.getLifeStageRange(factor);
+ this.currentMERMin = this.calculateMER(rer, range.min);
+ this.currentMERMax = this.calculateMER(rer, range.max);
+ this.currentMER = mer; // Keep middle/selected value for compatibility
rerValue.textContent = this.formatNumber(rer, 0) + ' cal/day';
- merValue.textContent = this.formatNumber(mer, 0) + ' cal/day';
+
+ // Show MER as range if applicable
+ if (range.min !== range.max) {
+ merValue.textContent = this.formatNumber(this.currentMERMin, 0) + '-' +
+ this.formatNumber(this.currentMERMax, 0) + ' cal/day';
+ } else {
+ merValue.textContent = this.formatNumber(mer, 0) + ' cal/day';
+ }
calorieResults.style.display = 'block';
this.updateFoodCalculations();
@@ -3504,6 +3556,9 @@ const CALCULATOR_CONFIG = {
updateFoodCalculations() {
if (this.currentMER === 0) return;
+ // Check if we have a range
+ const hasRange = this.currentMERMin !== this.currentMERMax;
+
const daysInput = document.getElementById('days');
const unitSelect = document.getElementById('unit');
const dailyFoodResults = document.getElementById('dailyFoodResults');
@@ -3576,43 +3631,70 @@ const CALCULATOR_CONFIG = {
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;
- console.log('Cups calculation:', {
- caloriesPerCup,
- dailyCaloriesForThisFood,
- dailyCupsForThisFood,
- dailyGramsForThisFood
- });
+ 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
});
@@ -3717,12 +3799,23 @@ const CALCULATOR_CONFIG = {
if (unit === 'cups') {
// For cups, use the pre-calculated cups value if available
if (breakdown.displayCups !== null) {
- valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${frequencySuffix}`;
+ if (breakdown.hasRange && breakdown.displayCupsMin !== breakdown.displayCupsMax) {
+ valueContent = `${this.formatNumber(breakdown.displayCupsMin, decimals)}-${this.formatNumber(breakdown.displayCupsMax, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${frequencySuffix}`;
+ }
} else {
valueContent = `N/A`;
}
} else {
- valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${frequencySuffix}`;
+ // For other units (g, kg, oz, lb)
+ if (breakdown.hasRange && breakdown.displayGramsMin !== breakdown.displayGramsMax) {
+ const minConverted = this.convertUnits(breakdown.displayGramsMin, unit);
+ const maxConverted = this.convertUnits(breakdown.displayGramsMax, unit);
+ valueContent = `${this.formatNumber(minConverted, decimals)}-${this.formatNumber(maxConverted, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${frequencySuffix}`;
+ }
}
} else {
valueContent = `⚠️`;
@@ -3760,23 +3853,53 @@ const CALCULATOR_CONFIG = {
if (validForCups) {
// Calculate total cups using pre-calculated values
let totalCups = 0;
+ let totalCupsMin = 0;
+ let totalCupsMax = 0;
foodBreakdowns.forEach(breakdown => {
if (breakdown.percentage > 0 && breakdown.displayCups !== null) {
totalCups += breakdown.displayCups;
+ if (breakdown.hasRange) {
+ totalCupsMin += breakdown.displayCupsMin || breakdown.displayCups;
+ totalCupsMax += breakdown.displayCupsMax || breakdown.displayCups;
+ } else {
+ totalCupsMin += breakdown.displayCups;
+ totalCupsMax += breakdown.displayCups;
+ }
}
});
- console.log('Total cups display:', {
- totalCups,
- displayTotal,
- foodBreakdowns: foodBreakdowns.map(b => ({ name: b.name, displayCups: b.displayCups }))
- });
- totalDisplayText = this.formatNumber(totalCups, decimals) + ` ${unitLabel}${frequencySuffix}`;
+
+ if (hasRange && totalCupsMin !== totalCupsMax) {
+ totalDisplayText = `${this.formatNumber(totalCupsMin, decimals)}-${this.formatNumber(totalCupsMax, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ totalDisplayText = this.formatNumber(totalCups, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ }
} else {
totalDisplayText = 'Mixed units - see breakdown';
}
} else {
- convertedTotal = this.convertUnits(displayTotal, unit);
- totalDisplayText = this.formatNumber(convertedTotal, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ // Calculate totals for ranges
+ if (hasRange) {
+ let totalGramsMin = 0;
+ let totalGramsMax = 0;
+ foodBreakdowns.forEach(breakdown => {
+ if (breakdown.percentage > 0 && breakdown.hasEnergyContent) {
+ totalGramsMin += breakdown.displayGramsMin || breakdown.displayGrams;
+ totalGramsMax += breakdown.displayGramsMax || breakdown.displayGrams;
+ }
+ });
+
+ const convertedMin = this.convertUnits(totalGramsMin, unit);
+ const convertedMax = this.convertUnits(totalGramsMax, unit);
+
+ if (totalGramsMin !== totalGramsMax) {
+ totalDisplayText = `${this.formatNumber(convertedMin, decimals)}-${this.formatNumber(convertedMax, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ totalDisplayText = this.formatNumber(convertedMin, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ }
+ } else {
+ convertedTotal = this.convertUnits(displayTotal, unit);
+ totalDisplayText = this.formatNumber(convertedTotal, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ }
}
dailyFoodValue.textContent = totalDisplayText;
diff --git a/src/css/main.css b/src/css/main.css
index ada69e7..d08276a 100644
--- a/src/css/main.css
+++ b/src/css/main.css
@@ -22,7 +22,7 @@
}
.dog-calculator-container {
- max-width: 600px;
+ max-width: 640px;
margin: 0 auto;
padding: 24px;
box-sizing: border-box;
@@ -203,6 +203,7 @@
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
+ gap: 10px; /* Add gap between label and value */
}
.dog-calculator-result-item:last-child {
@@ -222,6 +223,7 @@
padding: 4px 12px;
background: rgba(241, 154, 95, 0.15);
border-radius: 4px;
+ white-space: nowrap; /* Prevent text from wrapping to multiple lines */
}
.dog-calculator-collapsible {
@@ -533,6 +535,24 @@
flex-direction: column;
align-items: flex-start;
}
+
+ /* Stack result items vertically on small screens */
+ .dog-calculator-result-item {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 8px;
+ }
+
+ .dog-calculator-result-label {
+ margin-right: 0;
+ font-size: 0.9rem;
+ }
+
+ .dog-calculator-result-value {
+ font-size: 1rem;
+ align-self: stretch;
+ text-align: center;
+ }
}
/* Dark theme - manual override */
diff --git a/src/js/calculator.js b/src/js/calculator.js
index 5804985..66edde8 100644
--- a/src/js/calculator.js
+++ b/src/js/calculator.js
@@ -6,6 +6,8 @@
class DogCalorieCalculator {
constructor() {
this.currentMER = 0;
+ this.currentMERMin = 0; // For range calculations
+ this.currentMERMax = 0; // For range calculations
this.isImperial = false;
this.theme = this.getThemeFromURL() || CALCULATOR_CONFIG.defaultTheme;
this.scale = this.getScaleFromURL() || CALCULATOR_CONFIG.defaultScale;
@@ -1053,6 +1055,25 @@
return rer * factor;
}
+ // Get the range multipliers for each life stage
+ getLifeStageRange(factor) {
+ // Define ranges based on the reference image
+ const ranges = {
+ '3.0': { min: 3.0, max: 3.0 }, // Puppy 0-4 months (no range)
+ '2.0': { min: 2.0, max: 2.0 }, // Puppy 4m-adult OR Working light (no range for puppies)
+ '1.2': { min: 1.2, max: 1.4 }, // Adult inactive/obese
+ '1.6': { min: 1.4, max: 1.6 }, // Adult neutered/spayed
+ '1.8': { min: 1.6, max: 1.8 }, // Adult intact
+ '1.0': { min: 1.0, max: 1.0 }, // Weight loss (fixed)
+ '1.7': { min: 1.2, max: 1.8 }, // Weight gain (wide range)
+ '5.0': { min: 5.0, max: 5.0 }, // Working heavy (upper bound)
+ '1.1': { min: 1.1, max: 1.1 } // Senior (no range)
+ };
+
+ const key = factor.toFixed(1);
+ return ranges[key] || { min: factor, max: factor };
+ }
+
validateInput(value, min = 0, isInteger = false) {
const num = parseFloat(value);
if (isNaN(num) || num < min) return false;
@@ -1184,10 +1205,21 @@
const rer = this.calculateRER(weightKg);
const mer = this.calculateMER(rer, factor);
- this.currentMER = mer;
+ // Calculate range for MER
+ const range = this.getLifeStageRange(factor);
+ this.currentMERMin = this.calculateMER(rer, range.min);
+ this.currentMERMax = this.calculateMER(rer, range.max);
+ this.currentMER = mer; // Keep middle/selected value for compatibility
rerValue.textContent = this.formatNumber(rer, 0) + ' cal/day';
- merValue.textContent = this.formatNumber(mer, 0) + ' cal/day';
+
+ // Show MER as range if applicable
+ if (range.min !== range.max) {
+ merValue.textContent = this.formatNumber(this.currentMERMin, 0) + '-' +
+ this.formatNumber(this.currentMERMax, 0) + ' cal/day';
+ } else {
+ merValue.textContent = this.formatNumber(mer, 0) + ' cal/day';
+ }
calorieResults.style.display = 'block';
this.updateFoodCalculations();
@@ -1222,6 +1254,9 @@
updateFoodCalculations() {
if (this.currentMER === 0) return;
+ // Check if we have a range
+ const hasRange = this.currentMERMin !== this.currentMERMax;
+
const daysInput = document.getElementById('days');
const unitSelect = document.getElementById('unit');
const dailyFoodResults = document.getElementById('dailyFoodResults');
@@ -1294,43 +1329,70 @@
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;
- console.log('Cups calculation:', {
- caloriesPerCup,
- dailyCaloriesForThisFood,
- dailyCupsForThisFood,
- dailyGramsForThisFood
- });
+ 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
});
@@ -1435,12 +1497,23 @@
if (unit === 'cups') {
// For cups, use the pre-calculated cups value if available
if (breakdown.displayCups !== null) {
- valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${frequencySuffix}`;
+ if (breakdown.hasRange && breakdown.displayCupsMin !== breakdown.displayCupsMax) {
+ valueContent = `${this.formatNumber(breakdown.displayCupsMin, decimals)}-${this.formatNumber(breakdown.displayCupsMax, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${frequencySuffix}`;
+ }
} else {
valueContent = `N/A`;
}
} else {
- valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${frequencySuffix}`;
+ // For other units (g, kg, oz, lb)
+ if (breakdown.hasRange && breakdown.displayGramsMin !== breakdown.displayGramsMax) {
+ const minConverted = this.convertUnits(breakdown.displayGramsMin, unit);
+ const maxConverted = this.convertUnits(breakdown.displayGramsMax, unit);
+ valueContent = `${this.formatNumber(minConverted, decimals)}-${this.formatNumber(maxConverted, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${frequencySuffix}`;
+ }
}
} else {
valueContent = `⚠️`;
@@ -1478,23 +1551,53 @@
if (validForCups) {
// Calculate total cups using pre-calculated values
let totalCups = 0;
+ let totalCupsMin = 0;
+ let totalCupsMax = 0;
foodBreakdowns.forEach(breakdown => {
if (breakdown.percentage > 0 && breakdown.displayCups !== null) {
totalCups += breakdown.displayCups;
+ if (breakdown.hasRange) {
+ totalCupsMin += breakdown.displayCupsMin || breakdown.displayCups;
+ totalCupsMax += breakdown.displayCupsMax || breakdown.displayCups;
+ } else {
+ totalCupsMin += breakdown.displayCups;
+ totalCupsMax += breakdown.displayCups;
+ }
}
});
- console.log('Total cups display:', {
- totalCups,
- displayTotal,
- foodBreakdowns: foodBreakdowns.map(b => ({ name: b.name, displayCups: b.displayCups }))
- });
- totalDisplayText = this.formatNumber(totalCups, decimals) + ` ${unitLabel}${frequencySuffix}`;
+
+ if (hasRange && totalCupsMin !== totalCupsMax) {
+ totalDisplayText = `${this.formatNumber(totalCupsMin, decimals)}-${this.formatNumber(totalCupsMax, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ totalDisplayText = this.formatNumber(totalCups, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ }
} else {
totalDisplayText = 'Mixed units - see breakdown';
}
} else {
- convertedTotal = this.convertUnits(displayTotal, unit);
- totalDisplayText = this.formatNumber(convertedTotal, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ // Calculate totals for ranges
+ if (hasRange) {
+ let totalGramsMin = 0;
+ let totalGramsMax = 0;
+ foodBreakdowns.forEach(breakdown => {
+ if (breakdown.percentage > 0 && breakdown.hasEnergyContent) {
+ totalGramsMin += breakdown.displayGramsMin || breakdown.displayGrams;
+ totalGramsMax += breakdown.displayGramsMax || breakdown.displayGrams;
+ }
+ });
+
+ const convertedMin = this.convertUnits(totalGramsMin, unit);
+ const convertedMax = this.convertUnits(totalGramsMax, unit);
+
+ if (totalGramsMin !== totalGramsMax) {
+ totalDisplayText = `${this.formatNumber(convertedMin, decimals)}-${this.formatNumber(convertedMax, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ totalDisplayText = this.formatNumber(convertedMin, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ }
+ } else {
+ convertedTotal = this.convertUnits(displayTotal, unit);
+ totalDisplayText = this.formatNumber(convertedTotal, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ }
}
dailyFoodValue.textContent = totalDisplayText;
diff --git a/sundog-dog-food-calculator.js b/sundog-dog-food-calculator.js
index 8d8832c..3effe59 100644
--- a/sundog-dog-food-calculator.js
+++ b/sundog-dog-food-calculator.js
@@ -47,7 +47,7 @@
}
.dog-calculator-container {
- max-width: 600px;
+ max-width: 640px;
margin: 0 auto;
padding: 24px;
box-sizing: border-box;
@@ -228,6 +228,7 @@
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
+ gap: 10px; /* Add gap between label and value */
}
.dog-calculator-result-item:last-child {
@@ -247,6 +248,7 @@
padding: 4px 12px;
background: rgba(241, 154, 95, 0.15);
border-radius: 4px;
+ white-space: nowrap; /* Prevent text from wrapping to multiple lines */
}
.dog-calculator-collapsible {
@@ -558,6 +560,24 @@
flex-direction: column;
align-items: flex-start;
}
+
+ /* Stack result items vertically on small screens */
+ .dog-calculator-result-item {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 8px;
+ }
+
+ .dog-calculator-result-label {
+ margin-right: 0;
+ font-size: 0.9rem;
+ }
+
+ .dog-calculator-result-value {
+ font-size: 1rem;
+ align-self: stretch;
+ text-align: center;
+ }
}
/* Dark theme - manual override */
@@ -2105,6 +2125,8 @@ const CALCULATOR_CONFIG = {
this.theme = this.options.theme;
this.scale = this.options.scale;
this.currentMER = 0;
+ this.currentMERMin = 0; // For range calculations
+ this.currentMERMax = 0; // For range calculations
this.isImperial = false;
@@ -3372,6 +3394,25 @@ const CALCULATOR_CONFIG = {
return rer * factor;
}
+ // Get the range multipliers for each life stage
+ getLifeStageRange(factor) {
+ // Define ranges based on the reference image
+ const ranges = {
+ '3.0': { min: 3.0, max: 3.0 }, // Puppy 0-4 months (no range)
+ '2.0': { min: 2.0, max: 2.0 }, // Puppy 4m-adult OR Working light (no range for puppies)
+ '1.2': { min: 1.2, max: 1.4 }, // Adult inactive/obese
+ '1.6': { min: 1.4, max: 1.6 }, // Adult neutered/spayed
+ '1.8': { min: 1.6, max: 1.8 }, // Adult intact
+ '1.0': { min: 1.0, max: 1.0 }, // Weight loss (fixed)
+ '1.7': { min: 1.2, max: 1.8 }, // Weight gain (wide range)
+ '5.0': { min: 5.0, max: 5.0 }, // Working heavy (upper bound)
+ '1.1': { min: 1.1, max: 1.1 } // Senior (no range)
+ };
+
+ const key = factor.toFixed(1);
+ return ranges[key] || { min: factor, max: factor };
+ }
+
validateInput(value, min = 0, isInteger = false) {
const num = parseFloat(value);
if (isNaN(num) || num < min) return false;
@@ -3503,10 +3544,21 @@ const CALCULATOR_CONFIG = {
const rer = this.calculateRER(weightKg);
const mer = this.calculateMER(rer, factor);
- this.currentMER = mer;
+ // Calculate range for MER
+ const range = this.getLifeStageRange(factor);
+ this.currentMERMin = this.calculateMER(rer, range.min);
+ this.currentMERMax = this.calculateMER(rer, range.max);
+ this.currentMER = mer; // Keep middle/selected value for compatibility
rerValue.textContent = this.formatNumber(rer, 0) + ' cal/day';
- merValue.textContent = this.formatNumber(mer, 0) + ' cal/day';
+
+ // Show MER as range if applicable
+ if (range.min !== range.max) {
+ merValue.textContent = this.formatNumber(this.currentMERMin, 0) + '-' +
+ this.formatNumber(this.currentMERMax, 0) + ' cal/day';
+ } else {
+ merValue.textContent = this.formatNumber(mer, 0) + ' cal/day';
+ }
calorieResults.style.display = 'block';
this.updateFoodCalculations();
@@ -3541,6 +3593,9 @@ const CALCULATOR_CONFIG = {
updateFoodCalculations() {
if (this.currentMER === 0) return;
+ // Check if we have a range
+ const hasRange = this.currentMERMin !== this.currentMERMax;
+
const daysInput = this.container.querySelector('#days');
const unitSelect = this.container.querySelector('#unit');
const dailyFoodResults = this.container.querySelector('#dailyFoodResults');
@@ -3613,43 +3668,70 @@ const CALCULATOR_CONFIG = {
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;
- console.log('Cups calculation:', {
- caloriesPerCup,
- dailyCaloriesForThisFood,
- dailyCupsForThisFood,
- dailyGramsForThisFood
- });
+ 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
});
@@ -3754,12 +3836,23 @@ const CALCULATOR_CONFIG = {
if (unit === 'cups') {
// For cups, use the pre-calculated cups value if available
if (breakdown.displayCups !== null) {
- valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${frequencySuffix}`;
+ if (breakdown.hasRange && breakdown.displayCupsMin !== breakdown.displayCupsMax) {
+ valueContent = `${this.formatNumber(breakdown.displayCupsMin, decimals)}-${this.formatNumber(breakdown.displayCupsMax, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${frequencySuffix}`;
+ }
} else {
valueContent = `N/A`;
}
} else {
- valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${frequencySuffix}`;
+ // For other units (g, kg, oz, lb)
+ if (breakdown.hasRange && breakdown.displayGramsMin !== breakdown.displayGramsMax) {
+ const minConverted = this.convertUnits(breakdown.displayGramsMin, unit);
+ const maxConverted = this.convertUnits(breakdown.displayGramsMax, unit);
+ valueContent = `${this.formatNumber(minConverted, decimals)}-${this.formatNumber(maxConverted, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${frequencySuffix}`;
+ }
}
} else {
valueContent = `⚠️`;
@@ -3797,23 +3890,53 @@ const CALCULATOR_CONFIG = {
if (validForCups) {
// Calculate total cups using pre-calculated values
let totalCups = 0;
+ let totalCupsMin = 0;
+ let totalCupsMax = 0;
foodBreakdowns.forEach(breakdown => {
if (breakdown.percentage > 0 && breakdown.displayCups !== null) {
totalCups += breakdown.displayCups;
+ if (breakdown.hasRange) {
+ totalCupsMin += breakdown.displayCupsMin || breakdown.displayCups;
+ totalCupsMax += breakdown.displayCupsMax || breakdown.displayCups;
+ } else {
+ totalCupsMin += breakdown.displayCups;
+ totalCupsMax += breakdown.displayCups;
+ }
}
});
- console.log('Total cups display:', {
- totalCups,
- displayTotal,
- foodBreakdowns: foodBreakdowns.map(b => ({ name: b.name, displayCups: b.displayCups }))
- });
- totalDisplayText = this.formatNumber(totalCups, decimals) + ` ${unitLabel}${frequencySuffix}`;
+
+ if (hasRange && totalCupsMin !== totalCupsMax) {
+ totalDisplayText = `${this.formatNumber(totalCupsMin, decimals)}-${this.formatNumber(totalCupsMax, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ totalDisplayText = this.formatNumber(totalCups, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ }
} else {
totalDisplayText = 'Mixed units - see breakdown';
}
} else {
- convertedTotal = this.convertUnits(displayTotal, unit);
- totalDisplayText = this.formatNumber(convertedTotal, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ // Calculate totals for ranges
+ if (hasRange) {
+ let totalGramsMin = 0;
+ let totalGramsMax = 0;
+ foodBreakdowns.forEach(breakdown => {
+ if (breakdown.percentage > 0 && breakdown.hasEnergyContent) {
+ totalGramsMin += breakdown.displayGramsMin || breakdown.displayGrams;
+ totalGramsMax += breakdown.displayGramsMax || breakdown.displayGrams;
+ }
+ });
+
+ const convertedMin = this.convertUnits(totalGramsMin, unit);
+ const convertedMax = this.convertUnits(totalGramsMax, unit);
+
+ if (totalGramsMin !== totalGramsMax) {
+ totalDisplayText = `${this.formatNumber(convertedMin, decimals)}-${this.formatNumber(convertedMax, decimals)} ${unitLabel}${frequencySuffix}`;
+ } else {
+ totalDisplayText = this.formatNumber(convertedMin, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ }
+ } else {
+ convertedTotal = this.convertUnits(displayTotal, unit);
+ totalDisplayText = this.formatNumber(convertedTotal, decimals) + ` ${unitLabel}${frequencySuffix}`;
+ }
}
dailyFoodValue.textContent = totalDisplayText;