From 6449ec971a4e718b4b3f608e5fe08edcaf5093cd Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Thu, 1 Jun 2023 17:40:11 +0200 Subject: [PATCH] Improve responsiveness of input box via timeout delay, add date range to chart, add sum and sum by store charting to main page. --- site/cart.html | 4 ++++ site/cart.js | 25 ++++++++++++++++++++- site/index.html | 13 ++++++++++- site/main.js | 59 ++++++++++++++++++++++++++++++++----------------- site/utils.js | 58 ++++++++++++++++++++++++++++++++---------------- 5 files changed, 118 insertions(+), 41 deletions(-) diff --git a/site/cart.html b/site/cart.html index 4e3489b..262d694 100644 --- a/site/cart.html +++ b/site/cart.html @@ -26,6 +26,10 @@ +
+ + +

diff --git a/site/cart.js b/site/cart.js index 48610da..a661e4b 100644 --- a/site/cart.js +++ b/site/cart.js @@ -67,6 +67,10 @@ async function load() { document.querySelector("#sum").addEventListener("change", () => updateCharts(canvasDom, filter(cart.items))); document.querySelector("#sumstores").addEventListener("change", () => updateCharts(canvasDom, filter(cart.items))); document.querySelector("#todayonly").addEventListener("change", () => updateCharts(canvasDom, filter(cart.items))); + document.querySelector("#start").addEventListener("change", () => updateCharts(canvasDom, filter(cart.items))); + document.querySelector("#end").addEventListener("change", () => updateCharts(canvasDom, filter(cart.items))); + document.querySelector("#start").value = getOldestDate(cart.items); + document.querySelector("#end").value = currentDate(); const filtersStore = document.querySelector("#filters-store"); filtersStore.innerHTML = STORE_KEYS.map(store => ``).join(" "); @@ -103,6 +107,8 @@ function showSearch(cart, items) { cell.children[0].addEventListener("click", () => { cart.items.push(item); shoppingCarts.save(); + document.querySelector("#start").value = getOldestDate(cart.items); + document.querySelector("#end").value = currentDate(); showCart(cart); }); itemDom.appendChild(cell); @@ -111,7 +117,22 @@ function showSearch(cart, items) { } function updateCharts(canvasDom, items) { - showCharts(canvasDom, items, document.querySelector("#sum").checked, document.querySelector("#sumstores").checked, document.querySelector("#todayonly").checked); + let startDate = document.querySelector("#start").value; + let endDate = document.querySelector("#end").value; + if (start > endDate) { + let tmp = start; + start = endDate; + endDate = tmp; + } + showCharts( + canvasDom, + items, + document.querySelector("#sum").checked, + document.querySelector("#sumstores").checked, + document.querySelector("#todayonly").checked, + startDate, + endDate + ); } function showCart(cart) { @@ -156,6 +177,8 @@ function showCart(cart) { cell.children[1].addEventListener("click", () => { cart.items.splice(idx, 1); shoppingCarts.save(); + document.querySelector("#start").value = getOldestDate(cart.items); + document.querySelector("#end").value = currentDate(); showCart(cart) }); diff --git a/site/index.html b/site/index.html index 858df8d..2a82752 100644 --- a/site/index.html +++ b/site/index.html @@ -17,7 +17,18 @@ Tagespreisänderungen Warenkörbe
- +
+ +
+ + + +
+
+ + +
+
diff --git a/site/main.js b/site/main.js index c624d0f..d0d14bb 100644 --- a/site/main.js +++ b/site/main.js @@ -1,10 +1,41 @@ +function updateCharts(canvasDom, items) { + const now =performance.now(); + const sum = document.querySelector("#sum").checked; + const sumStores = document.querySelector("#sumstores").checked; + const todayOnly = document.querySelector("#todayonly").checked; + let startDate = document.querySelector("#start").value; + let endDate = document.querySelector("#end").value; + if (start > endDate) { + let tmp = start; + start = endDate; + endDate = tmp; + } + showCharts(canvasDom, items, sum, sumStores, todayOnly, startDate, endDate); + console.log("Updating charts took: " + (performance.now() - now) / 1000 + " seconds"); +} async function load() { const items = await loadItems(); const chartDom = document.querySelector("#chart"); + const canvasDom = chartDom.querySelector("canvas"); + let lastHits = null; + document.querySelector("#sum").addEventListener("change", () => updateCharts(canvasDom, lastHits)); + document.querySelector("#sumstores").addEventListener("change", () => updateCharts(canvasDom, lastHits)); + document.querySelector("#todayonly").addEventListener("change", () => updateCharts(canvasDom, lastHits)); + document.querySelector("#start").addEventListener("change", () => updateCharts(canvasDom, lastHits)); + document.querySelector("#end").addEventListener("change", () => updateCharts(canvasDom, lastHits)); + document.querySelector("#start").value = getOldestDate(items); + document.querySelector("#end").value = currentDate(); + newSearchComponent(document.querySelector("#search"), items, (hits) => { items.forEach(item => item.chart = false); - showChart(chartDom, []); + if (hits.length > 0) { + chartDom.classList.remove("hide"); + } else { + chartDom.classList.add("hide"); + } + updateCharts(canvasDom, hits); + lastHits = hits; return hits; }, null, @@ -19,28 +50,16 @@ async function load() { }) return header; }, (item, itemDom, items, setQuery) => { - const chartCheckbox = dom("input"); - const checked = (getQueryParameter("c") ?? []).includes(`${item.store}:${item.id}`); - chartCheckbox.setAttribute("type", "checkbox"); - chartCheckbox.checked = checked; - item.chart = checked; - chartCheckbox.setAttribute("data-id", `${item.store}:${item.id}`); - const cell = dom("td", ""); - cell.appendChild(chartCheckbox); + const checked = item.chart = (getQueryParameter("c") ?? []).includes(`${item.store}:${item.id}`); + const dataId = item.store + ":" + item.id; + const cell = dom("td", ``); itemDom.appendChild(cell); const handleClick = (eventShouldSetQuery = false) =>{ - item.chart = chartCheckbox.checked; - const data = []; - items.forEach(i => { if (i.chart) data.push(i) }); - if (data.length == 0) { - chartDom.style.display = "none"; - } else { - chartDom.style.display = "block"; - showChart(chartDom, data); - } + item.chart = cell.children[0].checked; + updateCharts(canvasDom, lastHits) !!eventShouldSetQuery && setQuery(); } - chartCheckbox.addEventListener("click", handleClick); + cell.children[0].addEventListener("click", handleClick); checked && handleClick(); return itemDom; }); @@ -49,7 +68,7 @@ async function load() { document.querySelector("input").value = query; const inputEvent = new Event('input', { bubbles: true, - cancelable: true + cancelable: false }); document.querySelector("input").dispatchEvent(inputEvent); } diff --git a/site/utils.js b/site/utils.js index be9cc4d..932101c 100644 --- a/site/utils.js +++ b/site/utils.js @@ -486,7 +486,7 @@ function newSearchComponent(parentElement, items, searched, filter, headerModifi now = performance.now(); let num = 0; - let limit = isMobile() ? 500 : 2000; + let limit = 500; // isMobile() ? 500 : 2000; hits.every(hit => { let itemDom = itemToDOM(hit); if (itemDomModifier) itemDom = itemDomModifier(hit, itemDom, hits, setQuery); @@ -499,19 +499,23 @@ function newSearchComponent(parentElement, items, searched, filter, headerModifi lastHits = hits; } + let timeoutId; searchInput.addEventListener("input", (event) => { - const query = searchInput.value.trim(); - if (query == 0) { - minPrice.value = 0; - maxPrice.value = 100; - } - if (query?.charAt(0) == "!") { - parentElement.querySelectorAll(".filters").forEach(f => f.style.display = "none"); - } else { - parentElement.querySelectorAll(".filters").forEach(f => f.style.display = "block"); - } - setQuery(); - search(searchInput.value); + clearTimeout(timeoutId); + timeoutId = setTimeout(() => { + const query = searchInput.value.trim(); + if (query == 0) { + minPrice.value = 0; + maxPrice.value = 100; + } + if (query?.charAt(0) == "!") { + parentElement.querySelectorAll(".filters").forEach(f => f.style.display = "none"); + } else { + parentElement.querySelectorAll(".filters").forEach(f => f.style.display = "block"); + } + setQuery(); + search(searchInput.value); + }, 50); }); budgetBrands.addEventListener("change", () => search(searchInput.value)); bio.addEventListener("change", () => search(searchInput.value)); @@ -587,13 +591,21 @@ function showChart(canvasDom, items, chartType) { document.documentElement.scrollTop = scrollTop; } -function showCharts(canvasDom, items, sum, sumStores, todayOnly) { +function getOldestDate(items) { + let oldestDate = "9999-01-01"; + for (item of items) { + if (oldestDate > item.dateOldest) oldestDate = item.dateOldest; + } + return oldestDate; +} + +function showCharts(canvasDom, items, sum, sumStores, todayOnly, startDate, endDate) { let itemsToShow = []; if (sum && items.length > 0) { itemsToShow.push({ name: "Preissumme Warenkorb", - priceHistory: calculateOverallPriceChanges(items, todayOnly) + priceHistory: calculateOverallPriceChanges(items, todayOnly, startDate, endDate) }); } @@ -603,20 +615,27 @@ function showCharts(canvasDom, items, sum, sumStores, todayOnly) { if (storeItems.length > 0) { itemsToShow.push({ name: "Preissumme " + store, - priceHistory: calculateOverallPriceChanges(storeItems, todayOnly) + priceHistory: calculateOverallPriceChanges(storeItems, todayOnly, startDate, endDate) }); } }); } items.forEach((item) => { - if (item.chart) itemsToShow.push({ name: item.store + " " + item.name, priceHistory: todayOnly ? [{date: currentDate(), price: item.price}] : item.priceHistory}); + if (item.chart) { + itemsToShow.push({ + name: item.store + " " + item.name, + priceHistory: todayOnly ? + [{ date: currentDate(), price: item.price }] : + item.priceHistory.filter(price => price.date >= startDate && price.date <= endDate) + }); + } }); showChart(canvasDom, itemsToShow, todayOnly ? "bar" : "line"); } -function calculateOverallPriceChanges(items, todayOnly) { +function calculateOverallPriceChanges(items, todayOnly, startDate, endDate) { if (items.length == 0) return { dates: [], changes: [] }; if (todayOnly) { @@ -626,8 +645,9 @@ function calculateOverallPriceChanges(items, todayOnly) { } const allDates = items.flatMap(product => product.priceHistory.map(item => item.date)); - const uniqueDates = [...new Set(allDates)]; + let uniqueDates = [...new Set(allDates)]; uniqueDates.sort(); + uniqueDates = uniqueDates.filter(date => date >= startDate && date <= endDate); const allPrices = items.map(product => { let price = null;