add weapon doughnut
This commit is contained in:
+18
-7
@@ -3,8 +3,9 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<!-- <div class="navbar-element">hamburger</div> -->
|
<!-- <div class="navbar-element">hamburger</div> -->
|
||||||
<div class="navbar-element"><!--<span>logo </span>--->TONE API</div>
|
<div class="navbar-element"><!--<span>logo </span>--->TONE API</div>
|
||||||
<div class="navbar-element"><a href="https://github.com/Legonzaur/Tone_WebClient">Github</a></div>
|
<div class="navbar-element github-link"><a href="https://github.com/Legonzaur/Tone_WebClient">Github</a></div>
|
||||||
<div class="navbar-element"><a href="https://github.com/Legonzaur/ToneAPI_servermod">Northstar Server Mod</a></div>
|
<div class="navbar-element github-link"><a
|
||||||
|
href="https://github.com/Legonzaur/ToneAPI_servermod">Northstar Server Mod</a></div>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<!-- <router-link to="/" class="navbar-element">Home</router-link>
|
<!-- <router-link to="/" class="navbar-element">Home</router-link>
|
||||||
<router-link to="/about" class="navbar-element">About</router-link> -->
|
<router-link to="/about" class="navbar-element">About</router-link> -->
|
||||||
@@ -23,6 +24,11 @@
|
|||||||
--foreground: #f8f8f2;
|
--foreground: #f8f8f2;
|
||||||
--orange: #ffb86c;
|
--orange: #ffb86c;
|
||||||
--cyan: #8be9fd;
|
--cyan: #8be9fd;
|
||||||
|
--green: #50fa7b;
|
||||||
|
--pink: #ff79c6;
|
||||||
|
--purple: #bd93f9;
|
||||||
|
--red: #ff5555;
|
||||||
|
--yellow: #f1fa8c;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -49,14 +55,19 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 922px) {
|
@media only screen and (max-width: 922px) {
|
||||||
#app{
|
#app {
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
'header header'
|
'header header'
|
||||||
'filters filters'
|
'filters filters'
|
||||||
'body body ';
|
'body body ';
|
||||||
grid-template-rows: auto auto 1fr;
|
grid-template-rows: auto auto 1fr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.github-link{
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
@@ -88,7 +99,7 @@ nav a.router-link-exact-active {
|
|||||||
padding: 24px 32px;
|
padding: 24px 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-element:hover{
|
.navbar-element:hover {
|
||||||
background: var(--current-line)
|
background: var(--current-line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div id="playerInfo">
|
|
||||||
<div v-if="playerWeapons && sortedWeaponList">
|
|
||||||
<span>Most Used Weapons :</span><br/>
|
|
||||||
<div v-if="sortedWeaponList[0]">{{ `${sortedWeaponList[0]} : ${playerWeapons[sortedWeaponList[0]].kills} kills` }}</div>
|
|
||||||
<div v-if="sortedWeaponList[1]">{{ `${sortedWeaponList[1]} : ${playerWeapons[sortedWeaponList[1]].kills} kills` }}</div>
|
|
||||||
<div v-if="sortedWeaponList[2]">{{ `${sortedWeaponList[2]} : ${playerWeapons[sortedWeaponList[2]].kills} kills` }}</div>
|
|
||||||
<div v-if="sortedWeaponList[3]">{{ `${sortedWeaponList[3]} : ${playerWeapons[sortedWeaponList[3]].kills} kills` }}</div>
|
|
||||||
<div v-if="sortedWeaponList[4]">{{ `${sortedWeaponList[4]} : ${playerWeapons[sortedWeaponList[4]].kills} kills` }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
import { Player, Weapon } from '@/store/index'
|
|
||||||
import { useStore } from 'vuex'
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
props: {
|
|
||||||
filters: Object,
|
|
||||||
playerHighlighted: String
|
|
||||||
},
|
|
||||||
emits: ['highlightPlayer'],
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
sortingData: { direction: -1, argument: 'kills' as keyof Player | 'k/d' },
|
|
||||||
store: useStore()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
players (): { [key: string]: Player } { return this.store.getters.getPlayerList(this.filters) },
|
|
||||||
player (): Player | undefined {
|
|
||||||
if (!this.playerHighlighted) return
|
|
||||||
if (!this.players) return
|
|
||||||
return this.players[this.playerHighlighted]
|
|
||||||
},
|
|
||||||
playerWeapons (): { [key: string]: Weapon } {
|
|
||||||
return this.store.getters.getWeaponList({ player: this.playerHighlighted, ...this.filters })
|
|
||||||
},
|
|
||||||
sortedWeaponList (): string[] {
|
|
||||||
if (!this.playerWeapons) return []
|
|
||||||
const weapons = Object.keys(this.playerWeapons)
|
|
||||||
weapons.sort((a, b) => {
|
|
||||||
if (Number(this.playerWeapons[a].kills) < Number(this.playerWeapons[b].kills)) {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
if (Number(this.playerWeapons[a].kills) > Number(this.playerWeapons[b].kills)) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
})
|
|
||||||
console.log(weapons)
|
|
||||||
return weapons
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
#playerInfo {
|
|
||||||
grid-area: info;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 922px) {
|
|
||||||
#playerInfo {
|
|
||||||
display: none
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
<template>
|
||||||
|
<div class="weaponChart" ref="container">
|
||||||
|
<Doughnut :data="chart" :options="chartOptions" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
ArcElement,
|
||||||
|
PointElement,
|
||||||
|
LineElement,
|
||||||
|
Tooltip,
|
||||||
|
Legend
|
||||||
|
} from 'chart.js'
|
||||||
|
import annotationPlugin from 'chartjs-plugin-annotation'
|
||||||
|
import dataLabel from 'chartjs-plugin-datalabels'
|
||||||
|
import { Store, useStore } from 'vuex'
|
||||||
|
import { Player, Weapon } from '@/store/index'
|
||||||
|
import { Doughnut } from 'vue-chartjs'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { functionExpression } from '@babel/types'
|
||||||
|
|
||||||
|
ChartJS.register(ArcElement, Tooltip, Legend, dataLabel)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'PlayerChart',
|
||||||
|
props: {
|
||||||
|
filters: Object,
|
||||||
|
playerHighlighted: String
|
||||||
|
},
|
||||||
|
emits: ['highlightPlayer'],
|
||||||
|
components: {
|
||||||
|
Doughnut
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.refreshColors++
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
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 () {
|
||||||
|
const colors = ['cyan', 'green', 'orange', 'pink', 'purple', 'red', 'yellow']
|
||||||
|
const chartData = {
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Weapons',
|
||||||
|
labels: this.sortedWeaponList || [] as string[],
|
||||||
|
borderColor: (context: any) => this.colors.fg,
|
||||||
|
backgroundColor: (context: any) => { 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].kills
|
||||||
|
})
|
||||||
|
return chartData
|
||||||
|
},
|
||||||
|
chartOptions () {
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
this.$props.playerHighlighted
|
||||||
|
const options = {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: true,
|
||||||
|
animation: { duration: 500 },
|
||||||
|
layout: { autoPadding: false },
|
||||||
|
plugins: {
|
||||||
|
datalabels: {
|
||||||
|
formatter: (value:any, context:any) => {
|
||||||
|
return this.sortedWeaponList[context.dataIndex]
|
||||||
|
},
|
||||||
|
backgroundColor: (context:any) => {
|
||||||
|
return context.dataset.backgroundColor(context)
|
||||||
|
},
|
||||||
|
borderColor: this.colors.fg,
|
||||||
|
borderRadius: 25,
|
||||||
|
borderWidth: 2,
|
||||||
|
color: this.colors.bg,
|
||||||
|
display: (context:any) => {
|
||||||
|
return context.dataIndex === context.dataset.labels.length - 1 ? true : 'auto'
|
||||||
|
},
|
||||||
|
font: {
|
||||||
|
weight: 'bold'
|
||||||
|
},
|
||||||
|
padding: 6
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: (ctx: any) => {
|
||||||
|
let label: string
|
||||||
|
if (!this.sortedWeaponList) {
|
||||||
|
label = ctx.dataset.labels[ctx.dataIndex]
|
||||||
|
} else {
|
||||||
|
console.log(this.sortedWeaponList)
|
||||||
|
label = this.sortedWeaponList[ctx.dataIndex]
|
||||||
|
}
|
||||||
|
label += ' (' + this.weapons[label].kills + ' kills)'
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
},
|
||||||
|
weapons (): { [key: string]: Weapon } {
|
||||||
|
return this.store.getters.getWeaponList(this.filters)
|
||||||
|
},
|
||||||
|
sortedWeaponList (): string[] {
|
||||||
|
if (!this.weapons) return []
|
||||||
|
const weapons = Object.keys(this.weapons)
|
||||||
|
weapons.sort((a, b) => {
|
||||||
|
if (Number(this.weapons[a].kills) < Number(this.weapons[b].kills)) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if (Number(this.weapons[a].kills) > Number(this.weapons[b].kills)) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
return weapons
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
store: useStore(),
|
||||||
|
refreshColors: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
canvas {
|
||||||
|
background: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 922px) {
|
||||||
|
canvas {
|
||||||
|
display: none !important
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
:playerHighlighted="playerHighlighted"></PlayerList>
|
:playerHighlighted="playerHighlighted"></PlayerList>
|
||||||
<PlayerChart :filters="filters" v-on:highlight-player="playerHighlighted = $event"
|
<PlayerChart :filters="filters" v-on:highlight-player="playerHighlighted = $event"
|
||||||
:playerHighlighted="playerHighlighted"></PlayerChart>
|
:playerHighlighted="playerHighlighted"></PlayerChart>
|
||||||
<PlayerInfo :filters="filters" :playerHighlighted="playerHighlighted"></PlayerInfo>
|
<WeaponChart :filters="{player: playerHighlighted, ...filters}" :playerHighlighted="playerHighlighted"></WeaponChart>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ import { Store, useStore } from 'vuex'
|
|||||||
import { Player, Weapon, Server } from '@/store/index'
|
import { Player, Weapon, Server } from '@/store/index'
|
||||||
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 PlayerInfo from '@/components/PlayerInfo.vue'
|
import WeaponChart from '@/components/WeaponChart.vue'
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } 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'
|
||||||
@@ -46,7 +46,7 @@ import 'vue-multiselect/dist/vue-multiselect.css'
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'PlayerView',
|
name: 'PlayerView',
|
||||||
components: {
|
components: {
|
||||||
PlayerList, PlayerChart, VueMultiselect, PlayerInfo
|
PlayerList, PlayerChart, VueMultiselect, WeaponChart
|
||||||
},
|
},
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
@@ -125,6 +125,7 @@ export default defineComponent({
|
|||||||
'list chart'
|
'list chart'
|
||||||
'list info';
|
'list info';
|
||||||
grid-template-columns: 50% 50%;
|
grid-template-columns: 50% 50%;
|
||||||
|
grid-template-rows: 50% 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 922px) {
|
@media only screen and (max-width: 922px) {
|
||||||
@@ -136,6 +137,7 @@ export default defineComponent({
|
|||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
'list list';
|
'list list';
|
||||||
grid-template-columns: 100%;
|
grid-template-columns: 100%;
|
||||||
|
grid-template-rows: 100%;
|
||||||
width: calc(100vw - 1em);
|
width: calc(100vw - 1em);
|
||||||
margin: 0 0rem 1rem 1rem;
|
margin: 0 0rem 1rem 1rem;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user