Add pitching stats
This commit is contained in:
parent
da894b9669
commit
4fbb1f0284
5
components.d.ts
vendored
5
components.d.ts
vendored
@ -5,7 +5,7 @@
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import '@vue/runtime-core'
|
||||
|
||||
export {}
|
||||
export { }
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
@ -15,10 +15,13 @@ declare module '@vue/runtime-core' {
|
||||
IconSupport: typeof import('./src/components/icons/IconSupport.vue')['default']
|
||||
IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
|
||||
LastFourGamesBattingTable: typeof import('./src/components/LastFourGamesBattingTable.vue')['default']
|
||||
LastFourGamesPitchingTable: typeof import('./src/components/LastFourGamesPitchingTable.vue')['default']
|
||||
NavBar: typeof import('./src/components/NavBar.vue')['default']
|
||||
NewsPreview: typeof import('./src/components/NewsPreview.vue')['default']
|
||||
PlayerBattingSummaryTable: typeof import('./src/components/PlayerBattingSummaryTable.vue')['default']
|
||||
PlayerCareerBattingTable: typeof import('./src/components/PlayerCareerBattingTable.vue')['default']
|
||||
PlayerCareerPitchingTable: typeof import('./src/components/PlayerCareerPitchingTable.vue')['default']
|
||||
PlayerPitchingSummaryTable: typeof import('./src/components/PlayerPitchingSummaryTable.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
StandingsTable: typeof import('./src/components/StandingsTable.vue')['default']
|
||||
|
||||
73
src/components/LastFourGamesPitchingTable.vue
Normal file
73
src/components/LastFourGamesPitchingTable.vue
Normal file
@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div class="col-sm-12">
|
||||
<h3>Last 4 Games</h3>
|
||||
<div class="table-responsive-xl">
|
||||
<table class="table table-sm table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Game</th>
|
||||
<th>W</th>
|
||||
<th>L</th>
|
||||
<th>ERA</th>
|
||||
<th>GS</th>
|
||||
<th>SV</th>
|
||||
<th>HD</th>
|
||||
<th>IP</th>
|
||||
<th>H</th>
|
||||
<th>R</th>
|
||||
<th>ER</th>
|
||||
<th>HR</th>
|
||||
<th>BB</th>
|
||||
<th>SO</th>
|
||||
<th>HBP</th>
|
||||
<th>BK</th>
|
||||
<th>WP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="last4-pitching">
|
||||
<tr v-for="gameStat in last4GamesPitching">
|
||||
<td>{{ makeWxGyFromGame(gameStat.game) }}</td>
|
||||
<td>{{ gameStat.win }}</td>
|
||||
<td>{{ gameStat.loss }}</td>
|
||||
<td>{{ gameStat.era.toFixed(2) }}</td>
|
||||
<td>{{ gameStat.gs }}</td>
|
||||
<td>{{ gameStat.save }}</td>
|
||||
<td>{{ gameStat.hold }}</td>
|
||||
<td>{{ outsToInnings(gameStat) }}</td>
|
||||
<td>{{ gameStat.hits }}</td>
|
||||
<td>{{ gameStat.run }}</td>
|
||||
<td>{{ gameStat.e_run }}</td>
|
||||
<td>{{ gameStat.hr }}</td>
|
||||
<td>{{ gameStat.bb }}</td>
|
||||
<td>{{ gameStat.so }}</td>
|
||||
<td>{{ gameStat.hbp }}</td>
|
||||
<td>{{ gameStat.balk }}</td>
|
||||
<td>{{ gameStat.wp }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { Game } from '@/services/apiResponseTypes'
|
||||
import type { PitchingStat } from '@/services/pitchingStatsService'
|
||||
import { outsToInnings } from '@/services/utilities'
|
||||
|
||||
export default {
|
||||
name: "LastFourGamesPitchingTable",
|
||||
props: {
|
||||
last4GamesPitching: { type: Array<PitchingStat>, required: true }
|
||||
},
|
||||
methods: {
|
||||
makeWxGyFromGame(game: Game | 'TOT'): string {
|
||||
if (game === 'TOT') return 'TOT'
|
||||
return `w${game.week}g${game.game_num}`
|
||||
},
|
||||
outsToInnings(stat: PitchingStat): string {
|
||||
return outsToInnings(stat)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="row" id="career-batting-row">
|
||||
<div v-if="hasBattingStats" class="row" id="career-batting-row">
|
||||
<div class="col-sm-12">
|
||||
<h3>Batting Stats</h3>
|
||||
<div class="table-responsive-xl">
|
||||
@ -118,6 +118,9 @@ export default {
|
||||
postSeasonBattingStats: { type: Array<BattingStat>, required: true }
|
||||
},
|
||||
computed: {
|
||||
hasBattingStats(): boolean {
|
||||
return !!(this.regularSeasonBattingStats.length + this.postSeasonBattingStats.length)
|
||||
},
|
||||
careerBattingStat(): BattingStat | undefined {
|
||||
if (this.regularSeasonBattingStats.length > 0) {
|
||||
// old site behavior just summed regular season stats for the career line total
|
||||
|
||||
189
src/components/PlayerCareerPitchingTable.vue
Normal file
189
src/components/PlayerCareerPitchingTable.vue
Normal file
@ -0,0 +1,189 @@
|
||||
<template>
|
||||
<div v-if="hasPitchingStats" class="row" id="career-pitching-row">
|
||||
<div class="col-sm-12">
|
||||
<h3>Pitching Stats</h3>
|
||||
<div class="table-responsive-xl">
|
||||
<table class="table table-sm table-striped" id="career-pitching">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Season</th>
|
||||
<th>W</th>
|
||||
<th>L</th>
|
||||
<th>W-L%</th>
|
||||
<th>ERA</th>
|
||||
<th>G</th>
|
||||
<th>GS</th>
|
||||
<th>SV</th>
|
||||
<th>HD</th>
|
||||
<th>BSV</th>
|
||||
<th>IP</th>
|
||||
<th>H</th>
|
||||
<th>R</th>
|
||||
<th>ER</th>
|
||||
<th>HR</th>
|
||||
<th>BB</th>
|
||||
<th>SO</th>
|
||||
<th>HBP</th>
|
||||
<th>BK</th>
|
||||
<th>WP</th>
|
||||
<th>IR</th>
|
||||
<th>IRS</th>
|
||||
<th>WHIP</th>
|
||||
<th>H/9</th>
|
||||
<th>HR/9</th>
|
||||
<th>BB/9</th>
|
||||
<th>SO/9</th>
|
||||
<th>SO/BB</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="career-pitching-table">
|
||||
<tr v-for="stat in sortedRegularAndPostSeasonPitching">
|
||||
<td>S{{ stat.seasonNumber }}{{ stat.isRegularSeason ? '' : ' / Playoffs' }}</td>
|
||||
<td>{{ stat.win }}</td>
|
||||
<td>{{ stat.loss }}</td>
|
||||
<td>{{ winPercentage(stat) }}</td>
|
||||
<td>{{ stat.era.toFixed(2) }}</td>
|
||||
<td>{{ stat.games }}</td>
|
||||
<td>{{ stat.gs }}</td>
|
||||
<td>{{ stat.save }}</td>
|
||||
<td>{{ stat.hold }}</td>
|
||||
<td>{{ stat.bsave }}</td>
|
||||
<td>{{ outsToInnings(stat) }}</td>
|
||||
<td>{{ stat.hits }}</td>
|
||||
<td>{{ stat.run }}</td>
|
||||
<td>{{ stat.e_run }}</td>
|
||||
<td>{{ stat.hr }}</td>
|
||||
<td>{{ stat.bb }}</td>
|
||||
<td>{{ stat.so }}</td>
|
||||
<td>{{ stat.hbp }}</td>
|
||||
<td>{{ stat.balk }}</td>
|
||||
<td>{{ stat.wp }}</td>
|
||||
<td>{{ stat.ir }}</td>
|
||||
<td>{{ stat.ir_sc }}</td>
|
||||
<td>{{ stat.whip.toFixed(2) }}</td>
|
||||
<td>{{ hitsPer9(stat) }}</td>
|
||||
<td>{{ hrsPer9(stat) }}</td>
|
||||
<td>{{ stat.bbPer9.toFixed(1) }}</td>
|
||||
<td>{{ stat.kPer9.toFixed(1) }}</td>
|
||||
<td>{{ stat.kPerBB.toFixed(1) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr v-if="careerPitchingStat" id="career-pitching-footer">
|
||||
<th>Career</th>
|
||||
<th>{{ careerPitchingStat.win }}</th>
|
||||
<th>{{ careerPitchingStat.loss }}</th>
|
||||
<th>{{ winPercentage(careerPitchingStat) }}</th>
|
||||
<th>{{ careerPitchingStat.era.toFixed(2) }}</th>
|
||||
<th>{{ careerPitchingStat.games }}</th>
|
||||
<th>{{ careerPitchingStat.gs }}</th>
|
||||
<th>{{ careerPitchingStat.save }}</th>
|
||||
<th>{{ careerPitchingStat.hold }}</th>
|
||||
<th>{{ careerPitchingStat.bsave }}</th>
|
||||
<th>{{ outsToInnings(careerPitchingStat) }}</th>
|
||||
<th>{{ careerPitchingStat.hits }}</th>
|
||||
<th>{{ careerPitchingStat.run }}</th>
|
||||
<th>{{ careerPitchingStat.e_run }}</th>
|
||||
<th>{{ careerPitchingStat.hr }}</th>
|
||||
<th>{{ careerPitchingStat.bb }}</th>
|
||||
<th>{{ careerPitchingStat.so }}</th>
|
||||
<th>{{ careerPitchingStat.hbp }}</th>
|
||||
<th>{{ careerPitchingStat.balk }}</th>
|
||||
<th>{{ careerPitchingStat.wp }}</th>
|
||||
<th>{{ careerPitchingStat.ir }}</th>
|
||||
<th>{{ careerPitchingStat.ir_sc }}</th>
|
||||
<th>{{ careerPitchingStat.whip.toFixed(2) }}</th>
|
||||
<th>{{ hitsPer9(careerPitchingStat) }}</th>
|
||||
<th>{{ hrsPer9(careerPitchingStat) }}</th>
|
||||
<th>{{ careerPitchingStat.bbPer9.toFixed(1) }}</th>
|
||||
<th>{{ careerPitchingStat.kPer9.toFixed(1) }}</th>
|
||||
<th>{{ careerPitchingStat.kPerBB.toFixed(1) }}</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { aggregatePitchingStats, type PitchingStat } from '@/services/pitchingStatsService'
|
||||
import { outsToInnings } from '@/services/utilities'
|
||||
|
||||
interface PitchingStatWithSeason extends PitchingStat {
|
||||
seasonNumber: number
|
||||
isRegularSeason: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "PlayerCareerPitchingTable",
|
||||
props: {
|
||||
regularSeasonPitchingStats: { type: Array<PitchingStat>, required: true },
|
||||
postSeasonPitchingStats: { type: Array<PitchingStat>, required: true }
|
||||
},
|
||||
computed: {
|
||||
hasPitchingStats(): boolean {
|
||||
return !!(this.regularSeasonPitchingStats.length + this.postSeasonPitchingStats.length)
|
||||
},
|
||||
careerPitchingStat(): PitchingStat | undefined {
|
||||
if (this.regularSeasonPitchingStats.length > 0) {
|
||||
// old site behavior just summed regular season stats for the career line total
|
||||
return aggregatePitchingStats(this.regularSeasonPitchingStats)
|
||||
}
|
||||
|
||||
return undefined
|
||||
},
|
||||
sortedRegularAndPostSeasonPitching(): PitchingStatWithSeason[] {
|
||||
let seasonStats: PitchingStatWithSeason[] = []
|
||||
|
||||
if (this.regularSeasonPitchingStats?.length) {
|
||||
seasonStats = seasonStats.concat(this.regularSeasonPitchingStats.map(stat => {
|
||||
return {
|
||||
...stat,
|
||||
seasonNumber: stat.player.season,
|
||||
isRegularSeason: true
|
||||
}
|
||||
}))
|
||||
}
|
||||
// TODO: here would be where you could filter out postseason stats if desired (like Josef requested)
|
||||
if (this.postSeasonPitchingStats?.length) {
|
||||
seasonStats = seasonStats.concat(this.postSeasonPitchingStats.map(stat => {
|
||||
return {
|
||||
...stat,
|
||||
seasonNumber: stat.player.season,
|
||||
isRegularSeason: false
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
return seasonStats.sort((s1, s2) => {
|
||||
return s1.seasonNumber - s2.seasonNumber === 0
|
||||
? s1.isRegularSeason
|
||||
? -1
|
||||
: 1
|
||||
: s1.seasonNumber - s2.seasonNumber
|
||||
})
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
outsToInnings(stat: PitchingStat): string {
|
||||
return outsToInnings(stat)
|
||||
},
|
||||
winPercentage(stat: PitchingStat): string {
|
||||
if (stat.win + stat.loss === 0) return '-'
|
||||
|
||||
return (stat.win / (stat.win + stat.loss)).toFixed(3)
|
||||
},
|
||||
hitsPer9(stat: PitchingStat): string {
|
||||
if (stat.outs === 0) return '-'
|
||||
|
||||
return (stat.hits * 27 / stat.outs).toFixed(1)
|
||||
},
|
||||
hrsPer9(stat: PitchingStat): string {
|
||||
if (stat.outs === 0) return '-'
|
||||
|
||||
return (stat.hr * 27 / stat.outs).toFixed(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
92
src/components/PlayerPitchingSummaryTable.vue
Normal file
92
src/components/PlayerPitchingSummaryTable.vue
Normal file
@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<div class="col-sm-8">
|
||||
<div class="table-responsive-xl" style="max-width:35rem">
|
||||
<table class="table table-sm table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Summary</th>
|
||||
<th>W</th>
|
||||
<th>L</th>
|
||||
<th>SV</th>
|
||||
<th>ERA</th>
|
||||
<th>G</th>
|
||||
<th>GS</th>
|
||||
<th>IP</th>
|
||||
<th>SO</th>
|
||||
<th>WHIP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="pitcher-summary-table">
|
||||
<tr v-if="currentSeasonPitching">
|
||||
<td>Season {{ currentSeasonPitching.player.season }}</td>
|
||||
<td>{{ currentSeasonPitching.win }}</td>
|
||||
<td>{{ currentSeasonPitching.loss }}</td>
|
||||
<td>{{ currentSeasonPitching.save }}</td>
|
||||
<td>{{ currentSeasonPitching.era.toFixed(2) }}</td>
|
||||
<td>{{ currentSeasonPitching.games }}</td>
|
||||
<td>{{ currentSeasonPitching.gs }}</td>
|
||||
<td>{{ outsToInnings(currentSeasonPitching) }}</td>
|
||||
<td>{{ currentSeasonPitching.so }}</td>
|
||||
<td>{{ currentSeasonPitching.whip.toFixed(2) }}</td>
|
||||
</tr>
|
||||
<tr v-if="currentPostSeasonPitching">
|
||||
<td>S{{ currentPostSeasonPitching.player.season }} / Playoffs</td>
|
||||
<td>{{ currentPostSeasonPitching.win }}</td>
|
||||
<td>{{ currentPostSeasonPitching.loss }}</td>
|
||||
<td>{{ currentPostSeasonPitching.save }}</td>
|
||||
<td>{{ currentPostSeasonPitching.era.toFixed(2) }}</td>
|
||||
<td>{{ currentPostSeasonPitching.games }}</td>
|
||||
<td>{{ currentPostSeasonPitching.gs }}</td>
|
||||
<td>{{ outsToInnings(currentPostSeasonPitching) }}</td>
|
||||
<td>{{ currentPostSeasonPitching.so }}</td>
|
||||
<td>{{ currentPostSeasonPitching.whip.toFixed(2) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot id="pitcher-summary-footer">
|
||||
<tr v-if="careerPitchingStat">
|
||||
<th>Career</th>
|
||||
<td>{{ careerPitchingStat.win }}</td>
|
||||
<td>{{ careerPitchingStat.loss }}</td>
|
||||
<td>{{ careerPitchingStat.save }}</td>
|
||||
<td>{{ careerPitchingStat.era.toFixed(2) }}</td>
|
||||
<td>{{ careerPitchingStat.games }}</td>
|
||||
<td>{{ careerPitchingStat.gs }}</td>
|
||||
<td>{{ outsToInnings(careerPitchingStat) }}</td>
|
||||
<td>{{ careerPitchingStat.so }}</td>
|
||||
<td>{{ careerPitchingStat.whip.toFixed(2) }}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { aggregatePitchingStats, type PitchingStat } from '@/services/pitchingStatsService'
|
||||
import { outsToInnings } from '@/services/utilities'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
export default {
|
||||
name: "PlayerPitchingSummaryTable",
|
||||
props: {
|
||||
currentSeasonPitching: { type: Object as PropType<PitchingStat>, required: false },
|
||||
currentPostSeasonPitching: { type: Object as PropType<PitchingStat>, required: false },
|
||||
regularSeasonPitchingStats: { type: Array<PitchingStat>, required: true }
|
||||
},
|
||||
computed: {
|
||||
careerPitchingStat(): PitchingStat | undefined {
|
||||
if (this.regularSeasonPitchingStats.length > 0) {
|
||||
// old site behavior just summed regular season stats for the career line total
|
||||
return aggregatePitchingStats(this.regularSeasonPitchingStats)
|
||||
}
|
||||
|
||||
return undefined
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
outsToInnings(stat: PitchingStat): string {
|
||||
return outsToInnings(stat)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -140,7 +140,7 @@ export async function fetchPitchingStatsBySeasonAndPlayerId(seasonNumber: number
|
||||
|
||||
const pitchingStatsResponse: {
|
||||
count: number
|
||||
stats: PitchingStat[]
|
||||
stats: PitchingStatRaw[]
|
||||
} = await response.json()
|
||||
|
||||
if (pitchingStatsResponse.count === 0) return undefined
|
||||
@ -149,7 +149,7 @@ export async function fetchPitchingStatsBySeasonAndPlayerId(seasonNumber: number
|
||||
throw new Error('pitchingStatsService.fetchPitchingStatsBySeasonAndPlayerId - Expected one stat line for season/player, return contained many')
|
||||
}
|
||||
|
||||
return pitchingStatsResponse.stats[0]
|
||||
return normalizePitchingStat(pitchingStatsResponse.stats[0])
|
||||
}
|
||||
|
||||
async function fetchLegacyPitchingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<PitchingStat | undefined> {
|
||||
@ -174,14 +174,14 @@ export async function fetchPitchingStatsForLastFourGamesBySeasonAndPlayerId(seas
|
||||
|
||||
const pitchingStatsResponse: {
|
||||
count: number
|
||||
stats: PitchingStat[]
|
||||
stats: PitchingStatRaw[]
|
||||
} = await response.json()
|
||||
|
||||
if (pitchingStatsResponse.count > 4) {
|
||||
throw new Error(`pitchingStatsService.fetchPitchingStatsForLastFourBySeasonAndPlayerId - Expected at most 4 games, return contained ${pitchingStatsResponse.count}`)
|
||||
}
|
||||
|
||||
return pitchingStatsResponse.stats
|
||||
return pitchingStatsResponse.stats.map(normalizePitchingStat)
|
||||
}
|
||||
|
||||
export function aggregatePitchingStats(pitchingStats: PitchingStat[]): PitchingStat {
|
||||
@ -277,6 +277,11 @@ export function aggregatePitchingStats(pitchingStats: PitchingStat[]): PitchingS
|
||||
|
||||
return {
|
||||
...totalStat,
|
||||
era: eraFromOuts(totalStat),
|
||||
whip: whipFromOuts(totalStat),
|
||||
kPer9: kPer9FromOuts(totalStat),
|
||||
bbPer9: bbPer9FromOuts(totalStat),
|
||||
kPerBB: kPerBB(totalStat),
|
||||
avg: avg(totalStatWithHit),
|
||||
obp: 0, //obp({pa: totalStat.}),
|
||||
slg: slg(totalStatWithHit),
|
||||
@ -399,24 +404,48 @@ function era(stat: { e_run: number, ip: number }): number {
|
||||
return stat.e_run * 9 / stat.ip
|
||||
}
|
||||
|
||||
function eraFromOuts(stat: { e_run: number, outs: number }): number {
|
||||
if (stat.outs === 0) return stat.e_run > 0 ? NaN : 0
|
||||
|
||||
return stat.e_run * 27 / stat.outs
|
||||
}
|
||||
|
||||
function whip(stat: { bb: number, hits: number, ip: number }): number {
|
||||
if (stat.ip === 0) return 0
|
||||
if (stat.ip === 0) return stat.bb + stat.hits > 0 ? NaN : 0
|
||||
|
||||
return (stat.bb + stat.hits) / stat.ip
|
||||
}
|
||||
|
||||
function whipFromOuts(stat: { bb: number, hits: number, outs: number }): number {
|
||||
if (stat.outs === 0) return stat.bb + stat.hits > 0 ? NaN : 0
|
||||
|
||||
return (stat.bb + stat.hits) * 3 / stat.outs
|
||||
}
|
||||
|
||||
function kPer9(stat: { so: number, ip: number }): number {
|
||||
if (stat.ip === 0) return 0
|
||||
|
||||
return stat.so * 9 / stat.ip
|
||||
}
|
||||
|
||||
function kPer9FromOuts(stat: { so: number, outs: number }): number {
|
||||
if (stat.outs === 0) return 0
|
||||
|
||||
return stat.so * 27 / stat.outs
|
||||
}
|
||||
|
||||
function bbPer9(stat: { bb: number, ip: number }): number {
|
||||
if (stat.ip === 0) return 0
|
||||
if (stat.ip === 0) return stat.bb > 0 ? NaN : 0
|
||||
|
||||
return stat.bb * 9 / stat.ip
|
||||
}
|
||||
|
||||
function bbPer9FromOuts(stat: { bb: number, outs: number }): number {
|
||||
if (stat.outs === 0) return stat.bb > 0 ? NaN : 0
|
||||
|
||||
return stat.bb * 27 / stat.outs
|
||||
}
|
||||
|
||||
function kPerBB(stat: { so: number, bb: number }): number {
|
||||
if (stat.bb === 0) return 0
|
||||
|
||||
|
||||
@ -38,3 +38,7 @@ export function woba(stat: { bb: number, hbp: number, hit: number, double: numbe
|
||||
|
||||
return numerator / denominator
|
||||
}
|
||||
|
||||
export function outsToInnings(stat: { outs: number }): string {
|
||||
return (stat.outs / 3).toFixed(1)
|
||||
}
|
||||
|
||||
@ -37,9 +37,12 @@
|
||||
<h3>Summary</h3>
|
||||
</div>
|
||||
<!-- Batting Summary -->
|
||||
<PlayerBattingSummaryTable :current-season-batting="currentSeasonBatting"
|
||||
<PlayerBattingSummaryTable v-if="isBatter" :current-season-batting="currentSeasonBatting"
|
||||
:current-post-season-batting="currentPostSeasonBatting"
|
||||
:regular-season-batting-stats="regularSeasonBattingStats" />
|
||||
<PlayerPitchingSummaryTable v-else :current-season-pitching="currentSeasonPitching"
|
||||
:current-post-season-pitching="currentPostSeasonPitching"
|
||||
:regular-season-pitching-stats="regularSeasonPitchingStats" />
|
||||
<div class="col-sm-4">
|
||||
<div class="table-responsive-xl" style="max-width:20rem">
|
||||
<table class="table table-sm table-striped">
|
||||
@ -61,11 +64,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- Last 4 Games -->
|
||||
<LastFourGamesBattingTable :last4-games-batting="last4Games" />
|
||||
<LastFourGamesBattingTable v-if="isBatter" :last4-games-batting="last4GamesBatting" />
|
||||
<LastFourGamesPitchingTable v-else :last4-games-pitching="last4GamesPitching" />
|
||||
</div>
|
||||
|
||||
<!-- Career Batting -->
|
||||
<PlayerCareerBattingTable :regular-season-batting-stats="regularSeasonBattingStats"
|
||||
<PlayerCareerBattingTable v-if="isBatter" :regular-season-batting-stats="regularSeasonBattingStats"
|
||||
:post-season-batting-stats="postSeasonBattingStats" />
|
||||
<PlayerCareerPitchingTable :regular-season-pitching-stats="regularSeasonPitchingStats"
|
||||
:post-season-pitching-stats="postSeasonPitchingStats" />
|
||||
<PlayerCareerBattingTable v-if="!isBatter" :regular-season-batting-stats="regularSeasonBattingStats"
|
||||
:post-season-batting-stats="postSeasonBattingStats" />
|
||||
</div>
|
||||
</div>
|
||||
@ -78,8 +86,12 @@ import { type Player, fetchPlayerByName } from '@/services/playersService'
|
||||
import { fetchBattingStatsBySeasonAndPlayerId, fetchBattingStatsForLastFourGamesBySeasonAndPlayerId, type BattingStat } from '@/services/battingStatsService'
|
||||
import { CURRENT_SEASON, isNotUndefined } from '@/services/utilities'
|
||||
import LastFourGamesBattingTable from '@/components/LastFourGamesBattingTable.vue'
|
||||
import LastFourGamesPitchingTable from '@/components/LastFourGamesPitchingTable.vue'
|
||||
import PlayerCareerBattingTable from '@/components/PlayerCareerBattingTable.vue'
|
||||
import PlayerCareerPitchingTable from '@/components/PlayerCareerPitchingTable.vue'
|
||||
import PlayerBattingSummaryTable from '@/components/PlayerBattingSummaryTable.vue'
|
||||
import PlayerPitchingSummaryTable from '@/components/PlayerPitchingSummaryTable.vue'
|
||||
import { fetchPitchingStatsBySeasonAndPlayerId, fetchPitchingStatsForLastFourGamesBySeasonAndPlayerId, type PitchingStat } from '@/services/pitchingStatsService'
|
||||
|
||||
export default {
|
||||
name: "PlayerView",
|
||||
@ -88,15 +100,23 @@ export default {
|
||||
isAuthenticated: false as Boolean,
|
||||
player: undefined as Player | undefined,
|
||||
last2Decisions: [] as Decision[],
|
||||
// Batting stats
|
||||
regularSeasonBattingStats: [] as BattingStat[],
|
||||
postSeasonBattingStats: [] as BattingStat[],
|
||||
last4Games: [] as BattingStat[]
|
||||
last4GamesBatting: [] as BattingStat[],
|
||||
// Pitching stats
|
||||
regularSeasonPitchingStats: [] as PitchingStat[],
|
||||
postSeasonPitchingStats: [] as PitchingStat[],
|
||||
last4GamesPitching: [] as PitchingStat[],
|
||||
}
|
||||
},
|
||||
components: {
|
||||
PlayerBattingSummaryTable,
|
||||
PlayerCareerBattingTable,
|
||||
LastFourGamesBattingTable
|
||||
LastFourGamesBattingTable,
|
||||
PlayerPitchingSummaryTable,
|
||||
PlayerCareerPitchingTable,
|
||||
LastFourGamesPitchingTable
|
||||
},
|
||||
props: {
|
||||
seasonNumber: { type: Number, required: true },
|
||||
@ -156,6 +176,16 @@ export default {
|
||||
return undefined
|
||||
return this.postSeasonBattingStats.find(stat => stat.player.season === CURRENT_SEASON)
|
||||
},
|
||||
currentSeasonPitching(): PitchingStat | undefined {
|
||||
if (!this.regularSeasonPitchingStats.length)
|
||||
return undefined
|
||||
return this.regularSeasonPitchingStats.find(stat => stat.player.season === CURRENT_SEASON)
|
||||
},
|
||||
currentPostSeasonPitching(): PitchingStat | undefined {
|
||||
if (!this.postSeasonPitchingStats.length)
|
||||
return undefined
|
||||
return this.postSeasonPitchingStats.find(stat => stat.player.season === CURRENT_SEASON)
|
||||
},
|
||||
lastAppearance(): string | undefined {
|
||||
if (!this.last2Decisions?.length)
|
||||
return undefined
|
||||
@ -191,12 +221,16 @@ export default {
|
||||
if (!this.player)
|
||||
return
|
||||
this.last2Decisions = await fetchLast2DecisionsByPlayerId(this.seasonNumber, this.player.id)
|
||||
this.last4Games = await fetchBattingStatsForLastFourGamesBySeasonAndPlayerId(this.seasonNumber, this.player.id)
|
||||
this.last4GamesBatting = await fetchBattingStatsForLastFourGamesBySeasonAndPlayerId(this.seasonNumber, this.player.id)
|
||||
this.last4GamesPitching = await fetchPitchingStatsForLastFourGamesBySeasonAndPlayerId(this.seasonNumber, this.player.id)
|
||||
|
||||
// TODO: this should change, either with an api that can take a player name for every season, a way
|
||||
// to get multiple seasons stats at once, or a players ids across all seasons at once
|
||||
const playerSeasons = await Promise.all(Array.from(Array(CURRENT_SEASON), (element, index) => index + 1).map(seasonNumber => fetchPlayerByName(seasonNumber, this.player!.name)))
|
||||
this.regularSeasonBattingStats = (await Promise.all(playerSeasons.filter(isNotUndefined).map(player => fetchBattingStatsBySeasonAndPlayerId(player!.season, player!.id, true)))).filter(isNotUndefined)
|
||||
this.postSeasonBattingStats = (await Promise.all(playerSeasons.filter(isNotUndefined).map(player => fetchBattingStatsBySeasonAndPlayerId(player!.season, player!.id, false)))).filter(isNotUndefined)
|
||||
this.regularSeasonPitchingStats = (await Promise.all(playerSeasons.filter(isNotUndefined).map(player => fetchPitchingStatsBySeasonAndPlayerId(player!.season, player!.id, true)))).filter(isNotUndefined)
|
||||
this.postSeasonPitchingStats = (await Promise.all(playerSeasons.filter(isNotUndefined).map(player => fetchPitchingStatsBySeasonAndPlayerId(player!.season, player!.id, false)))).filter(isNotUndefined)
|
||||
},
|
||||
async tryFetchPlayerByNameForAnySeason(seasonNumber: number, playerName: string): Promise<Player | undefined> {
|
||||
do {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user