add gamemode filter and multiselection
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="gamemodeChart" 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 gamemodes from '../stores/gamemodes.json'
|
||||
|
||||
import LoadingBar from './LoadingBar.vue'
|
||||
|
||||
ChartJS.register(ArcElement, Tooltip, Legend, dataLabel)
|
||||
|
||||
export default defineComponent({
|
||||
name: 'GamemodeChart',
|
||||
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.gamemode
|
||||
const data = this.store.getList('gamemodes', filter)?.value
|
||||
if (!data) return this.store.fetch('gamemodes', 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.sortedList) {
|
||||
return chartData
|
||||
}
|
||||
chartData.datasets[0].data = this.sortedList.map((e) => {
|
||||
if (!this.values) {
|
||||
return 0
|
||||
}
|
||||
return this.values[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.sortedList[context.dataIndex]
|
||||
// if (!(weapons as {[key:string]:string})[weaponId]) console.log(weaponId)
|
||||
return (gamemodes 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.sortedList) {
|
||||
label = ctx.dataset.labels[ctx.dataIndex]
|
||||
} else {
|
||||
label = this.sortedList[ctx.dataIndex]
|
||||
}
|
||||
label += ' (' + this.values[label].value.kills + ' kills)'
|
||||
return label
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return options
|
||||
},
|
||||
values (): { [key: string]: Ref<Weapon> } {
|
||||
const filter = new Filter({ ...this.filters, player: this.playerHighlighted })
|
||||
delete filter.gamemode
|
||||
const data = this.store.getList('gamemodes', filter)?.value.data
|
||||
if (!data) return this.store.fetch('gamemodes', filter).value.data
|
||||
return data
|
||||
},
|
||||
sortedList (): string[] {
|
||||
if (!this.values) return []
|
||||
const weapons = Object.keys(this.values).filter(e => unref(this.values[e]).kills > 0)
|
||||
weapons.sort((a, b) => {
|
||||
if (Number(this.values[a].value.kills) < Number(unref(this.values[b]).kills)) {
|
||||
return -1
|
||||
}
|
||||
if (Number(this.values[a].value.kills) > Number(unref(this.values[b]).kills)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
return weapons
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.weaponChart {
|
||||
width: calc(min(50vw, 50vh) - 3em);
|
||||
height: calc(min(50vw, 50vh) - 3em);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 922px) {
|
||||
canvas {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -66,11 +66,11 @@ export default defineComponent({
|
||||
} else if (mustScrollDown) {
|
||||
this.vIndex = Math.min(scrollIndex, this.list.length - this.toLoad)
|
||||
}
|
||||
if (mustScrollDown || mustScrollUp) {
|
||||
const msg = (mustScrollDown ? 'down ' : '') + (mustScrollUp ? 'up ' : '')
|
||||
// console.log(this.toLoad)
|
||||
// console.log((this.list.length * this.$props.rowHeight) - (this.vIndex * this.$props.rowHeight) - (this.visibleCount * this.$props.rowHeight))
|
||||
}
|
||||
// if (mustScrollDown || mustScrollUp) {
|
||||
// const msg = (mustScrollDown ? 'down ' : '') + (mustScrollUp ? 'up ' : '')
|
||||
// console.log(this.toLoad)
|
||||
// console.log((this.list.length * this.$props.rowHeight) - (this.vIndex * this.$props.rowHeight) - (this.visibleCount * this.$props.rowHeight))
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import dataLabel from 'chartjs-plugin-datalabels'
|
||||
import { useKillStore, Player, Filter } from '@/stores/kill'
|
||||
|
||||
import { Scatter } from 'vue-chartjs'
|
||||
import { defineComponent, PropType, Ref, toRaw, triggerRef, unref } from 'vue'
|
||||
import { defineComponent, PropType, toRaw, unref } from 'vue'
|
||||
import { ChartEvent } from 'chart.js/dist/core/core.plugins'
|
||||
import { _DeepPartialObject } from 'chart.js/dist/types/utils'
|
||||
|
||||
@@ -55,7 +55,7 @@ export default defineComponent({
|
||||
if (this.filters) {
|
||||
const filter = new Filter(this.filters)
|
||||
delete filter.player
|
||||
return this.store.getList('players', filter)?.value.progress
|
||||
return this.store.getList('players', filter)?.value.progress.value
|
||||
}
|
||||
return 0
|
||||
},
|
||||
|
||||
@@ -32,7 +32,6 @@ import { defineComponent, PropType, Ref, isRef } from 'vue'
|
||||
import { useKillStore, Player, Filter } from '@/stores/kill'
|
||||
import VirtualList from './List/VirtualList.vue'
|
||||
import LoadingBar from './LoadingBar.vue'
|
||||
import { cloneProxy } from 'vue-chartjs/dist/utils'
|
||||
|
||||
export default defineComponent({
|
||||
components: { VirtualList, LoadingBar },
|
||||
@@ -51,14 +50,13 @@ export default defineComponent({
|
||||
progress () {
|
||||
const filter = new Filter(this.filters)
|
||||
delete filter.player
|
||||
return this.store.getList('players', filter)?.value.progress
|
||||
return this.store.getList('players', filter)?.value.progress.value
|
||||
},
|
||||
players (): { [key: string]: Ref<Player> } {
|
||||
const filter = new Filter(this.filters)
|
||||
delete filter.player
|
||||
const data = this.store.getList('players', filter)?.value.data
|
||||
if (!data) return this.store.fetch('players', filter).value.data
|
||||
console.log(isRef(data), isRef(Object.values(data)[0]))
|
||||
return data
|
||||
},
|
||||
playerList (): (Ref<Player> & { id: string })[] {
|
||||
@@ -149,7 +147,6 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
.playerTable {
|
||||
grid-area: list;
|
||||
margin-right: 1rem;
|
||||
height: 100%;
|
||||
user-select: none;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="weaponChart" ref="container">
|
||||
<LoadingBar v-if="progress !== 1" :value="progress"></LoadingBar>
|
||||
<Doughnut :data="chart" :options="chartOptions" v-if="progress === 1"/>
|
||||
<Doughnut :data="chart" :options="chartOptions" v-if="progress === 1" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'
|
||||
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'
|
||||
@@ -41,8 +41,8 @@ export default defineComponent({
|
||||
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
|
||||
return data.progress
|
||||
if (!data) return this.store.fetch('weapons', filter).value.progress.value
|
||||
return data.progress.value
|
||||
},
|
||||
colors () {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
@@ -65,7 +65,7 @@ export default defineComponent({
|
||||
}
|
||||
return colors
|
||||
},
|
||||
chart () {
|
||||
chart (): ChartData<'doughnut', number[]> {
|
||||
const colors = [
|
||||
'cyan',
|
||||
'green',
|
||||
@@ -75,13 +75,12 @@ export default defineComponent({
|
||||
'red',
|
||||
'yellow'
|
||||
]
|
||||
const chartData = {
|
||||
const chartData: ChartData<'doughnut', number[]> = {
|
||||
datasets: [
|
||||
{
|
||||
label: 'Weapons',
|
||||
labels: this.sortedWeaponList || ([] as string[]),
|
||||
borderColor: () => this.colors.fg,
|
||||
backgroundColor: (context: any) => {
|
||||
backgroundColor: (context) => {
|
||||
return this.colors[
|
||||
colors[(context.dataIndex * 3) % colors.length]
|
||||
]
|
||||
@@ -101,30 +100,30 @@ export default defineComponent({
|
||||
})
|
||||
return chartData
|
||||
},
|
||||
chartOptions () {
|
||||
chartOptions (): ChartOptions<'doughnut'> {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
this.$props.playerHighlighted
|
||||
const options = {
|
||||
const options: ChartOptions<'doughnut'> = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
animation: { duration: 500 },
|
||||
layout: { autoPadding: false },
|
||||
plugins: {
|
||||
datalabels: {
|
||||
formatter: (value: any, context: any) => {
|
||||
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
|
||||
return (weapons as { [key: string]: string })[weaponId] || weaponId
|
||||
},
|
||||
backgroundColor: (context: any) => {
|
||||
return context.dataset.backgroundColor(context)
|
||||
backgroundColor: (context) => {
|
||||
return context.dataset.backgroundColor(context, options)
|
||||
},
|
||||
borderColor: this.colors.fg,
|
||||
borderRadius: 25,
|
||||
borderWidth: 2,
|
||||
color: this.colors.bg,
|
||||
display: (context: any) => {
|
||||
return context.dataIndex === context.dataset.labels.length - 1
|
||||
display: (context) => {
|
||||
return context.dataIndex === context.dataset.data.length - 1
|
||||
? true
|
||||
: 'auto'
|
||||
},
|
||||
@@ -153,7 +152,6 @@ export default defineComponent({
|
||||
delete filter.weapon
|
||||
const data = this.store.getList('weapons', filter)?.value.data
|
||||
if (!data) return this.store.fetch('weapons', filter).value.data
|
||||
console.log(filter.toURLSearchParams().toString(), filter)
|
||||
return data
|
||||
},
|
||||
sortedWeaponList (): string[] {
|
||||
|
||||
Reference in New Issue
Block a user