mirror of
https://github.com/samsonjs/spirit-tracker.git
synced 2026-03-25 09:25:51 +00:00
UX Improvements
This commit is contained in:
parent
930e030013
commit
cf0a711c93
2 changed files with 65 additions and 19 deletions
|
|
@ -102,6 +102,14 @@ function findMinPricesForSkuGroupInDb(obj, wantRealSkus, skuKeys, storeLabel) {
|
|||
|
||||
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) {
|
||||
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 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 stroke = lighten(base, 0.25);
|
||||
|
||||
return {
|
||||
label: s.label,
|
||||
data: labels.map((d) => (s.points.has(d) ? s.points.get(d) : null)),
|
||||
spanGaps: false,
|
||||
tension: 0.15,
|
||||
|
||||
backgroundColor: base,
|
||||
borderColor: stroke,
|
||||
pointBackgroundColor: base,
|
||||
pointBorderColor: stroke,
|
||||
borderWidth: datasetStrokeWidth(base),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -686,32 +686,51 @@ export async function renderStats($app) {
|
|||
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) {
|
||||
const { labels, stores, seriesByStore } = series;
|
||||
|
||||
const Chart = await ensureChartJs();
|
||||
const canvas = document.getElementById("statsChart");
|
||||
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 stroke = lighten(base, 0.25);
|
||||
|
||||
return {
|
||||
label: displayStoreName(s),
|
||||
data: Array.isArray(seriesByStore[s]) ? seriesByStore[s] : labels.map(() => null),
|
||||
spanGaps: false,
|
||||
tension: 0.15,
|
||||
|
||||
backgroundColor: base,
|
||||
borderColor: stroke,
|
||||
pointBackgroundColor: base,
|
||||
pointBorderColor: stroke,
|
||||
label: displayStoreName(s),
|
||||
data: Array.isArray(seriesByStore[s]) ? seriesByStore[s] : labels.map(() => null),
|
||||
spanGaps: false,
|
||||
tension: 0.15,
|
||||
backgroundColor: base,
|
||||
borderColor: stroke,
|
||||
pointBackgroundColor: base,
|
||||
pointBorderColor: stroke,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
if (_chart) {
|
||||
_chart.data.labels = labels;
|
||||
_chart.data.datasets = datasets;
|
||||
|
|
|
|||
Loading…
Reference in a new issue