mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-07-29 19:21:33 -07:00
fix(stats): show all titles in trend progress charts instead of top 7
The stacked Library-Cumulative charts silently dropped every title outside the top 7 by total value, while the Title Visibility filter listed all of them and promised 'Default: show everything'. Render every series and rely on the visibility chips to declutter.
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { buildLineData, type PerAnimeDataPoint } from './StackedTrendChart';
|
||||
|
||||
function makePoints(titleCount: number): PerAnimeDataPoint[] {
|
||||
const points: PerAnimeDataPoint[] = [];
|
||||
for (let i = 0; i < titleCount; i += 1) {
|
||||
points.push({ epochDay: 20_000 + i, animeTitle: `Title ${i}`, value: titleCount - i });
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
test('buildLineData keeps every title as a series instead of capping at the top 7', () => {
|
||||
const { points, seriesKeys } = buildLineData(makePoints(17));
|
||||
|
||||
assert.equal(seriesKeys.length, 17);
|
||||
assert.ok(seriesKeys.includes('Title 16'));
|
||||
for (const row of points) {
|
||||
for (const key of seriesKeys) {
|
||||
assert.ok(key in row);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('buildLineData orders series by total value descending', () => {
|
||||
const { seriesKeys } = buildLineData([
|
||||
{ epochDay: 20_000, animeTitle: 'Small', value: 1 },
|
||||
{ epochDay: 20_000, animeTitle: 'Big', value: 10 },
|
||||
{ epochDay: 20_001, animeTitle: 'Medium', value: 5 },
|
||||
]);
|
||||
|
||||
assert.deepEqual(seriesKeys, ['Big', 'Medium', 'Small']);
|
||||
});
|
||||
@@ -33,19 +33,18 @@ const DEFAULT_LINE_COLORS = [
|
||||
'#f4dbd6',
|
||||
];
|
||||
|
||||
function buildLineData(raw: PerAnimeDataPoint[]) {
|
||||
export function buildLineData(raw: PerAnimeDataPoint[]) {
|
||||
const totalByAnime = new Map<string, number>();
|
||||
for (const entry of raw) {
|
||||
totalByAnime.set(entry.animeTitle, (totalByAnime.get(entry.animeTitle) ?? 0) + entry.value);
|
||||
}
|
||||
|
||||
const sorted = [...totalByAnime.entries()].sort((a, b) => b[1] - a[1]);
|
||||
const topTitles = sorted.slice(0, 7).map(([title]) => title);
|
||||
const topSet = new Set(topTitles);
|
||||
const seriesKeys = [...totalByAnime.entries()]
|
||||
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
||||
.map(([title]) => title);
|
||||
|
||||
const byDay = new Map<number, Record<string, number>>();
|
||||
for (const entry of raw) {
|
||||
if (!topSet.has(entry.animeTitle)) continue;
|
||||
const row = byDay.get(entry.epochDay) ?? {};
|
||||
row[entry.animeTitle] = (row[entry.animeTitle] ?? 0) + Math.round(entry.value * 10) / 10;
|
||||
byDay.set(entry.epochDay, row);
|
||||
@@ -60,13 +59,13 @@ function buildLineData(raw: PerAnimeDataPoint[]) {
|
||||
day: 'numeric',
|
||||
}),
|
||||
};
|
||||
for (const title of topTitles) {
|
||||
for (const title of seriesKeys) {
|
||||
row[title] = values[title] ?? 0;
|
||||
}
|
||||
return row;
|
||||
});
|
||||
|
||||
return { points, seriesKeys: topTitles };
|
||||
return { points, seriesKeys };
|
||||
}
|
||||
|
||||
export function StackedTrendChart({ title, data, colorPalette }: StackedTrendChartProps) {
|
||||
|
||||
Reference in New Issue
Block a user