feat: add stats for most played champions

This commit is contained in:
Valentin Kaelin 2019-11-24 14:26:27 +01:00
parent 763ba327ae
commit d5394c64f8
7 changed files with 194 additions and 16 deletions

View file

@ -1,5 +1,6 @@
<template> <template>
<svg xmlns="http://www.w3.org/2000/svg" class="hidden"> <svg xmlns="http://www.w3.org/2000/svg" class="hidden">
<symbol id="layers" class="stroke-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"></polygon><polyline points="2 17 12 22 22 17"></polyline><polyline points="2 12 12 17 22 12"></polyline></symbol>
<symbol id="people" class="stroke-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" /> <circle cx="9" cy="7" r="4" /> <path d="M23 21v-2a4 4 0 0 0-3-3.87" /> <path d="M16 3.13a4 4 0 0 1 0 7.75" /> </symbol> <symbol id="people" class="stroke-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" /> <circle cx="9" cy="7" r="4" /> <path d="M23 21v-2a4 4 0 0 0-3-3.87" /> <path d="M16 3.13a4 4 0 0 1 0 7.75" /> </symbol>
<symbol id="graph" class="stroke-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="18" y1="20" x2="18" y2="10" /> <line x1="12" y1="20" x2="12" y2="4" /> <line x1="6" y1="20" x2="6" y2="14" /> </symbol> <symbol id="graph" class="stroke-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="18" y1="20" x2="18" y2="10" /> <line x1="12" y1="20" x2="12" y2="4" /> <line x1="6" y1="20" x2="6" y2="14" /> </symbol>
<symbol id="info" class="stroke-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></symbol> <symbol id="info" class="stroke-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></symbol>

View file

@ -0,0 +1,134 @@
<template>
<div class="bg-blue-800 rounded-lg">
<div class="relative heading flex items-center justify-center py-4 rounded-t-lg text-blue-200">
<svg class="w-5 h-5" style="transform: rotate(-5deg);">
<use xlink:href="#layers" />
</svg>
<span class="mx-4 text-lg font-bold uppercase">CHAMPIONS</span>
<svg class="w-5 h-5" style="transform: rotate(5deg);">
<use xlink:href="#layers" />
</svg>
<div class="absolute right-0 top-0 mt-3 mr-2">
<Dropdown>
<template v-slot:trigger>
<svg class="w-4 h-4 cursor-pointer">
<use xlink:href="#info" />
</svg>
</template>
<template v-slot:default>
<div class="px-2 text-white text-center text-sm select-none">
<div>Stats based on</div>
<div>
<span class="text-teal-400 font-bold">{{ stats.global.count }}</span> matches
</div>
<div class="mt-2 leading-tight text-xs text-blue-100 font-normal italic">
Load more matches
<br />to have better results.
</div>
</div>
</template>
</Dropdown>
</div>
</div>
<div class="mt-3 px-4 flex items-baseline text-left text-sm text-blue-300 font-bold">
<div class="ml-2 w-champion text-base text-blue-400">Champion</div>
<div class="w-plays">plays</div>
<div class="w-winrate">winrate</div>
<div class="w-kda">kda</div>
</div>
<ul class="mt-1 text-sm text-gray-100 text-left">
<li
v-for="(champion, index) in stats.champion"
:key="index"
:class="[{'rounded-b-lg': index === stats.champion.length - 1}, {'bg-blue-760': index % 2 === 0}]"
class="relative flex items-center px-4 py-2 leading-tight"
>
<div class="absolute text-xs" style="left: 6px;">{{ index + 1 }}.</div>
<div class="ml-2 w-champion flex items-center">
<div
:style="{backgroundImage: `url('https://ddragon.leagueoflegends.com/cdn/${version}/img/champion/${champion._id}.png')`}"
class="w-8 h-8 bg-center bg-cover rounded-full flex-shrink-0"
></div>
<div class="mx-1 truncate">{{ champion.champion }}</div>
</div>
<div class="w-plays">
<div class="text-blue-400 text-xs">{{ champion.count }}</div>
<div
:style="{width: widthBar(champion.count, mostPlayed)}"
class="mt-2px bg-blue-400 rounded-full h-1"
></div>
</div>
<div class="w-winrate">
<div class="text-green-400 text-xs">{{ champion.wins * 100 / champion.count|percent }}</div>
<div
:style="{width: widthBar(champion.wins, champion.count)}"
class="mt-2px bg-green-400 rounded-full h-1"
></div>
</div>
<div class="w-kda">
<div
class="text-purple-400 text-xs"
>{{ kda(champion.kills, champion.deaths, champion.assists) }}</div>
<div
:style="{width: widthBar(kda(champion.kills, champion.deaths, champion.assists), bestKda)}"
class="mt-2px bg-purple-400 rounded-full h-1"
></div>
</div>
</li>
</ul>
</div>
</template>
<script>
import { mapGetters, mapState } from 'vuex'
import Dropdown from '@/components/Dropdown.vue'
export default {
components: {
Dropdown,
},
computed: {
bestKda() {
const bestChamp = this.stats.champion.reduce((a, b) => {
return this.kda(a.kills, a.deaths, a.assists) > this.kda(b.kills, b.deaths, b.assists) ? a : b
})
return this.kda(bestChamp.kills, bestChamp.deaths, bestChamp.assists)
},
mostPlayed() {
return this.stats.champion.reduce((a, b) => a.count > b.count ? a : b).count
},
...mapGetters('ddragon', ['version']),
...mapState({
stats: state => state.summoner.infos.stats
}),
},
methods: {
kda(kills, deaths, assists) {
return this.$options.filters.round((kills + assists) / deaths)
},
widthBar(value, total) {
return `${value * 36 / total}px`
}
}
}
</script>
<style scoped>
.w-champion {
width: 110px;
}
.w-plays {
width: 55px;
}
.w-winrate {
width: 65px;
}
.w-kda {
width: 36px;
}
</style>

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="bg-blue-800 rounded-lg"> <div class="mt-4 bg-blue-800 rounded-lg">
<div class="relative heading flex justify-center py-4 rounded-t-lg text-blue-200"> <div class="relative heading flex justify-center py-4 rounded-t-lg text-blue-200">
<svg class="w-6 h-6"> <svg class="w-6 h-6">
<use xlink:href="#graph" /> <use xlink:href="#graph" />

