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 };
|
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),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue