UX Improvements

This commit is contained in:
Brennan Wilkes (Text Groove) 2026-02-02 22:08:49 -08:00
parent 930e030013
commit cf0a711c93
2 changed files with 65 additions and 19 deletions

View file

@ -102,6 +102,14 @@ function findMinPricesForSkuGroupInDb(obj, wantRealSkus, skuKeys, storeLabel) {
return { liveMin, removedMin }; return { liveMin, removedMin };
} }
function lastFiniteFromEnd(arr) {
if (!Array.isArray(arr)) return null;
for (let i = arr.length - 1; i >= 0; i--) {
const v = arr[i];
if (Number.isFinite(v)) return v;
}
return null;
}
function computeSuggestedY(values, minRange) { function computeSuggestedY(values, minRange) {
const nums = values.filter((v) => Number.isFinite(v)); const nums = values.filter((v) => Number.isFinite(v));
@ -665,22 +673,41 @@ export async function renderItem($app, skuInput) {
const span = (ySug.suggestedMax ?? 0) - (ySug.suggestedMin ?? 0); const span = (ySug.suggestedMax ?? 0) - (ySug.suggestedMin ?? 0);
const step = niceStepAtLeast(MIN_STEP, span, MAX_TICKS); const step = niceStepAtLeast(MIN_STEP, span, MAX_TICKS);
const colorMap = buildStoreColorMap(series.map((s) => s.label));
const datasets = series.map((s) => { const todayKey = today; // you already computed this earlier
const labelsLen = labels.length;
const seriesSorted = series
.map((s) => {
const todayVal = s.points.has(todayKey) ? s.points.get(todayKey) : null;
const lastVal = todayVal !== null ? todayVal : lastFiniteFromEnd(labels.map((d) => s.points.get(d)));
return { s, v: Number.isFinite(lastVal) ? lastVal : null };
})
.sort((a, b) => {
const av = a.v, bv = b.v;
if (av === null && bv === null) return a.s.label.localeCompare(b.s.label);
if (av === null) return 1;
if (bv === null) return -1;
if (av !== bv) return av - bv;
return a.s.label.localeCompare(b.s.label);
})
.map((x) => x.s);
const colorMap = buildStoreColorMap(seriesSorted.map((s) => s.label));
const datasets = seriesSorted.map((s) => {
const base = storeColor(s.label, colorMap); const base = storeColor(s.label, colorMap);
const stroke = lighten(base, 0.25); const stroke = lighten(base, 0.25);
return { return {
label: s.label, label: s.label,
data: labels.map((d) => (s.points.has(d) ? s.points.get(d) : null)), data: labels.map((d) => (s.points.has(d) ? s.points.get(d) : null)),
spanGaps: false, spanGaps: false,
tension: 0.15, tension: 0.15,
backgroundColor: base, backgroundColor: base,
borderColor: stroke, borderColor: stroke,
pointBackgroundColor: base, pointBackgroundColor: base,
pointBorderColor: stroke, pointBorderColor: stroke,
borderWidth: datasetStrokeWidth(base),
}; };
}); });

View file

@ -686,32 +686,51 @@ export async function renderStats($app) {
return { q, minP, maxP }; return { q, minP, maxP };
} }
function lastFiniteFromEnd(arr) {
if (!Array.isArray(arr)) return null;
for (let i = arr.length - 1; i >= 0; i--) {
const v = arr[i];
if (Number.isFinite(v)) return v;
}
return null;
}
async function drawOrUpdateChart(series, yBounds) { async function drawOrUpdateChart(series, yBounds) {
const { labels, stores, seriesByStore } = series; const { labels, stores, seriesByStore } = series;
const Chart = await ensureChartJs(); const Chart = await ensureChartJs();
const canvas = document.getElementById("statsChart"); const canvas = document.getElementById("statsChart");
if (!canvas) return; if (!canvas) return;
const colorMap = buildStoreColorMap(stores);
const datasets = stores.map((s) => { const order = stores
.map((s) => ({ s, v: lastFiniteFromEnd(seriesByStore[s]) }))
.sort((a, b) => {
const av = a.v, bv = b.v;
if (av === null && bv === null) return displayStoreName(a.s).localeCompare(displayStoreName(b.s));
if (av === null) return 1;
if (bv === null) return -1;
if (av !== bv) return av - bv; // cheapest (lowest index) first
return displayStoreName(a.s).localeCompare(displayStoreName(b.s));
})
.map((x) => x.s);
const colorMap = buildStoreColorMap(order);
const datasets = order.map((s) => {
const base = storeColor(s, colorMap); const base = storeColor(s, colorMap);
const stroke = lighten(base, 0.25); const stroke = lighten(base, 0.25);
return { return {
label: displayStoreName(s), label: displayStoreName(s),
data: Array.isArray(seriesByStore[s]) ? seriesByStore[s] : labels.map(() => null), data: Array.isArray(seriesByStore[s]) ? seriesByStore[s] : labels.map(() => null),
spanGaps: false, spanGaps: false,
tension: 0.15, tension: 0.15,
backgroundColor: base,
backgroundColor: base, borderColor: stroke,
borderColor: stroke, pointBackgroundColor: base,
pointBackgroundColor: base, pointBorderColor: stroke,
pointBorderColor: stroke,
}; };
}); });
if (_chart) { if (_chart) {
_chart.data.labels = labels; _chart.data.labels = labels;
_chart.data.datasets = datasets; _chart.data.datasets = datasets;