ddr: improved statistics graph (#13)

This commit is contained in:
archibun
2026-07-26 05:54:59 -07:00
committed by GitHub
parent 4d8519d122
commit a893c83535
4 changed files with 91 additions and 20 deletions

View File

@@ -26,10 +26,6 @@ ChartJS.register(
);
const props = defineProps({
profile: {
type: String,
default: null,
},
game: {
type: String,
default: null,
@@ -43,16 +39,6 @@ const props = defineProps({
},
});
const userProfile = ref(props.profile);
const version = ref(props.version);
watch(
() => props.version,
() => {
userProfile.value = props.profile;
version.value = props.version;
},
);
const groups = [
0, 700_000, 800_000, 850_000, 900_000, 950_000, 970_000, 980_000, 990_000,
995_000, 999_000, 999_910, 1_000_000,
@@ -91,12 +77,20 @@ const chartData = ref({
backgroundColor: colorGroups,
borderColor: "rgba(22, 95, 250, 0.5)",
data: [],
parsing: {
yAxisKey: "total",
xAxisKey: "total",
},
},
{
label: "0",
backgroundColor: colorGroups,
borderColor: "rgba(250, 170, 22, 0.5)",
data: [],
parsing: {
yAxisKey: "total",
xAxisKey: "total",
},
},
],
});
@@ -123,6 +117,17 @@ const chartOptions = {
label: function (ctx) {
return `level ${ctx.dataset.label}: ${ctx.parsed.y} scores`;
},
footer: function (ctx) {
const best = ctx[0].raw.best;
if (best.length < 1) return "";
let list = `Top ${best.length}:`;
for (const [index, { song, chart }] of best.entries()) {
const chartType = gameInfo.shortChartTable[chart.chart];
list += `\n${index + 1}. ${song} (${chartType}${chart.data.difficulty} - ${chart.record.points.toLocaleString()})`;
}
return list;
},
},
},
},
@@ -153,12 +158,15 @@ const statsTemplate = {
};
function onRangeUpdate(index, scores, stats) {
return (value) => {
const data = new Array(groups.length).fill(0);
const data = Array.from({ length: groups.length }, () => ({
total: 0,
best: [],
}));
const [min, max] = value;
const allPoints = [];
stats.value = { ...statsTemplate };
for (const { chart } of scores) {
for (const { song, chart } of scores) {
const record = chart.record;
const difficulty = chart.data.difficulty;
@@ -167,7 +175,8 @@ function onRangeUpdate(index, scores, stats) {
for (const [index, minimum] of groups.entries()) {
if (record.points >= minimum) targetIndex = index;
}
data[targetIndex]++;
data[targetIndex].total++;
data[targetIndex].best.push({ song: song.name, chart });
allPoints.push(record.points);
const halo = gameInfo.haloTable[record.data.halo];
@@ -197,6 +206,16 @@ function onRangeUpdate(index, scores, stats) {
: (allPoints[middle - 1] + allPoints[middle]) / 2;
}
for (const item of data) {
item.best = item.best
.sort((a, b) => {
const points = b.chart.record.points - a.chart.record.points;
if (points !== 0) return points;
return b.chart.data.difficulty - a.chart.data.difficulty;
})
.slice(0, 5);
}
chartData.value.datasets[index].data = data;
chartData.value.datasets[index].label =
`${min}${min !== max ? `-${max}` : ""}`;

View File

@@ -541,6 +541,18 @@ export const gameData = [
8: "DP EXPERT",
9: "DP CHALLENGE",
},
shortChartTable: {
0: "bSP",
1: "BSP",
2: "DSP",
3: "ESP",
4: "CSP",
5: "bDP",
6: "BDP",
7: "EDP",
8: "EDP",
9: "CDP",
},
haloTable: {
100: "",
1000: "FAILED",
@@ -810,6 +822,18 @@ export const gameData = [
8: "DP EXPERT",
9: "DP CHALLENGE",
},
shortChartTable: {
0: "bSP",
1: "BSP",
2: "DSP",
3: "ESP",
4: "CSP",
5: "bDP",
6: "BDP",
7: "EDP",
8: "EDP",
9: "CDP",
},
haloTable: {
100: "",
1000: "FAILED",

View File

@@ -1,7 +1,7 @@
<script setup>
import { ref, onMounted, reactive, computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { PhRanking } from "@phosphor-icons/vue";
import { PhRanking, PhChartBar } from "@phosphor-icons/vue";
import SectionMain from "@/components/SectionMain.vue";
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
import SectionTitleLine from "@/components/SectionTitleLine.vue";
@@ -11,7 +11,8 @@ import BaseButton from "@/components/BaseButton.vue";
import GameHeader from "@/components/Cards/GameHeader.vue";
import { APIGetRecordData } from "@/stores/api/music";
import { getGameInfo } from "@/constants";
import { GameConstants, getGameInfo } from "@/constants";
import UserDdrStatistics from "@/components/Charts/UserDdrStatistics.vue";
import {
shouldRenderChart,
formatDifficulty,
@@ -73,6 +74,28 @@ const filteredSongs = computed(() => {
<LayoutAuthenticated>
<SectionMain v-if="songData">
<GameHeader :game="thisGame" />
<template
v-if="
[GameConstants.DDR, GameConstants.DDROMNI].includes(thisGame.id) &&
songData.length > 0
"
>
<SectionTitleLine
:icon="PhChartBar"
:title="`Overall Network ${
thisGame.shortName ? thisGame.shortName : thisGame.name
} Statistics`"
main
class="mt-6"
/>
<UserDdrStatistics
:game="thisGame.id"
:version="versionForm.currentVersion"
:scores="songData"
/>
</template>
<SectionTitleLine :icon="PhRanking" title="Top Records" main>
<template v-if="thisGame.versions">
<div class="md:w-1/3 md:text-right">

View File

@@ -123,7 +123,12 @@ const songsWithRecords = computed(() => {
/>
</div>
<template v-if="thisGame.id == GameConstants.DDR && songData">
<template
v-if="
[GameConstants.DDR, GameConstants.DDROMNI].includes(thisGame.id) &&
songData.length > 0
"
>
<SectionTitleLine
:icon="PhChartBar"
:title="`${myProfile.username}'s Overall ${