kcalculator/main.js

235 lines
7.1 KiB
JavaScript
Raw Normal View History

2022-09-08 22:55:43 +02:00
const foodSearch = document.querySelector("#food-search");
const searchEntries = document.querySelector("#search-entries");
const foodMenu = document.querySelector("#food-menu");
2022-09-09 13:23:03 +02:00
const menuTable = document.querySelector("#menu-table");
const summaryEnergy = document.querySelector("#summary-energy");
const summaryFat = document.querySelector("#summary-fat");
const summaryCarbs = document.querySelector("#summary-carbs");
2022-09-09 15:25:08 +02:00
const summarySugar = document.querySelector("#summary-sugar");
2022-09-09 13:23:03 +02:00
const summaryProteins = document.querySelector("#summary-proteins");
2022-09-09 15:25:08 +02:00
const summaryAlc = document.querySelector("#summary-alc");
2022-09-09 13:23:03 +02:00
2022-09-09 15:25:08 +02:00
const alcDensity = 0.789;
2022-09-08 22:55:43 +02:00
updateSummary();
initFoodList();
foodSearch.addEventListener("input", onFoodSearched);
if (foodSearch.value != "") onFoodSearched();
function initFoodList() {
const dataList = document.querySelector("#food-list");
for (let food of foods) {
const option = document.createElement("option");
option.setAttribute("value", food.name);
dataList.appendChild(option);
}
}
function onFoodSearched() {
const food = foodSearch.value;
const foodLC = food.toLowerCase();
2022-09-09 17:22:52 +02:00
2022-09-08 22:55:43 +02:00
if (food == "") {
createSearchEntries([]);
return;
}
const foodsCopy = structuredClone(foods);
foodsCopy.sort((a, b) => {
const aNameLC = a.name.toLowerCase();
const bNameLC = b.name.toLowerCase();
const ainc = aNameLC.includes(foodLC);
const binc = bNameLC.includes(foodLC);
if (ainc && binc) {
return 0;
} else if (ainc) {
return -1;
} else if (binc) {
return 1;
}
const distA = levenshtein(foodLC, aNameLC);
const distB = levenshtein(foodLC, bNameLC);
return distA - distB;
})
const maxDist = 10;
let maxAmount = 10;
let amount = 0;
for (let f of foodsCopy) {
const fnameLC = f.name.toLowerCase();
if (fnameLC.includes(foodLC)) {
amount++;
maxAmount++;
continue;
}
const dist = levenshtein(foodLC, fnameLC);
if (dist >= maxDist) break;
amount++;
}
createSearchEntries(foodsCopy.slice(0, Math.min(amount, maxAmount, 30)));
}
async function createSearchEntries(foods) {
const nodes = [];
for (let food of foods) {
const node = await JST.load("search-entry");
node.querySelector(".search-entry-name").textContent = food.name;
node.querySelector(".search-entry").addEventListener("click", () => addMenuItem(food));
nodes.push(node);
}
searchEntries.replaceChildren(...nodes);
}
async function addMenuItem(food) {
const alreadyAddedMenuItem = document.querySelector(`#food-menu .menu-item[data-food-name="${food.name}"]`);
if (alreadyAddedMenuItem !== null) {
alreadyAddedMenuItem.style.animation = "highlight 0.25s linear";
setTimeout(() => alreadyAddedMenuItem.style.animation = "", 250);
return;
}
const node = await JST.load("menu-item");
2022-09-09 13:23:03 +02:00
2022-09-08 22:55:43 +02:00
const nodeRoot = node.querySelector(".menu-item");
2022-09-09 13:23:03 +02:00
const itemName = node.querySelector(".menu-item-name");
const itemKcal = node.querySelector(".menu-item-kcal");
const itemUnit = node.querySelector(".menu-item-unit");
2022-09-08 22:55:43 +02:00
const itemAmount = node.querySelector(".menu-item-amount");
2022-09-09 13:23:03 +02:00
const kcalAmount = node.querySelector(".menu-item-energy");
const fatAmount = node.querySelector(".menu-item-fat");
const carbsAmount = node.querySelector(".menu-item-carbs");
2022-09-09 15:25:08 +02:00
const sugarAmount = node.querySelector(".menu-item-sugar");
2022-09-09 13:23:03 +02:00
const proteinsAmount = node.querySelector(".menu-item-proteins");
2022-09-09 15:25:08 +02:00
const alcAmount = node.querySelector(".menu-item-alc");
2022-09-09 00:21:59 +02:00
const score = node.querySelector(".menu-item-score");
2022-09-09 13:23:03 +02:00
2022-09-09 15:25:08 +02:00
const nutritions100 = calculateKcal(food, 100);
2022-09-08 22:55:43 +02:00
nodeRoot.setAttribute("data-food-name", food.name);
2022-09-09 13:23:03 +02:00
itemName.textContent = food.name;
2022-09-09 15:25:08 +02:00
itemKcal.textContent = `${nutritions100.kcal} kcal/100${food.unit}`;
2022-09-09 13:23:03 +02:00
itemUnit.textContent = food.unit;
fatAmount.textContent = `${food.fat}g`;
carbsAmount.textContent = `${food.carbs}g`;
proteinsAmount.textContent = `${food.proteins}g`;
2022-09-09 00:21:59 +02:00
2022-09-09 15:25:08 +02:00
score.textContent = nutritions100.score.toFixed(1);
score.classList.add(getScoreColor(nutritions100.score, food.unit));
2022-09-09 00:21:59 +02:00
2022-09-08 22:55:43 +02:00
node.querySelector(".delete-menu-item").addEventListener("click", () => {
foodMenu.removeChild(nodeRoot);
updateSummary();
});
2022-09-09 15:25:08 +02:00
const updateFoodValues = () => {
2022-09-09 01:20:36 +02:00
if (!/^[0-9]+$/.test(itemAmount.value)) {
2022-09-08 22:55:43 +02:00
return;
}
2022-09-09 01:20:36 +02:00
2022-09-08 22:55:43 +02:00
const amount = parseInt(itemAmount.value);
2022-09-09 15:25:08 +02:00
updateFoodAmount(food, amount, kcalAmount, fatAmount, carbsAmount, sugarAmount, proteinsAmount, alcAmount);
2022-09-09 01:20:36 +02:00
};
2022-09-09 15:25:08 +02:00
const evaluateFoodValues = () => {
2022-09-09 01:20:36 +02:00
if (/^[0-9]+$/.test(itemAmount.value)) {
return;
}
const evaluator = new Worker("evaluator.js");
evaluator.postMessage(itemAmount.value);
evaluator.onmessage = e => {
const amount = Math.max(parseInt(e.data), 0);
itemAmount.value = amount;
2022-09-09 15:25:08 +02:00
updateFoodAmount(food, amount, kcalAmount, fatAmount, carbsAmount, sugarAmount, proteinsAmount, alcAmount);
2022-09-09 01:20:36 +02:00
};
2022-09-08 22:55:43 +02:00
}
2022-09-09 00:55:16 +02:00
itemAmount.value = food.avg_amount ?? 100;
2022-09-09 15:25:08 +02:00
itemAmount.addEventListener("input", updateFoodValues);
itemAmount.addEventListener("change", evaluateFoodValues);
2022-09-08 22:55:43 +02:00
foodMenu.appendChild(node);
2022-09-09 15:25:08 +02:00
updateFoodValues();
}
function updateFoodAmount(food, amount, kcalAmount, fatAmount, carbsAmount, sugarAmount, proteinsAmount, alcAmount) {
const {fat, carbs, sugar, proteins, alc, kcal} = calculateKcal(food, amount);
kcalAmount.textContent = `${parseInt(kcal)}kcal`;
fatAmount.textContent = `${parseInt(fat)}g`;
carbsAmount.textContent = `${parseInt(carbs)}g`;
sugarAmount.textContent = `${parseInt(sugar)}g`;
proteinsAmount.textContent = `${parseInt(proteins)}g`;
alcAmount.textContent = `${parseInt(alc)}g`;
2022-09-08 22:55:43 +02:00
updateSummary();
}
2022-09-09 15:25:08 +02:00
function calculateKcal(food, amount) {
const fat = Math.round(food.fat / 100 * amount)
const carbs = Math.round(food.carbs / 100 * amount);
const sugar = Math.round(food.sugar / 100 * amount);
const proteins = Math.round(food.proteins / 100 * amount);
const alc = Math.round(amount * food.alc / 100);
const kcal = Math.round(fat * 9 + carbs * 4 + proteins * 4 + alc * 7);
const score = kcal / amount;
return {fat, carbs, sugar, proteins, alc, kcal, score}
}
2022-09-08 22:55:43 +02:00
function updateSummary() {
2022-09-09 13:23:03 +02:00
const menuItems = foodMenu.querySelectorAll(".menu-item");
menuTable.style.display = menuItems.length > 0 ? "table" : "none";
let energy = 0;
let fat = 0;
let carbs = 0;
2022-09-09 15:25:08 +02:00
let sugar = 0;
2022-09-09 13:23:03 +02:00
let proteins = 0;
2022-09-09 15:25:08 +02:00
let alc = 0;
2022-09-09 13:23:03 +02:00
for (let menuItem of menuItems) {
energy += parseInt(menuItem.querySelector(".menu-item-energy").textContent);
fat += parseInt(menuItem.querySelector(".menu-item-fat").textContent);
carbs += parseInt(menuItem.querySelector(".menu-item-carbs").textContent);
2022-09-09 15:25:08 +02:00
sugar += parseInt(menuItem.querySelector(".menu-item-sugar").textContent);
2022-09-09 13:23:03 +02:00
proteins += parseInt(menuItem.querySelector(".menu-item-proteins").textContent);
2022-09-09 15:25:08 +02:00
alc += parseInt(menuItem.querySelector(".menu-item-alc").textContent);
2022-09-08 22:55:43 +02:00
}
2022-09-09 13:23:03 +02:00
summaryEnergy.textContent = `${energy}kcal`;
summaryFat.textContent = `${fat}g`;
summaryCarbs.textContent = `${carbs}g`;
2022-09-09 15:25:08 +02:00
summarySugar.textContent = `${sugar}g`;
2022-09-09 13:23:03 +02:00
summaryProteins.textContent = `${proteins}g`;
2022-09-09 15:25:08 +02:00
summaryAlc.textContent = `${alc}g`;
2022-09-09 00:21:59 +02:00
}
function getScoreColor(density, unit) {
switch (unit) {
case "g": {
if (density >= 2.4) {
return "red"
2022-09-09 15:25:08 +02:00
} else if (density >= 1.6) {
2022-09-09 00:21:59 +02:00
return "orange"
} else {
return "green";
}
}
2022-09-09 17:22:52 +02:00
2022-09-09 00:21:59 +02:00
case "ml": {
2022-09-09 15:25:08 +02:00
if (density >= 0.1) {
2022-09-09 00:21:59 +02:00
return "red"
} else {
return "green";
}
}
}
2022-09-09 17:22:52 +02:00
}