mirror of
https://github.com/PhaseII-eAmusement-Network/PhaseWeb3-Vue.git
synced 2026-09-14 04:05:18 -05:00
ddr: improved statistics graph (#13)
This commit is contained in:
@@ -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}` : ""}`;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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 ${
|
||||
|
||||
Reference in New Issue
Block a user