Lane-dependant stats (fix #5)
This commit is contained in:
@@ -1,18 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
championId: string,
|
||||
championId: number,
|
||||
winrate: number,
|
||||
pickrate: number,
|
||||
gameCount: number
|
||||
}>()
|
||||
|
||||
const championId = Number(props.championId)
|
||||
const winrate = ref((props.winrate * 100).toFixed(2))
|
||||
watch(() => props.winrate, () => {winrate.value = (props.winrate * 100).toFixed(2)})
|
||||
const pickrate = ref((props.pickrate * 100).toFixed(2))
|
||||
watch(() => props.pickrate, () => {pickrate.value = (props.pickrate * 100).toFixed(2)})
|
||||
|
||||
const winrate = (props.winrate * 100).toFixed(2)
|
||||
const pickrate = (props.pickrate * 100).toFixed(2)
|
||||
const gameCount = props.gameCount
|
||||
|
||||
const { data: championData } : ChampionResponse = await useFetch(CDRAGON_BASE + "plugins/rcp-be-lol-game-data/global/default/v1/champions/" + championId + ".json")
|
||||
const { data: championData } : ChampionResponse = await useFetch(CDRAGON_BASE + "plugins/rcp-be-lol-game-data/global/default/v1/champions/" + props.championId + ".json")
|
||||
const championName = championData.value.name
|
||||
const championDescription = championData.value.title
|
||||
</script>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
const props = defineProps<{
|
||||
builds: Builds
|
||||
}>()
|
||||
const builds = props.builds
|
||||
|
||||
const {data : items} : ItemResponse = await useFetch(CDRAGON_BASE + "plugins/rcp-be-lol-game-data/global/default/v1/items.json")
|
||||
const itemMap = reactive(new Map())
|
||||
@@ -10,9 +9,15 @@ for(let item of items.value) {
|
||||
itemMap.set(item.id, item)
|
||||
}
|
||||
|
||||
builds.tree.children.splice(1, builds.tree.children.length - 1)
|
||||
if(builds.tree.children[0] != null && builds.tree.children[0] != undefined)
|
||||
builds.tree.children[0].children.splice(1, builds.tree.children[0].children.length - 1)
|
||||
watch(() => props.builds, () => trimBuilds(props.builds))
|
||||
trimBuilds(props.builds)
|
||||
|
||||
function trimBuilds(builds : Builds) {
|
||||
builds.tree.children.splice(1, builds.tree.children.length - 1)
|
||||
if(builds.tree.children[0] != null && builds.tree.children[0] != undefined)
|
||||
builds.tree.children[0].children.splice(1, builds.tree.children[0].children.length - 1)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { LANE_IMAGES, LANE_IMAGES_HOVER, LANE_IMAGES_SELECTED } from '~/utils/cdragon';
|
||||
|
||||
const emit = defineEmits<{
|
||||
filterChange: [value: number]
|
||||
}>()
|
||||
|
||||
const POSITIONS = ["top", "jungle", "middle", "bottom", "utility"]
|
||||
const LANE_IMAGES = Array(5).fill("").map((_, index) => "/img/lanes/icon-position-" + POSITIONS[index] + ".png")
|
||||
const LANE_IMAGES_HOVER = Array(5).fill("").map((_, index) => "/img/lanes/icon-position-" + POSITIONS[index] + "-hover.png")
|
||||
const LANE_IMAGES_SELECTED = Array(5).fill("").map((_, index) => "/img/lanes/icon-position-" + POSITIONS[index] + "-blue.png")
|
||||
|
||||
const laneImgs = Array(5).fill(ref("")).map((_, index) => ref(LANE_IMAGES[index]))
|
||||
const laneFilter = ref(-1)
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ const props = defineProps<{
|
||||
pickrate: number}>
|
||||
}>()
|
||||
|
||||
const runes = props.runes
|
||||
|
||||
const currentlySelectedPage = ref(0)
|
||||
const primaryStyles : Ref<Array<PerkStyle>> = ref([])
|
||||
const secondaryStyles : Ref<Array<PerkStyle>> = ref([])
|
||||
@@ -21,22 +19,35 @@ for(let perk of perks_data.value) {
|
||||
}
|
||||
|
||||
let { data: stylesData } : PerkStylesResponse = await useFetch(CDRAGON_BASE + "plugins/rcp-be-lol-game-data/global/default/v1/perkstyles.json")
|
||||
for(let style of stylesData.value.styles) {
|
||||
for(let rune of runes) {
|
||||
if(style.id == rune.primaryStyle) {
|
||||
primaryStyles.value.push(style)
|
||||
for(let perk of style.slots[0].perks) {
|
||||
if(rune.selections.includes(perk)) {
|
||||
keystoneIds.value.push(perk)
|
||||
watch(() => props.runes, (newRunes, oldRunes) => {
|
||||
currentlySelectedPage.value = 0
|
||||
primaryStyles.value = []
|
||||
secondaryStyles.value = []
|
||||
keystoneIds.value = []
|
||||
|
||||
refreshStylesKeystones()
|
||||
})
|
||||
|
||||
function refreshStylesKeystones() {
|
||||
for(let style of stylesData.value.styles) {
|
||||
for(let rune of props.runes) {
|
||||
if(style.id == rune.primaryStyle) {
|
||||
primaryStyles.value.push(style)
|
||||
for(let perk of style.slots[0].perks) {
|
||||
if(rune.selections.includes(perk)) {
|
||||
keystoneIds.value.push(perk)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(style.id == rune.secondaryStyle) {
|
||||
secondaryStyles.value.push(style)
|
||||
if(style.id == rune.secondaryStyle) {
|
||||
secondaryStyles.value.push(style)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
refreshStylesKeystones()
|
||||
|
||||
function runeSelect(index: number) {
|
||||
currentlySelectedPage.value = index
|
||||
}
|
||||
@@ -45,8 +56,12 @@ function runeSelect(index: number) {
|
||||
|
||||
<template>
|
||||
<div style="width: fit-content;">
|
||||
<RunePage style="margin:auto; width: fit-content;" :primaryStyleId="runes[currentlySelectedPage].primaryStyle" :secondaryStyleId="runes[currentlySelectedPage].secondaryStyle" :selectionIds="runes[currentlySelectedPage].selections" />
|
||||
<div style="display: flex; margin-top: 20px;">
|
||||
<RunePage v-if="runes[currentlySelectedPage] != undefined && runes[currentlySelectedPage] != null"
|
||||
style="margin:auto; width: fit-content;"
|
||||
:primaryStyleId="runes[currentlySelectedPage].primaryStyle"
|
||||
:secondaryStyleId="runes[currentlySelectedPage].secondaryStyle"
|
||||
:selectionIds="runes[currentlySelectedPage].selections" />
|
||||
<div style="display: flex; margin-top: 20px; justify-content: center;">
|
||||
<div v-for="(_, i) in runes" :class="'rune-selector-entry ' + (i == currentlySelectedPage ? 'rune-selector-entry-selected' : '')" @click="runeSelect(i)">
|
||||
<div style="display: flex; margin-top: 20px;">
|
||||
<NuxtImg v-if="primaryStyles[i] != null && primaryStyles[i] != undefined"
|
||||
|
||||
@@ -1,27 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import { LANE_IMAGES, lanePositionToIndex } from '~/utils/cdragon';
|
||||
|
||||
defineProps<{
|
||||
championName: String
|
||||
championLanes: any
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
stateChange: [state: String]
|
||||
stateChange: [state: String, lane: number]
|
||||
}>()
|
||||
|
||||
const state = ref("runes")
|
||||
const laneState = ref(0)
|
||||
|
||||
function handleStateChange(newState : string) {
|
||||
function handleStateChange(newState : string, newLane: number) {
|
||||
state.value = newState;
|
||||
emit('stateChange', newState)
|
||||
laneState.value = newLane;
|
||||
emit('stateChange', newState, newLane)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="sidebar-container">
|
||||
<Logo font-size="2.6rem" img-width="60" style="padding-left: 15px; padding-right: 15px; margin-top: 30px;"/>
|
||||
<h1 class="sidebar-link" style="margin-top: 30px; font-size: 2.4rem; padding-left: 20px;">{{ championName }}</h1>
|
||||
<h2 :class="'sidebar-link ' + (state == 'runes' ? 'sidebar-link-selected' : '')"
|
||||
@click="handleStateChange('runes')" style="margin-top: 10px; font-size: 1.9rem; padding-left: 35px;">Runes</h2>
|
||||
<h2 :class="'sidebar-link ' + (state == 'items' ? 'sidebar-link-selected' : '')"
|
||||
@click="handleStateChange('items')" style="margin-top: 10px; font-size: 1.9rem; padding-left: 35px;">Items</h2>
|
||||
|
||||
<div v-for="(lane, i) in championLanes">
|
||||
|
||||
<div style="display: flex; align-items: center; margin-top: 30px;">
|
||||
<h1 style="font-size: 2.4rem; padding-left: 20px;">{{ championName }}</h1>
|
||||
<img style="margin-left: 10px;" width="40" height="40" :src="LANE_IMAGES[lanePositionToIndex(lane.data)]" />
|
||||
<h2 style="margin-left: 5px; font-size: 1.8rem; font-weight: 200;">{{ lane.data.toLowerCase() }}</h2>
|
||||
</div>
|
||||
|
||||
<h2 :class="'sidebar-link ' + (state == 'runes' && laneState == i ? 'sidebar-link-selected' : '')"
|
||||
@click="handleStateChange('runes', i)" style="margin-top: 10px; font-size: 1.9rem; padding-left: 35px;">Runes</h2>
|
||||
<h2 :class="'sidebar-link ' + (state == 'items' && laneState == i ? 'sidebar-link-selected' : '')"
|
||||
@click="handleStateChange('items', i)" style="margin-top: 10px; font-size: 1.9rem; padding-left: 35px;">Items</h2>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -8,15 +8,12 @@ const emit = defineEmits<{
|
||||
refresh: []
|
||||
}>()
|
||||
|
||||
const item = props.tree
|
||||
|
||||
const {data : items} : ItemResponse = await useFetch(CDRAGON_BASE + "plugins/rcp-be-lol-game-data/global/default/v1/items.json")
|
||||
const itemMap = reactive(new Map())
|
||||
for(let item of items.value) {
|
||||
itemMap.set(item.id, item)
|
||||
}
|
||||
|
||||
import type { TreeItem } from '#build/components';
|
||||
import pkg from 'svg-dom-arrows';
|
||||
const { LinePath } = pkg;
|
||||
|
||||
@@ -28,6 +25,18 @@ onMounted(() => {
|
||||
emit('mount', start.value!!)
|
||||
})
|
||||
|
||||
onBeforeUpdate(() => {
|
||||
for(let arrow of arrows) {
|
||||
arrow.release()
|
||||
}
|
||||
arrows.splice(0, arrows.length)
|
||||
})
|
||||
|
||||
onUpdated(() => {
|
||||
refreshArrows()
|
||||
emit('mount', start.value!!)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
for(let arrow of arrows) {
|
||||
arrow.release()
|
||||
@@ -84,13 +93,13 @@ function handleRefresh() {
|
||||
<template>
|
||||
<div style="display: flex; align-items: center;">
|
||||
|
||||
<div v-if="item.data != undefined && item.data != null" style="width: fit-content; height: fit-content;">
|
||||
<img ref="start" class="item-img" width="64" height="64" :alt="item.data.toString()" :src="CDRAGON_BASE + mapPath(itemMap.get(item.data).iconPath)" />
|
||||
<h3 style="width: fit-content; margin:auto; margin-bottom: 10px;">{{ item.count }}</h3>
|
||||
<div v-if="tree.data != undefined && tree.data != null" style="width: fit-content; height: fit-content;">
|
||||
<img ref="start" class="item-img" width="64" height="64" :alt="tree.data.toString()" :src="CDRAGON_BASE + mapPath(itemMap.get(tree.data).iconPath)" />
|
||||
<h3 style="width: fit-content; margin:auto; margin-bottom: 10px;">{{ tree.count }}</h3>
|
||||
</div>
|
||||
|
||||
<div style="margin-left: 30px;">
|
||||
<div style="width: fit-content; height: fit-content;" v-for="child in item.children">
|
||||
<div style="width: fit-content; height: fit-content;" v-for="child in tree.children">
|
||||
<TreeItem @refresh="handleRefresh" @mount="(end) => handleSubtreeMount(end)" :tree="child" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
const route = useRoute()
|
||||
const championAlias = route.params.alias
|
||||
const championAlias = route.params.alias as string
|
||||
|
||||
const { data : championData } = await useFetch("/api/champion/" + championAlias.toLowerCase())
|
||||
const { data : championData } : {data : Ref<ChampionData>} = await useFetch("/api/champion/" + championAlias.toLowerCase())
|
||||
const championId = championData.value.id
|
||||
|
||||
const laneState = ref(0)
|
||||
const state = ref("runes")
|
||||
const lane = ref(championData.value.lanes[laneState.value])
|
||||
function updateState(newState : string, newLane : number) {
|
||||
state.value = newState
|
||||
laneState.value = newLane
|
||||
lane.value = championData.value.lanes[laneState.value]
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -13,13 +20,15 @@ const state = ref("runes")
|
||||
<Title>{{ championData.name }} - BuildPath</Title>
|
||||
</Head>
|
||||
|
||||
<SideBar :champion-name="championData.name" @state-change="(newState) => state = newState"/>
|
||||
<SideBar :champion-name="championData.name"
|
||||
:champion-lanes="championData.lanes"
|
||||
@state-change="updateState"/>
|
||||
|
||||
<!-- <div style="display: flex; width: fit-content; margin: auto; margin-left: 330px;"> -->
|
||||
<div style="margin-top: 64px; margin-left: 339px;">
|
||||
<ChampionTitle :champion-id="championId" :winrate="championData.winrate" :pickrate="championData.pickrate" :game-count="championData.gameCount" />
|
||||
<RuneSelector v-if="state == 'runes' && championData.gameCount > 0" style="margin: auto; margin-top: 40px;" :runes="championData.runes" />
|
||||
<ItemViewer v-if="state == 'items' && championData.gameCount > 0" style="margin:auto; margin-top: 40px;" :builds="championData.builds" />
|
||||
<ChampionTitle v-if="championData.gameCount > 0" :champion-id="championId" :winrate="lane.winrate" :pickrate="lane.pickrate" :game-count="lane.count" />
|
||||
<RuneSelector v-if="state == 'runes' && championData.gameCount > 0" style="margin: auto; margin-top: 40px;" :runes="lane.runes" />
|
||||
<ItemViewer v-if="state == 'items' && championData.gameCount > 0" style="margin:auto; margin-top: 40px;" :builds="lane.builds" />
|
||||
<h2 v-if="championData.gameCount == 0" style="margin: auto; margin-top: 20px; width: fit-content;">Sorry, there is no data for this champion :(</h2>
|
||||
</div>
|
||||
<!-- <ItemViewer v-if="championData.gameCount > 0" style="margin-top: 64px; margin-left: 64px;" :builds="championData.builds" /> -->
|
||||
|
||||
43
frontend/types/api.ts
Normal file
43
frontend/types/api.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
declare global {
|
||||
type ItemTree = {
|
||||
count: number
|
||||
data: number
|
||||
children: Array<ItemTree>
|
||||
}
|
||||
type Builds = {
|
||||
start: Array<{count: number, data: number}>
|
||||
tree: ItemTree
|
||||
bootsFirst: number
|
||||
boots: Array<{count: number, data: number}>
|
||||
lateGame: Array<{count: number, data: number}>
|
||||
}
|
||||
type Rune = {
|
||||
count: number
|
||||
primaryStyle: number
|
||||
secondaryStyle: number
|
||||
selections: Array<number>
|
||||
pickrate: number
|
||||
}
|
||||
type LaneData = {
|
||||
data: string
|
||||
count: number
|
||||
winningMatches: number
|
||||
losingMatches: number
|
||||
winrate: number
|
||||
pickrate: number
|
||||
runes: Array<Rune>
|
||||
builds: Builds
|
||||
}
|
||||
|
||||
type ChampionData = {
|
||||
id: number
|
||||
name: string
|
||||
alias: string
|
||||
gameCount: number
|
||||
winrate: number
|
||||
pickrate: number
|
||||
lanes: Array<LaneData>
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -1,16 +0,0 @@
|
||||
declare global {
|
||||
type ItemTree = {
|
||||
count: number
|
||||
data: number
|
||||
children: Array<ItemTree>
|
||||
}
|
||||
type Builds = {
|
||||
start: Array<{count: number, data: number}>
|
||||
tree: ItemTree
|
||||
bootsFirst: number
|
||||
boots: Array<{count: number, data: number}>
|
||||
lateGame: Array<{count: number, data: number}>
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -1,8 +0,0 @@
|
||||
const CDRAGON_BASE = "https://raw.communitydragon.org/latest/"
|
||||
|
||||
function mapPath(assetPath) {
|
||||
if(assetPath === undefined || assetPath === null) return ""
|
||||
return assetPath.toLowerCase().replace("/lol-game-data/assets/", "plugins/rcp-be-lol-game-data/global/default/")
|
||||
}
|
||||
|
||||
export { mapPath, CDRAGON_BASE}
|
||||
31
frontend/utils/cdragon.ts
Normal file
31
frontend/utils/cdragon.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
const CDRAGON_BASE = "https://raw.communitydragon.org/latest/"
|
||||
|
||||
/* Lanes */
|
||||
const POSITIONS = ["top", "jungle", "middle", "bottom", "utility"]
|
||||
const LANE_IMAGES = Array(5).fill("").map((_, index) => "/img/lanes/icon-position-" + POSITIONS[index] + ".png")
|
||||
const LANE_IMAGES_HOVER = Array(5).fill("").map((_, index) => "/img/lanes/icon-position-" + POSITIONS[index] + "-hover.png")
|
||||
const LANE_IMAGES_SELECTED = Array(5).fill("").map((_, index) => "/img/lanes/icon-position-" + POSITIONS[index] + "-blue.png")
|
||||
function laneIndexToPosition(index : number) {
|
||||
switch(index) {
|
||||
case 0: return "top"
|
||||
case 1: return "jungle"
|
||||
case 2: return "middle"
|
||||
case 3: return "bottom"
|
||||
case 4: return "utility"
|
||||
}
|
||||
return null
|
||||
}
|
||||
function lanePositionToIndex(position : string) {
|
||||
const p = position.toLowerCase()
|
||||
for(let i = 0; i < POSITIONS.length; i++) {
|
||||
if(p == POSITIONS[i]) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function mapPath(assetPath : string) {
|
||||
if(assetPath === undefined || assetPath === null) return ""
|
||||
return assetPath.toLowerCase().replace("/lol-game-data/assets/", "plugins/rcp-be-lol-game-data/global/default/")
|
||||
}
|
||||
|
||||
export { mapPath, CDRAGON_BASE, laneIndexToPosition, lanePositionToIndex, POSITIONS, LANE_IMAGES, LANE_IMAGES_HOVER, LANE_IMAGES_SELECTED}
|
||||
@@ -46,6 +46,16 @@ type Champion = {
|
||||
name: String
|
||||
alias: String
|
||||
}
|
||||
type LaneData = {
|
||||
data: string
|
||||
count: number
|
||||
winningMatches: number
|
||||
losingMatches: number
|
||||
winrate: number
|
||||
pickrate: number
|
||||
runes: Array<Rune>
|
||||
builds: Builds
|
||||
}
|
||||
|
||||
function handleParticipantRunes(participant, runes: Array<Rune>) {
|
||||
const primaryStyle = participant.perks.styles[0].style
|
||||
@@ -141,9 +151,7 @@ async function championInfos(client, patch: number, champion: Champion) {
|
||||
let winningMatches = 0;
|
||||
let losingMatches = 0;
|
||||
let totalMatches = 0;
|
||||
const lanes : Array<{data: string, count: number}> = [];
|
||||
const runes : Array<Rune> = [];
|
||||
const builds : Builds = {tree:treeInit(), start: [], bootsFirst: 0, boots: [], lateGame: []}
|
||||
const lanes : Array<LaneData> = [];
|
||||
for await (let match of allMatches) {
|
||||
totalMatches += 1;
|
||||
let participantIndex = 0;
|
||||
@@ -158,16 +166,24 @@ async function championInfos(client, patch: number, champion: Champion) {
|
||||
losingMatches += 1;
|
||||
|
||||
// Lanes
|
||||
// TODO: make stats lane-dependant
|
||||
const already = lanes.find((x) => x.data == participant.teamPosition)
|
||||
if(already == undefined) lanes.push({count:1, data: participant.teamPosition})
|
||||
else already.count += 1
|
||||
let lane = lanes.find((x) => x.data == participant.teamPosition)
|
||||
if(lane == undefined) {
|
||||
const builds : Builds = {tree:treeInit(), start: [], bootsFirst: 0, boots: [], lateGame: []}
|
||||
lane = {count:1, data: participant.teamPosition, runes:[], builds:builds, winningMatches: 0, losingMatches: 0, winrate: 0, pickrate: 0}
|
||||
lanes.push(lane)
|
||||
}
|
||||
else lane.count += 1
|
||||
|
||||
if(participant.win)
|
||||
lane.winningMatches += 1;
|
||||
else
|
||||
lane.losingMatches += 1;
|
||||
|
||||
// Runes
|
||||
handleParticipantRunes(participant, runes)
|
||||
handleParticipantRunes(participant, lane.runes)
|
||||
|
||||
// Items
|
||||
handleMatchItems(match.timeline, participantIndex, builds)
|
||||
handleMatchItems(match.timeline, participantIndex, lane.builds)
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -179,31 +195,44 @@ async function championInfos(client, patch: number, champion: Champion) {
|
||||
lanes.sort((a, b) => b.count - a.count)
|
||||
|
||||
// Filter runes to keep 3 most played
|
||||
runes.sort((a, b) => b.count - a.count)
|
||||
if(runes.length > 3)
|
||||
runes.splice(3, runes.length - 3)
|
||||
// Compute runes pickrate
|
||||
for(let rune of runes)
|
||||
rune.pickrate = rune.count / totalChampionMatches;
|
||||
for(let lane of lanes) {
|
||||
const runes = lane.runes
|
||||
|
||||
// Cut item tree branches to keep only 4 branches every time and with percentage threshold
|
||||
builds.tree.count = totalChampionMatches;
|
||||
treeCutBranches(builds.tree, 4, 0.05)
|
||||
treeSort(builds.tree)
|
||||
runes.sort((a, b) => b.count - a.count)
|
||||
if(runes.length > 3)
|
||||
runes.splice(3, runes.length - 3)
|
||||
// Compute runes pickrate
|
||||
for(let rune of runes)
|
||||
rune.pickrate = rune.count / lane.count;
|
||||
}
|
||||
|
||||
// Cut item start, to only 4 and with percentage threshold
|
||||
arrayRemovePercentage(builds.start, totalChampionMatches, 0.05)
|
||||
builds.start.sort((a, b) => b.count - a.count)
|
||||
if(builds.start.length > 4)
|
||||
builds.start.splice(4, builds.start.length - 4)
|
||||
for(let lane of lanes) {
|
||||
const builds = lane.builds
|
||||
|
||||
// Remove boots that are not within percentage threshold
|
||||
arrayRemovePercentage(builds.boots, totalChampionMatches, 0.05)
|
||||
builds.boots.sort((a, b) => b.count - a.count)
|
||||
// Cut item tree branches to keep only 4 branches every time and with percentage threshold
|
||||
builds.tree.count = lane.count;
|
||||
treeCutBranches(builds.tree, 4, 0.05)
|
||||
treeSort(builds.tree)
|
||||
|
||||
builds.bootsFirst /= (winningMatches + losingMatches)
|
||||
// Cut item start, to only 4 and with percentage threshold
|
||||
arrayRemovePercentage(builds.start, lane.count, 0.05)
|
||||
builds.start.sort((a, b) => b.count - a.count)
|
||||
if(builds.start.length > 4)
|
||||
builds.start.splice(4, builds.start.length - 4)
|
||||
|
||||
builds.lateGame.sort((a, b) => b.count - a.count)
|
||||
// Remove boots that are not within percentage threshold
|
||||
arrayRemovePercentage(builds.boots, lane.count, 0.05)
|
||||
builds.boots.sort((a, b) => b.count - a.count)
|
||||
|
||||
builds.bootsFirst /= lane.count
|
||||
|
||||
builds.lateGame.sort((a, b) => b.count - a.count)
|
||||
}
|
||||
|
||||
for(let lane of lanes) {
|
||||
lane.winrate = lane.winningMatches / lane.count
|
||||
lane.pickrate = lane.count / totalMatches
|
||||
}
|
||||
|
||||
return {name: champion.name,
|
||||
alias: champion.alias.toLowerCase(),
|
||||
@@ -212,8 +241,6 @@ async function championInfos(client, patch: number, champion: Champion) {
|
||||
winrate: winningMatches / totalChampionMatches,
|
||||
gameCount: totalChampionMatches,
|
||||
pickrate: totalChampionMatches/totalMatches,
|
||||
runes: runes,
|
||||
builds: builds
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user