Leaderboard: Implement simple points cumsum chart
All checks were successful
Build Formula11 Docker Image / pocketbase-docker (push) Successful in 1m3s
All checks were successful
Build Formula11 Docker Image / pocketbase-docker (push) Successful in 1m3s
This commit is contained in:
@ -1,10 +1,28 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Table, type TableColumn } from "$lib/components";
|
import { Table, type TableColumn } from "$lib/components";
|
||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value } from "$lib/database";
|
||||||
|
import type { RacePickPoints, RacePickPointsAcc, User } from "$lib/schema";
|
||||||
import type { PageData } from "./$types";
|
import type { PageData } from "./$types";
|
||||||
|
import {
|
||||||
|
LineChart,
|
||||||
|
ScaleTypes,
|
||||||
|
type ChartTabularData,
|
||||||
|
type LineChartOptions,
|
||||||
|
} from "@carbon/charts-svelte";
|
||||||
|
import "@carbon/charts-svelte/styles.css";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
|
// Await promises
|
||||||
|
let users: User[] | undefined = $state(undefined);
|
||||||
|
data.users.then((u: User[]) => (users = u));
|
||||||
|
|
||||||
|
let racepickpoints: RacePickPoints[] | undefined = $state(undefined);
|
||||||
|
data.racepickpoints.then((r: RacePickPoints[]) => (racepickpoints = r));
|
||||||
|
|
||||||
|
let racepickpointsacc: RacePickPointsAcc[] | undefined = $state(undefined);
|
||||||
|
data.racepickpointsacc.then((r: RacePickPointsAcc[]) => (racepickpointsacc = r));
|
||||||
|
|
||||||
const leaderboard_columns: TableColumn[] = $derived([
|
const leaderboard_columns: TableColumn[] = $derived([
|
||||||
{
|
{
|
||||||
data_value_name: "user",
|
data_value_name: "user",
|
||||||
@ -14,15 +32,124 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
data_value_name: "total_points",
|
data_value_name: "total_points",
|
||||||
label: "Points",
|
label: "Total",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data_value_name: "total_pxx_points",
|
||||||
|
label: "PXX",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data_value_name: "total_dnf_points",
|
||||||
|
label: "DNF",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data_value_name: "total_points_per_pick",
|
||||||
|
label: "Per Pick",
|
||||||
|
valuefun: async (value: string): Promise<string> => Number.parseFloat(value).toFixed(2),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const points_chart_data: ChartTabularData = $derived.by(() => {
|
||||||
|
if (!users || !racepickpointsacc) return [];
|
||||||
|
|
||||||
|
return users
|
||||||
|
.map((user: User) => {
|
||||||
|
return {
|
||||||
|
group: user.firstname,
|
||||||
|
step: "0",
|
||||||
|
points: 0,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.concat(
|
||||||
|
racepickpointsacc.map((points: RacePickPointsAcc) => {
|
||||||
|
return {
|
||||||
|
group: get_by_value(users ?? [], "id", points.user)?.firstname || "INVALID",
|
||||||
|
step: points.step.toString(),
|
||||||
|
points: points.acc_points,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const points_chart_options: LineChartOptions = {
|
||||||
|
title: "I ❤️ CumSum",
|
||||||
|
axes: {
|
||||||
|
bottom: {
|
||||||
|
mapsTo: "step",
|
||||||
|
scaleType: ScaleTypes.LABELS,
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
mapsTo: "points",
|
||||||
|
scaleType: ScaleTypes.LINEAR,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
curve: "curveMonotoneX",
|
||||||
|
// toolbar: {
|
||||||
|
// enabled: false,
|
||||||
|
// },
|
||||||
|
animations: true,
|
||||||
|
// canvasZoom: {
|
||||||
|
// enabled: false,
|
||||||
|
// },
|
||||||
|
grid: {
|
||||||
|
x: {
|
||||||
|
enabled: true,
|
||||||
|
alignWithAxisTicks: true,
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
enabled: true,
|
||||||
|
alignWithAxisTicks: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
enabled: true,
|
||||||
|
clickable: true,
|
||||||
|
position: "top",
|
||||||
|
},
|
||||||
|
points: {
|
||||||
|
enabled: true,
|
||||||
|
radius: 5,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
showTotal: false,
|
||||||
|
},
|
||||||
|
resizable: true,
|
||||||
|
width: "100%",
|
||||||
|
height: "400px",
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>Formula 11 - Leaderboard</title>
|
<title>Formula 11 - Leaderboard</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
{#await Promise.all( [data.users, data.racepickpoints, data.racepickpointsacc], ) then [users, racepickpoints, racepickpointsacc]}
|
{#await Promise.all( [data.users, data.racepickpoints, data.racepickpointsacc, data.racepickpointstotal], ) then [users, racepickpoints, racepickpointsacc, racepickpointstotal]}
|
||||||
<Table data={racepickpointsacc} columns={leaderboard_columns} />
|
<div class="flex gap-2">
|
||||||
|
<!-- Podium -->
|
||||||
|
<!-- <div class="card w-60 bg-surface-100 p-2 shadow"> -->
|
||||||
|
<!-- <div class="flex h-20 w-full gap-1"></div> -->
|
||||||
|
<!-- <div class="flex h-20 w-full gap-1"> -->
|
||||||
|
<!-- <div class="w-20"> -->
|
||||||
|
<!-- <div class="h-[30%] w-full"></div> -->
|
||||||
|
<!-- <div class="h-[70%] w-full bg-surface-500"></div> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
<!-- <div class="w-20"> -->
|
||||||
|
<!-- <div class="h-[100%] w-full bg-surface-500"></div> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
<!-- <div class="w-20"> -->
|
||||||
|
<!-- <div class="h-[60%] w-full"></div> -->
|
||||||
|
<!-- <div class="h-[40%] w-full bg-surface-600"></div> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
|
||||||
|
<!-- Points chart -->
|
||||||
|
<div class="card w-full bg-surface-100 p-2 shadow">
|
||||||
|
<LineChart data={points_chart_data} options={points_chart_options} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-2">
|
||||||
|
<Table data={racepickpointstotal} columns={leaderboard_columns} />
|
||||||
|
</div>
|
||||||
{/await}
|
{/await}
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import { fetch_users, fetch_racepickpoints, fetch_racepickpointsacc } from "$lib/fetch";
|
import {
|
||||||
|
fetch_users,
|
||||||
|
fetch_racepickpoints,
|
||||||
|
fetch_racepickpointsacc,
|
||||||
|
fetch_racepickpointstotal,
|
||||||
|
} from "$lib/fetch";
|
||||||
import type { PageLoad } from "../$types";
|
import type { PageLoad } from "../$types";
|
||||||
|
|
||||||
export const load: PageLoad = async ({ fetch, depends }) => {
|
export const load: PageLoad = async ({ fetch, depends }) => {
|
||||||
@ -8,5 +13,6 @@ export const load: PageLoad = async ({ fetch, depends }) => {
|
|||||||
users: fetch_users(fetch),
|
users: fetch_users(fetch),
|
||||||
racepickpoints: fetch_racepickpoints(fetch),
|
racepickpoints: fetch_racepickpoints(fetch),
|
||||||
racepickpointsacc: fetch_racepickpointsacc(fetch),
|
racepickpointsacc: fetch_racepickpointsacc(fetch),
|
||||||
|
racepickpointstotal: fetch_racepickpointstotal(fetch),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user