View file

@ -21,7 +21,7 @@ Vue.filter('secToTime', (sec) => {
}) })
Vue.filter('percent', (value) => { Vue.filter('percent', (value) => {
return `${+value.toFixed(2)}%` return `${+value.toFixed(1)}%`
}) })
Vue.filter('round', (value) => { Vue.filter('round', (value) => {

View file

@ -62,24 +62,26 @@
<div class="mt-3 text-center flex"> <div class="mt-3 text-center flex">
<div class="mt-4 w-3/12"> <div class="mt-4 w-3/12">
<SummonerChampions />
<SummonerStats /> <SummonerStats />
<SummonerMates /> <SummonerMates />
</div> </div>
<ul class="w-9/12 text-gray-900"> <div class="w-9/12">
<Match <ul>
v-for="(match, index) in summonerInfos.matches" <Match
:key="index" v-for="(match, index) in summonerInfos.matches"
:data="summonerInfos.matches[index]" :key="index"
/> :data="summonerInfos.matches[index]"
</ul> />
</ul>
<LoadingButton
v-if="moreMatchesToFetch"
@clicked="moreMatches"
:loading="matchesLoading"
btn-class="mt-4 block mx-auto bg-blue-800 px-4 py-2 rounded-md font-semibold hover:bg-blue-1000 shadow-lg"
>More matches</LoadingButton>
</div>
</div> </div>
<LoadingButton
v-if="moreMatchesToFetch"
@clicked="moreMatches"
:loading="matchesLoading"
btn-class="mt-4 block mx-auto bg-blue-800 px-4 py-2 rounded-md font-semibold hover:bg-blue-1000 shadow-lg"
>More matches</LoadingButton>
</div> </div>
</template> </template>
@ -109,6 +111,7 @@ import MainFooter from '@/components/MainFooter.vue'
import Match from '@/components/Match/Match.vue' import Match from '@/components/Match/Match.vue'
import RecentActivity from '@/components/Summoner/RecentActivity.vue' import RecentActivity from '@/components/Summoner/RecentActivity.vue'
import SearchForm from '@/components/SearchForm.vue' import SearchForm from '@/components/SearchForm.vue'
import SummonerChampions from '@/components/Summoner/SummonerChampions.vue'
import SummonerLoader from '@/components/Summoner/SummonerLoader.vue' import SummonerLoader from '@/components/Summoner/SummonerLoader.vue'
import SummonerMates from '@/components/Summoner/SummonerMates.vue' import SummonerMates from '@/components/Summoner/SummonerMates.vue'
import SummonerRanked from '@/components/Summoner/SummonerRanked.vue' import SummonerRanked from '@/components/Summoner/SummonerRanked.vue'
@ -122,6 +125,7 @@ export default {
Match, Match,
RecentActivity, RecentActivity,
SearchForm, SearchForm,
SummonerChampions,
SummonerLoader, SummonerLoader,
SummonerMates, SummonerMates,
SummonerRanked, SummonerRanked,

View file

@ -24,6 +24,7 @@ class StatsHelper {
}) })
} }
} }
const championStats = await this.matchRepository.championStats(account.puuid)
const championClassStats = await this.matchRepository.championClassStats(account.puuid) const championClassStats = await this.matchRepository.championClassStats(account.puuid)
const mates = await this.matchRepository.mates(account.puuid, account.name) const mates = await this.matchRepository.mates(account.puuid, account.name)
@ -33,6 +34,7 @@ class StatsHelper {
role: roleStats.sort(this.sortTeamByRole), role: roleStats.sort(this.sortTeamByRole),
class: championClassStats, class: championClassStats,
mates, mates,
champion: championStats,
} }
} }

View file

@ -9,6 +9,43 @@ class MatchRepository {
this.Match = Match this.Match = Match
} }
/**
* Get Summoner's statistics for the 5 most played champions
* @param puuid of the summoner
*/
championStats(puuid) {
return this.Match.query().aggregate([
{
$match: {
summoner_puuid: puuid,
result: { $not: { $eq: 'Remake' } }
}
},
{
$group: {
_id: "$champion.id",
champion: { $first: "$champion.name" },
count: { $sum: 1 },
wins: {
$sum: {
$cond: [{ $eq: ["$result", "Win"] }, 1, 0]
}
},
losses: {
$sum: {
$cond: [{ $eq: ["$result", "Fail"] }, 1, 0]
}
},
kills: { $sum: "$stats.kills" },
deaths: { $sum: "$stats.deaths" },
assists: { $sum: "$stats.assists" },
}
},
{ $sort: { 'count': -1 } },
{ $limit: 5 },
])
}
/** /**
* Get Summoner's statistics for all played champion classes * Get Summoner's statistics for all played champion classes
* @param puuid of the summoner * @param puuid of the summoner