271 lines
8.8 KiB
JavaScript
271 lines
8.8 KiB
JavaScript
/**
|
||
* Dog Calorie Calculator - Shared Core Logic
|
||
* This file contains all the business logic, calculations, and configurations
|
||
* that are shared between the iframe and widget versions.
|
||
*
|
||
* By Canine Nutrition and Wellness
|
||
* https://caninenutritionandwellness.com
|
||
*/
|
||
|
||
// Core configuration and constants
|
||
const DOG_CALCULATOR_CONFIG = {
|
||
// Dog type factors and labels
|
||
dogTypes: [
|
||
{ value: "3.0", label: "Puppy (0-4 months)" },
|
||
{ value: "2.0", label: "Puppy (4 months - adult)" },
|
||
{ value: "1.2", label: "Adult - inactive/obese" },
|
||
{ value: "1.6", label: "Adult (neutered/spayed) - average activity" },
|
||
{ value: "1.8", label: "Adult (intact) - average activity" },
|
||
{ value: "1.0", label: "Adult - weight loss" },
|
||
{ value: "1.7", label: "Adult - weight gain" },
|
||
{ value: "2.0", label: "Working dog - light work" },
|
||
{ value: "3.0", label: "Working dog - moderate work" },
|
||
{ value: "5.0", label: "Working dog - heavy work" },
|
||
{ value: "1.1", label: "Senior dog" }
|
||
],
|
||
|
||
// Energy unit configurations
|
||
energyUnits: [
|
||
{ value: "kcal100g", label: "kcal/100g" },
|
||
{ value: "kcalkg", label: "kcal/kg" },
|
||
{ value: "kcalcup", label: "kcal/cup" },
|
||
{ value: "kcalcan", label: "kcal/can" }
|
||
],
|
||
|
||
// Unit options for different measurement systems
|
||
units: {
|
||
metric: [
|
||
{ value: "g", label: "grams (g)" },
|
||
{ value: "kg", label: "kilograms (kg)" },
|
||
{ value: "oz", label: "ounces (oz)" },
|
||
{ value: "lb", label: "pounds (lb)" }
|
||
],
|
||
imperial: [
|
||
{ value: "oz", label: "ounces (oz)" },
|
||
{ value: "lb", label: "pounds (lb)" },
|
||
{ value: "g", label: "grams (g)" },
|
||
{ value: "kg", label: "kilograms (kg)" }
|
||
]
|
||
},
|
||
|
||
// Conversion factors
|
||
conversions: {
|
||
lbToKg: 2.20462,
|
||
gToOz: 28.3495,
|
||
gToLb: 453.592,
|
||
gToKg: 1000
|
||
},
|
||
|
||
// Energy unit conversion factors to kcal/100g
|
||
energyConversions: {
|
||
kcal100g: 1,
|
||
kcalkg: 0.1, // 1 kg = 10 × 100g
|
||
kcalcup: 0.833, // Assume 1 cup ≈ 120g for dry dog food
|
||
kcalcan: 0.222 // Assume 1 can ≈ 450g for wet dog food
|
||
},
|
||
|
||
// Validation limits for energy units
|
||
energyLimits: {
|
||
kcal100g: { min: 1, max: 1000 },
|
||
kcalkg: { min: 10, max: 10000 },
|
||
kcalcup: { min: 50, max: 1000 },
|
||
kcalcan: { min: 100, max: 2000 }
|
||
}
|
||
};
|
||
|
||
// Core calculator functions
|
||
const DogCalculatorCore = {
|
||
/**
|
||
* Calculate Resting Energy Requirement (RER)
|
||
* Formula: 70 × (weight in kg)^0.75
|
||
*/
|
||
calculateRER(weightKg) {
|
||
if (!weightKg || weightKg <= 0) return 0;
|
||
return 70 * Math.pow(weightKg, 0.75);
|
||
},
|
||
|
||
/**
|
||
* Calculate Maintenance Energy Requirement (MER)
|
||
* Formula: RER × activity factor
|
||
*/
|
||
calculateMER(rer, factor) {
|
||
if (!rer || !factor || factor <= 0) return 0;
|
||
return rer * factor;
|
||
},
|
||
|
||
/**
|
||
* Convert weight to kg regardless of input unit
|
||
*/
|
||
convertWeightToKg(weight, isImperial) {
|
||
if (!weight || weight <= 0) return null;
|
||
return isImperial ? weight / DOG_CALCULATOR_CONFIG.conversions.lbToKg : weight;
|
||
},
|
||
|
||
/**
|
||
* Convert weight from kg to display unit
|
||
*/
|
||
convertWeightFromKg(weightKg, isImperial) {
|
||
if (!weightKg || weightKg <= 0) return null;
|
||
return isImperial ? weightKg * DOG_CALCULATOR_CONFIG.conversions.lbToKg : weightKg;
|
||
},
|
||
|
||
/**
|
||
* Convert food energy to kcal/100g for calculations
|
||
*/
|
||
convertFoodEnergyTo100g(energy, unit) {
|
||
if (!energy || energy <= 0) return null;
|
||
const factor = DOG_CALCULATOR_CONFIG.energyConversions[unit];
|
||
return factor ? energy * factor : energy;
|
||
},
|
||
|
||
/**
|
||
* Convert food amounts between units
|
||
*/
|
||
convertUnits(grams, targetUnit) {
|
||
if (!grams || grams <= 0) return 0;
|
||
|
||
switch (targetUnit) {
|
||
case 'kg':
|
||
return grams / DOG_CALCULATOR_CONFIG.conversions.gToKg;
|
||
case 'oz':
|
||
return grams / DOG_CALCULATOR_CONFIG.conversions.gToOz;
|
||
case 'lb':
|
||
return grams / DOG_CALCULATOR_CONFIG.conversions.gToLb;
|
||
default:
|
||
return grams;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Calculate daily food amount in grams
|
||
*/
|
||
calculateDailyFoodGrams(merCalories, energyPer100g) {
|
||
if (!merCalories || !energyPer100g || energyPer100g <= 0) return 0;
|
||
return (merCalories / energyPer100g) * 100;
|
||
},
|
||
|
||
/**
|
||
* Validate input values
|
||
*/
|
||
validateInput(value, min = 0, isInteger = false) {
|
||
const num = parseFloat(value);
|
||
if (isNaN(num) || num < min) return false;
|
||
if (isInteger && !Number.isInteger(num)) return false;
|
||
return true;
|
||
},
|
||
|
||
/**
|
||
* Validate energy input based on unit
|
||
*/
|
||
validateEnergyInput(energy, unit) {
|
||
if (!energy || !unit) return false;
|
||
const limits = DOG_CALCULATOR_CONFIG.energyLimits[unit];
|
||
if (!limits) return false;
|
||
|
||
const num = parseFloat(energy);
|
||
return !isNaN(num) && num >= limits.min && num <= limits.max;
|
||
},
|
||
|
||
/**
|
||
* Format number for display
|
||
*/
|
||
formatNumber(num, decimals = 0) {
|
||
if (typeof num !== 'number' || isNaN(num)) return '0';
|
||
|
||
if (decimals === 0) {
|
||
return Math.round(num).toString();
|
||
}
|
||
return num.toFixed(decimals).replace(/\.?0+$/, '');
|
||
},
|
||
|
||
/**
|
||
* Get theme from URL parameters
|
||
*/
|
||
getThemeFromURL() {
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
const theme = urlParams.get('theme');
|
||
return ['light', 'dark', 'system'].includes(theme) ? theme : 'system';
|
||
},
|
||
|
||
/**
|
||
* Get scale from URL parameters
|
||
*/
|
||
getScaleFromURL() {
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
const scale = parseFloat(urlParams.get('scale'));
|
||
return (!isNaN(scale) && scale >= 0.5 && scale <= 2.0) ? scale : 1.0;
|
||
},
|
||
|
||
/**
|
||
* Generate embed codes
|
||
*/
|
||
generateEmbedCodes(baseUrl) {
|
||
const scriptTag = `<script src="${baseUrl}/dog-food-calculator-widget.js"></script>`;
|
||
const divTag = `<div id="dog-calorie-calculator"></div>`;
|
||
const widgetCode = scriptTag + '\n' + divTag;
|
||
|
||
const iframeCode = `<iframe src="${baseUrl}/iframe.html" width="100%" height="600" frameborder="0" title="Dog Calorie Calculator"></iframe>`;
|
||
|
||
return { widgetCode, iframeCode };
|
||
},
|
||
|
||
/**
|
||
* Share URLs for different platforms
|
||
*/
|
||
generateShareUrls(currentUrl) {
|
||
const encodedUrl = encodeURIComponent(currentUrl);
|
||
const text = encodeURIComponent('Check out this useful dog calorie calculator!');
|
||
|
||
return {
|
||
facebook: `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`,
|
||
twitter: `https://twitter.com/intent/tweet?url=${encodedUrl}&text=${text}`,
|
||
linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${encodedUrl}`,
|
||
email: `mailto:?subject=${encodeURIComponent('Dog Calorie Calculator')}&body=${encodeURIComponent('Check out this useful dog calorie calculator: ' + currentUrl)}`
|
||
};
|
||
},
|
||
|
||
/**
|
||
* Copy text to clipboard with fallback
|
||
*/
|
||
async copyToClipboard(text, button) {
|
||
if (!text || !button) return false;
|
||
|
||
try {
|
||
await navigator.clipboard.writeText(text);
|
||
const originalText = button.textContent;
|
||
button.textContent = 'Copied!';
|
||
button.classList.add('copied');
|
||
|
||
setTimeout(() => {
|
||
button.textContent = originalText;
|
||
button.classList.remove('copied');
|
||
}, 2000);
|
||
|
||
return true;
|
||
} catch (err) {
|
||
// Fallback for older browsers
|
||
try {
|
||
const textArea = document.createElement('textarea');
|
||
textArea.value = text;
|
||
textArea.style.position = 'fixed';
|
||
textArea.style.opacity = '0';
|
||
document.body.appendChild(textArea);
|
||
textArea.select();
|
||
document.execCommand('copy');
|
||
document.body.removeChild(textArea);
|
||
return true;
|
||
} catch (fallbackErr) {
|
||
console.error('Copy to clipboard failed:', fallbackErr);
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
// Export for different module systems
|
||
if (typeof module !== 'undefined' && module.exports) {
|
||
module.exports = { DOG_CALCULATOR_CONFIG, DogCalculatorCore };
|
||
} else if (typeof window !== 'undefined') {
|
||
window.DOG_CALCULATOR_CONFIG = DOG_CALCULATOR_CONFIG;
|
||
window.DogCalculatorCore = DogCalculatorCore;
|
||
} |