Files
buildpath/frontend/components/tierlist/Chart.vue
T
vhaudiquet e6ddc27d5c
pipeline / lint-and-format (push) Successful in 4m17s
pipeline / build-and-push-images (push) Successful in 2m4s
feat/frontend: center winrates arround 50% and add graph title
2026-06-27 11:53:16 +02:00

129 lines
3.0 KiB
Vue

<script lang="ts" setup>
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
BarElement,
CategoryScale,
LinearScale
} from 'chart.js'
import { Bar } from 'vue-chartjs'
import type { Champion } from '~/types/cdragon'
import type { LaneData } from 'match_collector'
// Register
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
const props = withDefaults(
defineProps<{
data: Array<{ title: string; data: Array<{ lane: LaneData; champion: Champion }> }>
metric?: 'pickrate' | 'winrate'
}>(),
{
metric: 'pickrate'
}
)
const labels: Array<string> = []
const values: Array<number> = []
const images: Array<string> = []
const backgroundColors: Array<string> = []
const CHAMPION_CUT_THRESHOLD = 32
const TIER_COLORS = ['#ff7f7e', '#ffbf7f', '#ffdf80', '#feff7f', '#beff7f', '#7eff80']
let count = 0
let colorIndex = 0
for (const tier of props.data) {
for (const { champion: champion, lane: lane } of tier.data) {
if (count > CHAMPION_CUT_THRESHOLD) break
labels.push(champion.name)
values.push(lane[props.metric] * 100)
images.push(CDRAGON_BASE + mapPath(champion.squarePortraitPath))
backgroundColors.push(TIER_COLORS[colorIndex])
count++
}
colorIndex++
}
const chartData = ref({
labels: labels,
datasets: [
{
label: props.metric === 'pickrate' ? 'Pickrate' : 'Winrate',
backgroundColor: backgroundColors,
barPercentage: 1.0,
data: values
}
]
})
const chartOptions = ref({
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
ticks: {
callback: () => ''
}
},
y: {
title: {
display: true,
text: props.metric === 'winrate' ? 'Winrate (%)' : 'Pickrate (%)'
},
...(props.metric === 'winrate'
? {
min: 40,
max: 60,
grid: {
color: (context: { tick: { value: number } }) =>
context.tick.value === 50 ? '#666' : 'rgba(0, 0, 0, 0.1)',
lineWidth: (context: { tick: { value: number } }) =>
context.tick.value === 50 ? 2 : 1
}
}
: {})
}
},
plugins: {
legend: {
display: false
}
}
})
const chartPlugins = [
{
id: 'image-draw',
afterDraw: (chart: unknown) => {
const ctx: CanvasRenderingContext2D = (chart as { ctx: CanvasRenderingContext2D }).ctx
const xAxis = (
chart as {
scales: {
x: {
ticks: Array<unknown>
getPixelForTick: (_index: number) => number
bottom: number
}
}
}
).scales.x
xAxis.ticks.forEach((value: unknown, index: number) => {
const x = xAxis.getPixelForTick(index)
const image = new Image()
image.src = images[index]
ctx.drawImage(image, x - 14, xAxis.bottom - 28, 28, 28)
})
}
}
]
</script>
<template>
<div>
<Bar :data="chartData" :options="chartOptions" :plugins="chartPlugins" />
</div>
</template>