aboutsummaryrefslogtreecommitdiffhomepage
path: root/services/app/assets/chart.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/app/assets/chart.js')
-rw-r--r--services/app/assets/chart.js73
1 files changed, 68 insertions, 5 deletions
diff --git a/services/app/assets/chart.js b/services/app/assets/chart.js
index 5873080..9ff08e4 100644
--- a/services/app/assets/chart.js
+++ b/services/app/assets/chart.js
@@ -42,14 +42,63 @@ document.addEventListener('DOMContentLoaded', async () => {
s.scores = bestScores;
}
+ const scoresInChronologicalOrder = stats
+ .flatMap(s => s.scores.map(score => ({ ...score, user: s.user })))
+ .toSorted((a, b) => a.submitted_at - b.submitted_at);
+
+ const scoresAndRanksAtEachTime = (() => {
+ const result = [];
+ const currentScoresForUser = new Map();
+ for (const { user, submitted_at, code_size } of scoresInChronologicalOrder) {
+ currentScoresForUser.set(user.name, { user, submitted_at, code_size });
+ const ranking = currentScoresForUser
+ .values()
+ .toArray()
+ .toSorted(
+ (a, b) => a.code_size === b.code_size ? a.submitted_at - b.submitted_at : a.code_size - b.code_size,
+ );
+ const scores = new Map();
+ for (const [i, { user, code_size }] of ranking.entries()) {
+ scores.set(user.name, {
+ user,
+ code_size,
+ rank: i + 1,
+ });
+ }
+ result.push({ submitted_at: submitted_at, scores });
+ }
+ return result;
+ })();
+
+ const rankingHistory = (() => {
+ const result = new Map();
+ for (const { submitted_at, scores } of scoresAndRanksAtEachTime) {
+ for (const [username, { user, code_size, rank }] of scores.entries()) {
+ if (!result.has(username)) {
+ result.set(username, []);
+ }
+ const scores = result.get(username);
+ scores.push({ user, code_size, rank, submitted_at });
+ }
+ }
+ return result
+ .values()
+ .toArray()
+ .toSorted((a, b) => {
+ const finalRankA = a[a.length - 1].rank;
+ const finalRankB = b[b.length - 1].rank;
+ return finalRankA - finalRankB;
+ });
+ })();
+
new Chart(
chartCanvas,
{
type: 'line',
data: {
- datasets: stats.map(s => ({
- label: `${s.user.name}${s.user.is_admin ? ' (staff)' : ''}`,
- data: s.scores.map(row => ({ x: row.submitted_at * 1000, y: row.code_size })),
+ datasets: rankingHistory.map(s => ({
+ label: `${s[0].user.name}${s[0].user.is_admin ? ' (staff)' : ''}`,
+ data: s.map(row => ({ x: row.submitted_at * 1000, y: row.rank, code_size: row.code_size })),
}))
},
options: {
@@ -67,13 +116,27 @@ document.addEventListener('DOMContentLoaded', async () => {
},
title: {
display: true,
- text: '提出日時',
+ text: '日時',
},
},
y: {
title: {
display: true,
- text: 'コードサイズ (byte)',
+ text: '順位',
+ },
+ reverse: true,
+ min: 1,
+ offset: true,
+ },
+ },
+ plugins: {
+ tooltip: {
+ callbacks: {
+ label: (context) => {
+ const label = context.dataset.label;
+ const code_size = context.raw.code_size;
+ return `${label} (${code_size} byte)`;
+ },
},
},
},