Basic fielding stats leaders - needs filter on position specific x-check count
This commit is contained in:
parent
69a59c7d72
commit
4bb2795929
@ -89,6 +89,25 @@ export async function fetchFieldingStatsBySeasonAndTeamId(seasonNumber: number,
|
||||
return fieldingStatsResponse.stats.map(normalizeFieldingStat)
|
||||
}
|
||||
|
||||
export async function fetchFieldingStatsBySeason(seasonNumber: number, isRegularSeason: boolean): Promise<FieldingStat[]> {
|
||||
// different endpoint for pre-modern stats (/plays) era
|
||||
if (seasonNumber < MODERN_STAT_ERA_START) {
|
||||
return []
|
||||
}
|
||||
|
||||
// TODO might want to make this playerpositionteam grouping (currently does not exist)
|
||||
const response = await fetch(`${SITE_URL}/api/v3/plays/fielding?season=${seasonNumber}&limit=10000&group_by=playerposition&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
||||
|
||||
const fieldingStatsResponse: {
|
||||
count: number
|
||||
stats: FieldingStatRaw[]
|
||||
} = await response.json()
|
||||
|
||||
if (fieldingStatsResponse.count === 0) return []
|
||||
|
||||
return fieldingStatsResponse.stats.map(normalizeFieldingStat)
|
||||
}
|
||||
|
||||
async function fetchLegacyFieldingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<FieldingStat[]> {
|
||||
const response = await fetch(`${SITE_URL}/api/v3/fieldingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
||||
|
||||
|
||||
@ -56,10 +56,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { Team } from '@/services/apiResponseTypes'
|
||||
import { fetchBattingStatsBySeason, type BattingStat } from '@/services/battingStatsService'
|
||||
import { type LeagueInfo, fetchCurrentLeagueInfo } from '@/services/currentService'
|
||||
import type { FieldingStat } from '@/services/fieldingStatsService'
|
||||
import { fetchFieldingStatsBySeason, type FieldingStat } from '@/services/fieldingStatsService'
|
||||
import { fetchPitchingStatsBySeason, type PitchingStat } from '@/services/pitchingStatsService'
|
||||
import type { Player } from '@/services/playersService'
|
||||
import { CURRENT_SEASON, GAMES_PER_WEEK, WEEKS_PER_SEASON } from '@/services/utilities'
|
||||
|
||||
interface LeaderboardTableData<T> {
|
||||
@ -69,12 +71,34 @@ interface LeaderboardTableData<T> {
|
||||
precision?: number
|
||||
}
|
||||
|
||||
interface FlatFieldingStat {
|
||||
player: Player
|
||||
team: Team
|
||||
xCheckCount: number
|
||||
hit: number
|
||||
error: number
|
||||
stolenBaseCheckCount: number
|
||||
stolenBaseCount: number
|
||||
caughtStealingCount: number
|
||||
caughtStealingPercent: number
|
||||
passedBallCount: number
|
||||
weightedFieldingPercentPitcher: number
|
||||
weightedFieldingPercentCatcher: number
|
||||
weightedFieldingPercentFirstBase: number
|
||||
weightedFieldingPercentSecondBase: number
|
||||
weightedFieldingPercentThirdBase: number
|
||||
weightedFieldingPercentShortstop: number
|
||||
weightedFieldingPercentLeftField: number
|
||||
weightedFieldingPercentCenterField: number
|
||||
weightedFieldingPercentRightField: number
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'LeaderboardView',
|
||||
data() {
|
||||
return {
|
||||
allPlayersBattingStats: [] as BattingStat[],
|
||||
allPlayersFieldingStats: [] as FieldingStat[],
|
||||
allPlayersFieldingStats: [] as FlatFieldingStat[],
|
||||
allPlayersPitchingStats: [] as PitchingStat[],
|
||||
currentSeasonNumber: CURRENT_SEASON,
|
||||
seasonNumber: CURRENT_SEASON,
|
||||
@ -110,7 +134,7 @@ export default {
|
||||
qualifyingPitchingStats(): PitchingStat[] {
|
||||
return this.allPlayersPitchingStats.filter(ps => ps.ip >= this.inningsPitchedMinimum)
|
||||
},
|
||||
leaderboardTableData(): LeaderboardTableData<BattingStat>[] | LeaderboardTableData<PitchingStat>[] | LeaderboardTableData<FieldingStat>[] {
|
||||
leaderboardTableData(): LeaderboardTableData<BattingStat>[] | LeaderboardTableData<PitchingStat>[] | LeaderboardTableData<FlatFieldingStat>[] {
|
||||
if (this.statType == 'Batting') {
|
||||
return this.battingLeaderboardTableData
|
||||
}
|
||||
@ -181,8 +205,28 @@ export default {
|
||||
{ title: 'Inherited Runners Scored', columnName: 'IRS', statPropertyName: 'ir_sc' }
|
||||
]
|
||||
},
|
||||
fieldingLeaderboardTableData(): LeaderboardTableData<FieldingStat>[] {
|
||||
return []
|
||||
fieldingLeaderboardTableData(): LeaderboardTableData<FlatFieldingStat>[] {
|
||||
return [
|
||||
{ title: 'Fielding Chances', columnName: 'X-Ch', statPropertyName: 'xCheckCount' },
|
||||
{ title: 'Weighted Fielding % (RF)', columnName: 'wF%', statPropertyName: 'weightedFieldingPercentRightField', precision: 3 },
|
||||
{ title: 'Weighted Fielding % (CF)', columnName: 'wF%', statPropertyName: 'weightedFieldingPercentCenterField', precision: 3 },
|
||||
{ title: 'Weighted Fielding % (LF)', columnName: 'wF%', statPropertyName: 'weightedFieldingPercentLeftField', precision: 3 },
|
||||
|
||||
{ title: 'Weighted Fielding % (SS)', columnName: 'wF%', statPropertyName: 'weightedFieldingPercentShortstop', precision: 3 },
|
||||
{ title: 'Weighted Fielding % (3B)', columnName: 'wF%', statPropertyName: 'weightedFieldingPercentThirdBase', precision: 3 },
|
||||
{ title: 'Weighted Fielding % (2B)', columnName: 'wF%', statPropertyName: 'weightedFieldingPercentSecondBase', precision: 3 },
|
||||
{ title: 'Weighted Fielding % (1B)', columnName: 'wF%', statPropertyName: 'weightedFieldingPercentFirstBase', precision: 3 },
|
||||
|
||||
{ title: 'Weighted Fielding % (C)', columnName: 'wF%', statPropertyName: 'weightedFieldingPercentCatcher', precision: 3 },
|
||||
{ title: 'Weighted Fielding % (P)', columnName: 'wF%', statPropertyName: 'weightedFieldingPercentPitcher', precision: 3 },
|
||||
{ title: 'Errors', columnName: 'E', statPropertyName: 'error' },
|
||||
{ title: 'Hits Allowed', columnName: 'X-Hit', statPropertyName: 'hit' },
|
||||
|
||||
{ title: 'Passed Balls', columnName: 'PB', statPropertyName: 'passedBallCount' },
|
||||
{ title: 'Steal Attempts Against', columnName: 'SBa', statPropertyName: 'stolenBaseCheckCount' },
|
||||
{ title: 'Runners Thrown Out (C)', columnName: 'CSc', statPropertyName: 'caughtStealingCount' },
|
||||
{ title: 'Caught Stealing % (C)', columnName: 'CS%', statPropertyName: 'caughtStealingPercent', precision: 1 },
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -199,7 +243,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTop10StatByCategory(stat: keyof BattingStat | keyof PitchingStat | keyof FieldingStat): (BattingStat | PitchingStat | FieldingStat)[] {
|
||||
getTop10StatByCategory(stat: keyof BattingStat | keyof PitchingStat | keyof FlatFieldingStat): (BattingStat | PitchingStat | FlatFieldingStat)[] {
|
||||
if (this.statType == 'Batting') {
|
||||
return this.getTop10BattingStatByCategory(stat as keyof BattingStat)
|
||||
}
|
||||
@ -207,7 +251,7 @@ export default {
|
||||
return this.getTop10PitchingStatByCategory(stat as keyof PitchingStat)
|
||||
}
|
||||
|
||||
return [] // this.getTop10FieldingStatByCategory(stat as keyof FieldingStat)
|
||||
return this.getTop10FieldingStatByCategory(stat as keyof FlatFieldingStat)
|
||||
},
|
||||
getTop10BattingStatByCategory(stat: keyof BattingStat): BattingStat[] {
|
||||
// concat an empty array so that the existing array is not sorted as a side effect
|
||||
@ -225,19 +269,28 @@ export default {
|
||||
|
||||
return statBase.sort((a, b) => sortMultiplier * ((b[stat] as number) - (a[stat] as number))).slice(0, 10)
|
||||
},
|
||||
// getTop10FieldingStatByCategory(stat: keyof FieldingStat): FieldingStat[] {
|
||||
// // concat an empty array so that the existing array is not sorted as a side effect
|
||||
getTop10FieldingStatByCategory(stat: keyof FlatFieldingStat): FlatFieldingStat[] {
|
||||
// High: 2B/SS - 2 XCh/wk
|
||||
// Med: 1B/3B/CF - 1 XCh/wk
|
||||
// Low: LF/RF/P/C - 0.5 XCh/wk
|
||||
const highXCheckGroup: (keyof FlatFieldingStat)[] = ['weightedFieldingPercentSecondBase', 'weightedFieldingPercentShortstop']
|
||||
const mediumXCheckGroup: (keyof FlatFieldingStat)[] = ['weightedFieldingPercentFirstBase', 'weightedFieldingPercentThirdBase', 'weightedFieldingPercentCenterField']
|
||||
const lowXCheckGroup: (keyof FlatFieldingStat)[] = ['weightedFieldingPercentLeftField', 'weightedFieldingPercentRightField', 'weightedFieldingPercentCatcher', 'weightedFieldingPercentCatcher', 'weightedFieldingPercentPitcher']
|
||||
|
||||
// return []//this.qualifyingBattingStats.concat([]).sort((a, b) => (b[stat] as number) - (a[stat] as number)).slice(0, 10)
|
||||
// },
|
||||
formatNumericalStat(stat: BattingStat | PitchingStat | FieldingStat, property: keyof BattingStat | keyof PitchingStat | keyof FieldingStat, precision: number): number | string {
|
||||
const xCheckCountPerWeek = highXCheckGroup.includes(stat) ? 2 : mediumXCheckGroup.includes(stat) ? 1 : lowXCheckGroup.includes(stat) ? 0.5 : 0
|
||||
|
||||
return this.allPlayersFieldingStats
|
||||
.filter(stat => stat.xCheckCount >= xCheckCountPerWeek * this.weekNumberForCalcs)
|
||||
.sort((a, b) => ((b[stat] as number) - (a[stat] as number))).slice(0, 10)
|
||||
},
|
||||
formatNumericalStat(stat: BattingStat | PitchingStat | FlatFieldingStat, property: keyof BattingStat | keyof PitchingStat | keyof FlatFieldingStat, precision: number): number | string {
|
||||
let numericalStat: number = 0
|
||||
|
||||
if (this.statType == 'Batting') numericalStat = (stat as BattingStat)[property as keyof BattingStat] as number
|
||||
if (this.statType == 'Pitching') numericalStat = (stat as PitchingStat)[property as keyof PitchingStat] as number
|
||||
if (this.statType == 'Fielding') numericalStat = (stat as FieldingStat)[property as keyof FieldingStat] as number
|
||||
if (this.statType == 'Fielding') numericalStat = (stat as FlatFieldingStat)[property as keyof FlatFieldingStat] as number
|
||||
|
||||
if (Number.isInteger(numericalStat)) return numericalStat
|
||||
if (Number.isInteger(numericalStat) && !precision) return numericalStat
|
||||
|
||||
return numericalStat.toFixed(precision)
|
||||
},
|
||||
@ -252,7 +305,75 @@ export default {
|
||||
this.allPlayersPitchingStats = await fetchPitchingStatsBySeason(this.seasonNumber, true)
|
||||
}
|
||||
if (this.statType == 'Fielding') {
|
||||
this.allPlayersFieldingStats = []
|
||||
const allPlayerPositionFieldingStats: FieldingStat[] = await fetchFieldingStatsBySeason(this.seasonNumber, true)
|
||||
const aggregatedFieldingStatsByPlayer: { [playerName: string]: FlatFieldingStat } = {}
|
||||
allPlayerPositionFieldingStats.forEach(stat => {
|
||||
if (!aggregatedFieldingStatsByPlayer[stat.player.name]) {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name] = {
|
||||
player: stat.player,
|
||||
team: stat.team,
|
||||
xCheckCount: 0,
|
||||
hit: 0,
|
||||
error: 0,
|
||||
stolenBaseCheckCount: 0,
|
||||
stolenBaseCount: 0,
|
||||
caughtStealingCount: 0,
|
||||
caughtStealingPercent: 0,
|
||||
passedBallCount: 0,
|
||||
weightedFieldingPercentPitcher: 0,
|
||||
weightedFieldingPercentCatcher: 0,
|
||||
weightedFieldingPercentFirstBase: 0,
|
||||
weightedFieldingPercentSecondBase: 0,
|
||||
weightedFieldingPercentThirdBase: 0,
|
||||
weightedFieldingPercentShortstop: 0,
|
||||
weightedFieldingPercentLeftField: 0,
|
||||
weightedFieldingPercentCenterField: 0,
|
||||
weightedFieldingPercentRightField: 0
|
||||
}
|
||||
}
|
||||
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].xCheckCount += stat.xCheckCount
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].hit += stat.hit
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].error += stat.error
|
||||
|
||||
if (stat.pos === 'P') {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].weightedFieldingPercentPitcher = stat.weightedFieldingPercent
|
||||
}
|
||||
else if (stat.pos === 'C') {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].weightedFieldingPercentCatcher = stat.weightedFieldingPercent
|
||||
// catchers have extra stats
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].stolenBaseCheckCount = stat.stolenBaseCheckCount
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].stolenBaseCount = stat.stolenBaseCount
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].caughtStealingCount = stat.caughtStealingCount
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].caughtStealingPercent = stat.caughtStealingPercent
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].passedBallCount = stat.passedBallCount
|
||||
}
|
||||
else if (stat.pos === '1B') {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].weightedFieldingPercentFirstBase = stat.weightedFieldingPercent
|
||||
}
|
||||
else if (stat.pos === '2B') {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].weightedFieldingPercentSecondBase = stat.weightedFieldingPercent
|
||||
}
|
||||
else if (stat.pos === '3B') {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].weightedFieldingPercentThirdBase = stat.weightedFieldingPercent
|
||||
}
|
||||
else if (stat.pos === 'SS') {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].weightedFieldingPercentShortstop = stat.weightedFieldingPercent
|
||||
}
|
||||
else if (stat.pos === 'LF') {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].weightedFieldingPercentLeftField = stat.weightedFieldingPercent
|
||||
}
|
||||
else if (stat.pos === 'CF') {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].weightedFieldingPercentCenterField = stat.weightedFieldingPercent
|
||||
}
|
||||
else if (stat.pos === 'RF') {
|
||||
aggregatedFieldingStatsByPlayer[stat.player.name].weightedFieldingPercentRightField = stat.weightedFieldingPercent
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
|
||||
this.allPlayersFieldingStats = Object.values(aggregatedFieldingStatsByPlayer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user