merge gamemode and weapon into one reusable component
This commit is contained in:
@@ -11,37 +11,46 @@ import dataLabel from 'chartjs-plugin-datalabels'
|
|||||||
import { Weapon, Filter, useKillStore } from '@/stores/kill'
|
import { Weapon, Filter, useKillStore } from '@/stores/kill'
|
||||||
import { Doughnut } from 'vue-chartjs'
|
import { Doughnut } from 'vue-chartjs'
|
||||||
import { defineComponent, PropType, Ref, unref } from 'vue'
|
import { defineComponent, PropType, Ref, unref } from 'vue'
|
||||||
import gamemodes from '../stores/gamemodes.json'
|
|
||||||
|
|
||||||
import LoadingBar from './LoadingBar.vue'
|
import LoadingBar from './LoadingBar.vue'
|
||||||
|
|
||||||
ChartJS.register(ArcElement, Tooltip, Legend, dataLabel)
|
ChartJS.register(ArcElement, Tooltip, Legend, dataLabel)
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'GamemodeChart',
|
name: 'PieChart',
|
||||||
props: {
|
props: {
|
||||||
filters: Object as PropType<Filter>,
|
filters: Object as PropType<Filter>,
|
||||||
playerHighlighted: String
|
playerHighlighted: String,
|
||||||
|
type: Object as PropType<'server' | 'player' | 'weapon' | 'map' | 'gamemode'>
|
||||||
},
|
},
|
||||||
emits: ['highlightPlayer'],
|
emits: ['highlightPlayer'],
|
||||||
components: {
|
components: {
|
||||||
Doughnut, LoadingBar
|
Doughnut, LoadingBar
|
||||||
},
|
},
|
||||||
|
created () {
|
||||||
|
// eslint-disable-next-line no-extra-bind
|
||||||
|
import(`../stores/${this.type}s.json`).then((e => { this.locale = e }).bind(this))
|
||||||
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.refreshColors++
|
this.refreshColors++
|
||||||
},
|
},
|
||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
store: useKillStore(),
|
store: useKillStore(),
|
||||||
refreshColors: 0
|
refreshColors: 0,
|
||||||
|
locale: {} as {[key:string]:string}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
progress () {
|
progress () {
|
||||||
const filter = new Filter(this.filters)
|
const filter = new Filter(this.filters)
|
||||||
delete filter.gamemode
|
if (this.type === undefined) return 0
|
||||||
const data = this.store.getList('gamemodes', filter)?.value
|
if (!(['server', 'player', 'weapon', 'map', 'gamemode'].includes(this.type))) return 0
|
||||||
if (!data) return this.store.fetch('gamemodes', filter).value.progress.value
|
const type = this.type as 'server' | 'player' | 'weapon' | 'map' | 'gamemode'
|
||||||
|
|
||||||
|
if (this.type !== undefined) delete filter[type]
|
||||||
|
const data = this.store.getList(`${type}s`, filter)?.value
|
||||||
|
if (!data) return this.store.fetch(`${type}s`, filter).value.progress.value
|
||||||
return data.progress.value
|
return data.progress.value
|
||||||
},
|
},
|
||||||
colors () {
|
colors () {
|
||||||
@@ -112,8 +121,7 @@ export default defineComponent({
|
|||||||
datalabels: {
|
datalabels: {
|
||||||
formatter: (value, context) => {
|
formatter: (value, context) => {
|
||||||
const weaponId = this.sortedList[context.dataIndex]
|
const weaponId = this.sortedList[context.dataIndex]
|
||||||
// if (!(weapons as {[key:string]:string})[weaponId]) console.log(weaponId)
|
return this.locale[weaponId] || weaponId
|
||||||
return (gamemodes as { [key: string]: string })[weaponId] || weaponId
|
|
||||||
},
|
},
|
||||||
backgroundColor: (context) => {
|
backgroundColor: (context) => {
|
||||||
return context.dataset.backgroundColor(context, options)
|
return context.dataset.backgroundColor(context, options)
|
||||||
@@ -149,9 +157,11 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
values (): { [key: string]: Ref<Weapon> } {
|
values (): { [key: string]: Ref<Weapon> } {
|
||||||
const filter = new Filter({ ...this.filters, player: this.playerHighlighted })
|
const filter = new Filter({ ...this.filters, player: this.playerHighlighted })
|
||||||
delete filter.gamemode
|
if (this.type === undefined) return {}
|
||||||
const data = this.store.getList('gamemodes', filter)?.value.data
|
if (!(['server', 'player', 'weapon', 'map', 'gamemode'].includes(this.type))) return {}
|
||||||
if (!data) return this.store.fetch('gamemodes', filter).value.data
|
const type = this.type as 'server' | 'player' | 'weapon' | 'map' | 'gamemode'
|
||||||
|
const data = this.store.getList(`${type}s`, filter)?.value.data
|
||||||
|
if (!data) return this.store.fetch(`${type}s`, filter).value.data
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
sortedList (): string[] {
|
sortedList (): string[] {
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="weaponChart" ref="container">
|
|
||||||
<LoadingBar v-if="progress !== 1" :value="progress"></LoadingBar>
|
|
||||||
<Doughnut :data="chart" :options="chartOptions" v-if="progress === 1" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { Chart as ChartJS, ArcElement, Tooltip, Legend, ChartData, ChartOptions } from 'chart.js'
|
|
||||||
import dataLabel from 'chartjs-plugin-datalabels'
|
|
||||||
import { Weapon, Filter, useKillStore } from '@/stores/kill'
|
|
||||||
import { Doughnut } from 'vue-chartjs'
|
|
||||||
import { defineComponent, PropType, Ref, unref } from 'vue'
|
|
||||||
import weapons from '../stores/weapons.json'
|
|
||||||
|
|
||||||
import LoadingBar from './LoadingBar.vue'
|
|
||||||
|
|
||||||
ChartJS.register(ArcElement, Tooltip, Legend, dataLabel)
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'WeaponChart',
|
|
||||||
props: {
|
|
||||||
filters: Object as PropType<Filter>,
|
|
||||||
playerHighlighted: String
|
|
||||||
},
|
|
||||||
emits: ['highlightPlayer'],
|
|
||||||
components: {
|
|
||||||
Doughnut, LoadingBar
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
this.refreshColors++
|
|
||||||
},
|
|
||||||
data: () => {
|
|
||||||
return {
|
|
||||||
store: useKillStore(),
|
|
||||||
refreshColors: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
progress () {
|
|
||||||
const filter = new Filter(this.filters)
|
|
||||||
delete filter.weapon
|
|
||||||
const data = this.store.getList('weapons', filter)?.value
|
|
||||||
if (!data) return this.store.fetch('weapons', filter).value.progress.value
|
|
||||||
return data.progress.value
|
|
||||||
},
|
|
||||||
colors () {
|
|
||||||
// eslint-disable-next-line no-unused-expressions
|
|
||||||
this.refreshColors
|
|
||||||
const colors = {} as { [key: string]: string }
|
|
||||||
if (this.$refs.container) {
|
|
||||||
const style = getComputedStyle(this.$refs.container as Element)
|
|
||||||
colors.fg = style.getPropertyValue('--foreground')
|
|
||||||
colors.bg = style.getPropertyValue('--bg-color')
|
|
||||||
colors.orange = style.getPropertyValue('--orange')
|
|
||||||
colors.cyan = style.getPropertyValue('--cyan')
|
|
||||||
colors.yellow = style.getPropertyValue('--yellow')
|
|
||||||
colors.green = style.getPropertyValue('--green')
|
|
||||||
colors.purple = style.getPropertyValue('--purple')
|
|
||||||
colors.red = style.getPropertyValue('--red')
|
|
||||||
colors.pink = style.getPropertyValue('--pink')
|
|
||||||
colors.currentLine = style.getPropertyValue('--current-line')
|
|
||||||
} else {
|
|
||||||
colors.fg = '#ffffff'
|
|
||||||
}
|
|
||||||
return colors
|
|
||||||
},
|
|
||||||
chart (): ChartData<'doughnut', number[]> {
|
|
||||||
const colors = [
|
|
||||||
'cyan',
|
|
||||||
'green',
|
|
||||||
'orange',
|
|
||||||
'pink',
|
|
||||||
'purple',
|
|
||||||
'red',
|
|
||||||
'yellow'
|
|
||||||
]
|
|
||||||
const chartData: ChartData<'doughnut', number[]> = {
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: 'Weapons',
|
|
||||||
borderColor: () => this.colors.fg,
|
|
||||||
backgroundColor: (context) => {
|
|
||||||
return this.colors[
|
|
||||||
colors[(context.dataIndex * 3) % colors.length]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
data: [] as number[]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
if (!this.sortedWeaponList) {
|
|
||||||
return chartData
|
|
||||||
}
|
|
||||||
chartData.datasets[0].data = this.sortedWeaponList.map((e) => {
|
|
||||||
if (!this.weapons) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return this.weapons[e].value.kills
|
|
||||||
})
|
|
||||||
return chartData
|
|
||||||
},
|
|
||||||
chartOptions (): ChartOptions<'doughnut'> {
|
|
||||||
// eslint-disable-next-line no-unused-expressions
|
|
||||||
this.$props.playerHighlighted
|
|
||||||
const options: ChartOptions<'doughnut'> = {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: true,
|
|
||||||
animation: { duration: 500 },
|
|
||||||
layout: { autoPadding: false },
|
|
||||||
plugins: {
|
|
||||||
datalabels: {
|
|
||||||
formatter: (value, context) => {
|
|
||||||
const weaponId = this.sortedWeaponList[context.dataIndex]
|
|
||||||
// if (!(weapons as {[key:string]:string})[weaponId]) console.log(weaponId)
|
|
||||||
return (weapons as { [key: string]: string })[weaponId] || weaponId
|
|
||||||
},
|
|
||||||
backgroundColor: (context) => {
|
|
||||||
return context.dataset.backgroundColor(context, options)
|
|
||||||
},
|
|
||||||
borderColor: this.colors.fg,
|
|
||||||
borderRadius: 25,
|
|
||||||
borderWidth: 2,
|
|
||||||
color: this.colors.bg,
|
|
||||||
display: (context) => {
|
|
||||||
return context.dataIndex === context.dataset.data.length - 1
|
|
||||||
? true
|
|
||||||
: 'auto'
|
|
||||||
},
|
|
||||||
padding: 6
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
callbacks: {
|
|
||||||
label: (ctx: any) => {
|
|
||||||
let label: string
|
|
||||||
if (!this.sortedWeaponList) {
|
|
||||||
label = ctx.dataset.labels[ctx.dataIndex]
|
|
||||||
} else {
|
|
||||||
label = this.sortedWeaponList[ctx.dataIndex]
|
|
||||||
}
|
|
||||||
label += ' (' + this.weapons[label].value.kills + ' kills)'
|
|
||||||
return label
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return options
|
|
||||||
},
|
|
||||||
weapons (): { [key: string]: Ref<Weapon> } {
|
|
||||||
const filter = new Filter({ ...this.filters, player: this.playerHighlighted })
|
|
||||||
delete filter.weapon
|
|
||||||
const data = this.store.getList('weapons', filter)?.value.data
|
|
||||||
if (!data) return this.store.fetch('weapons', filter).value.data
|
|
||||||
return data
|
|
||||||
},
|
|
||||||
sortedWeaponList (): string[] {
|
|
||||||
if (!this.weapons) return []
|
|
||||||
const weapons = Object.keys(this.weapons).filter(e => unref(this.weapons[e]).kills > 0)
|
|
||||||
weapons.sort((a, b) => {
|
|
||||||
if (Number(this.weapons[a].value.kills) < Number(unref(this.weapons[b]).kills)) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if (Number(this.weapons[a].value.kills) > Number(unref(this.weapons[b]).kills)) {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
})
|
|
||||||
return weapons
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.weaponChart {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 922px) {
|
|
||||||
canvas {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -80,15 +80,16 @@
|
|||||||
:playerHighlighted="playerHighlighted?.id"
|
:playerHighlighted="playerHighlighted?.id"
|
||||||
>
|
>
|
||||||
</PlayerChart>
|
</PlayerChart>
|
||||||
<WeaponChart
|
<PieChart
|
||||||
:filters="{ player: playerHighlighted?.id, ...filters }"
|
:filters="{ player: playerHighlighted?.id, ...filters }"
|
||||||
:playerHighlighted="playerHighlighted?.id"
|
:playerHighlighted="playerHighlighted?.id"
|
||||||
>
|
type="weapon"
|
||||||
</WeaponChart>
|
></PieChart>
|
||||||
<GamemodeChart
|
<PieChart
|
||||||
:filters="{ player: playerHighlighted?.id, ...filters }"
|
:filters="{ player: playerHighlighted?.id, ...filters }"
|
||||||
:playerHighlighted="playerHighlighted?.id"
|
:playerHighlighted="playerHighlighted?.id"
|
||||||
></GamemodeChart>
|
type="gamemode"
|
||||||
|
></PieChart>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -96,8 +97,7 @@
|
|||||||
import { Player, Weapon, Server, Kill, useKillStore, Filter } from '@/stores/kill'
|
import { Player, Weapon, Server, Kill, useKillStore, Filter } from '@/stores/kill'
|
||||||
import PlayerList from '@/components/PlayerList.vue'
|
import PlayerList from '@/components/PlayerList.vue'
|
||||||
import PlayerChart from '@/components/PlayerChart.vue'
|
import PlayerChart from '@/components/PlayerChart.vue'
|
||||||
import WeaponChart from '@/components/WeaponChart.vue'
|
import PieChart from '@/components/PieChart.vue'
|
||||||
import GamemodeChart from '@/components/GamemodeChart.vue'
|
|
||||||
import { Ref, defineComponent, unref } from 'vue'
|
import { Ref, defineComponent, unref } from 'vue'
|
||||||
import VueMultiselect from 'vue-multiselect'
|
import VueMultiselect from 'vue-multiselect'
|
||||||
import 'vue-multiselect/dist/vue-multiselect.css'
|
import 'vue-multiselect/dist/vue-multiselect.css'
|
||||||
@@ -115,8 +115,7 @@ export default defineComponent({
|
|||||||
VueMultiselect,
|
VueMultiselect,
|
||||||
PlayerList,
|
PlayerList,
|
||||||
PlayerChart,
|
PlayerChart,
|
||||||
WeaponChart,
|
PieChart
|
||||||
GamemodeChart
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
|
|||||||
Reference in New Issue
Block a user