Files
csgowtf/src/components/PlayerSideInfo.vue

373 lines
10 KiB
Vue

<template>
<div class="side-info">
<div v-if="props.player_meta.most_mates" class="side-info-box most-played-with">
<div class="heading">
<h5>Most played with</h5>
</div>
<hr>
<ul v-for="mate in props.player_meta.most_mates" :key="mate.player.steamid64" class="list-unstyled">
<li @click="GoToPlayer(mate.player.vanity_url || mate.player.steamid64)">
<span class="start">
<img :class="mate.player.tracked ? 'tracked' : ''" :src="constructAvatarUrl(mate.player.avatar)"
:title="mate.player.tracked ? 'Tracked' : ''" alt="Player avatar">
<span class="text">{{ mate.player.name }}</span>
</span>
<span class="end">
{{ mate.total }}
</span>
</li>
</ul>
</div>
<div v-else class="side-info-box most-played-with">
<div class="heading">
<h5>Most played with</h5>
</div>
<hr>
<ul class="list-unstyled placeholder-glow">
<li class="placeholder col-11"></li>
<li class="placeholder col-11"></li>
<li class="placeholder col-11"></li>
</ul>
</div>
<div v-if="props.player_meta.best_mates" class="side-info-box best-mate">
<div class="heading">
<h5>Best Mate <span class="text-muted">(by winrate)</span></h5>
</div>
<hr>
<ul v-for="mate in props.player_meta.best_mates" :key="mate.player.steamid64" class="list-unstyled">
<li @click="GoToPlayer(mate.player.vanity_url || mate.player.steamid64)">
<span class="start">
<img :class="mate.player.tracked ? 'tracked' : ''" :src="constructAvatarUrl(mate.player.avatar)"
:title="mate.player.tracked ? 'Tracked' : ''" alt="Player avatar">
<span class="text">{{ mate.player.name }}</span>
</span>
<span class="end">
{{ (mate.win_rate * 100).toFixed(0) }} %
<span v-if="mate.total" class="total text-muted">({{ mate.total }})</span>
</span>
</li>
</ul>
</div>
<div v-else-if="props.player_meta.most_mates && props.player_meta.most_mates[0].total === 1" class="side-info-box best-mate">
<div class="heading">
<h5>Best Mate <span class="text-muted">(by winrate)</span></h5>
</div>
<hr>
<ul class="list-unstyled placeholder-glow">
<li class="col-11">Not enough Data</li>
</ul>
</div>
<div v-else class="side-info-box best-mate">
<div class="heading">
<h5>Best Mate <span class="text-muted">(by winrate)</span></h5>
</div>
<hr>
<ul class="list-unstyled placeholder-glow">
<li class="placeholder col-11"></li>
<li class="placeholder col-11"></li>
<li class="placeholder col-11"></li>
</ul>
</div>
<div v-if="props.player_meta.eq_map && props.player_meta.weapon_dmg" class="side-info-box preferred-weapons">
<div class="heading">
<h5>Weapons <span class="text-muted">(by dmg)</span></h5>
</div>
<hr>
<ul v-for="(id, key) in data.best_weapons" :key="id[0]" class="list-unstyled">
<li>
<span class="start">
<span class="text">{{ id[0] }}</span>
</span>
<span :title="id[0] + ' - ' + id[1] + ' dmg'" class="end">
<span :class="'dmg-chart-' + key">
{{ id[1] }}
</span>
</span>
</li>
</ul>
{{ setDmgGraphWidth() }}
</div>
<div v-else class="side-info-box preferred-weapons">
<div class="heading">
<h5>Weapons <span class="text-muted">(by dmg)</span></h5>
</div>
<hr>
<ul class="list-unstyled placeholder-glow">
<li class="placeholder col-11"></li>
<li class="placeholder col-11"></li>
<li class="placeholder col-11"></li>
</ul>
</div>
<div v-if="props.player_meta.win_maps" class="side-info-box best-map">
<div class="heading">
<h5>Best Map <span class="text-muted">(by winrate)</span></h5>
</div>
<hr>
<ul v-for="map in data.best_maps" :key="map[0]" class="list-unstyled">
<li>
<span class="start">
<img :src="require('../assets/images/map_icons/map_icon_' + map[0] + '.svg')" alt="Player avatar">
<span class="text">{{ FixMapName(map[0]) }}</span>
</span>
<span class="end">
{{ (map[1] * 100).toFixed(0) }} %
<span v-if="props.player_meta.total_maps[map[0]]"
class="total text-muted">({{ props.player_meta.total_maps[map[0]] }})</span>
</span>
</li>
</ul>
</div>
<div v-else-if="props.player_meta.total_maps && !props.player_meta.win_maps" class="side-info-box best-map">
<div class="heading">
<h5>Best Map <span class="text-muted">(by winrate)</span></h5>
</div>
<hr>
<ul class="list-unstyled placeholder-glow">
<li class="col-11">Not enough Data</li>
</ul>
</div>
<div v-else class="side-info-box best-map">
<div class="heading">
<h5>Best Map <span class="text-muted">(by winrate)</span></h5>
</div>
<hr>
<ul class="list-unstyled placeholder-glow">
<li class="placeholder col-11"></li>
<li class="placeholder col-11"></li>
<li class="placeholder col-11"></li>
</ul>
</div>
</div>
</template>
<script>
import {constructAvatarUrl, FixMapName, GoToPlayer, sortObjectValue} from "@/utils";
import {reactive, ref, watch} from "vue";
export default {
name: "PlayerSideInfo",
props: {
player_meta: {
type: Object,
required: true
}
},
setup(props) {
const displayCounter = 3
const data = reactive({
best_maps: [],
best_weapons_tmp: [],
best_weapons: []
})
const mapWeaponDamage = () => {
if (props.player_meta.eq_map && props.player_meta.weapon_dmg) {
Object.keys(props.player_meta.eq_map).forEach((key) => {
for (const id in props.player_meta.weapon_dmg) {
Object.keys(props.player_meta.weapon_dmg[id]).forEach((k) => {
if (k === 'eq') {
if (props.player_meta.weapon_dmg[id][k] === key * 1) {
data.best_weapons_tmp.push([props.player_meta.eq_map[key], props.player_meta.weapon_dmg[id]['dmg']])
}
}
})
}
})
data.best_weapons_tmp.sort((a, b) => {
return b[1] - a[1]
})
data.best_weapons = data.best_weapons_tmp
data.best_weapons_tmp = []
}
}
const setDmgGraphWidth = () => {
setTimeout(() => {
let weaponsContainer
const dmg100 = ref(0)
const dmg = ref(0)
for (let i = 0; i <= 4; i++) {
weaponsContainer = document.querySelector('.dmg-chart-' + i)
if (weaponsContainer !== null) {
if (i === 0) {
dmg100.value = weaponsContainer.innerHTML * 1
weaponsContainer.style.width = '100%'
}
dmg.value = weaponsContainer.innerHTML * 1
weaponsContainer.style.width = dmg.value * 100 / dmg100.value + '%'
}
}
}, 100)
}
watch(() => props.player_meta, () => {
mapWeaponDamage()
data.best_maps = sortObjectValue(props.player_meta.win_maps, 'desc')
if (data.best_maps.length > displayCounter)
data.best_maps.splice(displayCounter, data.best_maps.length - displayCounter)
})
return {props, data, setDmgGraphWidth, GoToPlayer, constructAvatarUrl, FixMapName}
}
}
</script>
<style lang="scss" scoped>
.side-info {
display: flex;
flex-direction: column;
gap: 1rem;
width: 100%;
height: auto;
margin-top: 30px;
.placeholder {
height: 25px;
padding: 0 10px !important;
margin: 14px auto !important;
border-radius: 5px;
}
.side-info-box {
width: 100%;
height: auto;
background: rgba(20, 20, 20, .8);
border: 1px solid rgba(white, .3);
border-radius: 5px;
}
ol, ul, dl {
margin-bottom: 0;
}
.best-mate,
.preferred-weapons,
.most-played-with,
.best-map {
.heading {
display: flex;
align-items: center;
justify-content: center;
height: 30px;
h5 {
font-size: 1rem;
margin: 0;
padding: 0;
}
}
hr {
margin: 0 0 5px 0;
border-color: rgba(white, .3);
}
ul li {
line-height: 25px;
font-size: .9rem;
padding: 0 10px;
margin: 10px 0;
cursor: pointer;
display: flex;
justify-content: space-between;
gap: 1rem;
.start {
width: 50%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.tracked {
font-size: .8rem;
margin-right: 5px;
}
img {
width: 25px;
height: 25px;
border-radius: 50%;
margin-right: 5px;
margin-left: 5px;
&.tracked {
border: 2px solid var(--bs-success);
}
}
}
.end {
display: flex;
width: 45%;
justify-content: flex-end;
align-items: flex-end;
}
}
}
.best-map, .best-mate {
ul li {
.start {
width: 75%;
}
.end {
.total {
padding-left: 5px;
}
}
}
}
.preferred-weapons,
.best-map {
ul li {
cursor: default;
}
}
.preferred-weapons {
.end {
position: relative;
@for $i from 0 through 3 {
.dmg-chart-#{$i} {
position: absolute;
background: rgba(150, 50, 50, 1);
border-radius: 15px;
color: transparent;
user-select: none;
cursor: help;
&:hover {
background: rgba(220, 50, 50, 1);
}
}
}
}
}
}
</style>