Add fielding stats to Team page
This commit is contained in:
parent
672ef8ece1
commit
66058ff359
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -26,6 +26,8 @@ declare module '@vue/runtime-core' {
|
|||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
StandingsTable: typeof import('./src/components/StandingsTable.vue')['default']
|
StandingsTable: typeof import('./src/components/StandingsTable.vue')['default']
|
||||||
|
TeamBattingTable: typeof import('./src/components/TeamBattingTable.vue')['default']
|
||||||
|
TeamFieldingTable: typeof import('./src/components/TeamFieldingTable.vue')['default']
|
||||||
TeamPitchingTable: typeof import('./src/components/TeamPitchingTable.vue')['default']
|
TeamPitchingTable: typeof import('./src/components/TeamPitchingTable.vue')['default']
|
||||||
TeamScheduleTable: typeof import('./src/components/TeamScheduleTable.vue')['default']
|
TeamScheduleTable: typeof import('./src/components/TeamScheduleTable.vue')['default']
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,25 +54,13 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { aggregateFieldingStats, type FieldingStat } from '@/services/fieldingStatsService'
|
import { aggregateFieldingStats, type FieldingStat } from '@/services/fieldingStatsService'
|
||||||
|
import { POS_MAP } from '@/services/utilities'
|
||||||
|
|
||||||
interface FieldingStatWithSeason extends FieldingStat {
|
interface FieldingStatWithSeason extends FieldingStat {
|
||||||
seasonNumber: number
|
seasonNumber: number
|
||||||
isRegularSeason: boolean
|
isRegularSeason: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const POS_MAP = {
|
|
||||||
'P': 1,
|
|
||||||
'C': 2,
|
|
||||||
'1B': 3,
|
|
||||||
'2B': 4,
|
|
||||||
'3B': 5,
|
|
||||||
'SS': 6,
|
|
||||||
'LF': 7,
|
|
||||||
'CF': 8,
|
|
||||||
'RF': 9,
|
|
||||||
'TOT': 10
|
|
||||||
}
|
|
||||||
|
|
||||||
function compareFieldingStats(s1: FieldingStatWithSeason, s2: FieldingStatWithSeason): number {
|
function compareFieldingStats(s1: FieldingStatWithSeason, s2: FieldingStatWithSeason): number {
|
||||||
if (s1.seasonNumber - s2.seasonNumber !== 0) {
|
if (s1.seasonNumber - s2.seasonNumber !== 0) {
|
||||||
return s1.seasonNumber - s2.seasonNumber
|
return s1.seasonNumber - s2.seasonNumber
|
||||||
|
|||||||
149
src/components/TeamBattingTable.vue
Normal file
149
src/components/TeamBattingTable.vue
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="battingStats.length" class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h3>Team Batting {{ isRegularSeason ? '' : ' - Postseason' }}</h3>
|
||||||
|
<div class="table-responsive-xl">
|
||||||
|
<table class="table table-sm table-striped" id="table-batting-stats">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr style="min-width: 75px">
|
||||||
|
<th>Player</th>
|
||||||
|
<th>PA</th>
|
||||||
|
<th>AB</th>
|
||||||
|
<th>R</th>
|
||||||
|
<th>H</th>
|
||||||
|
<th>2B</th>
|
||||||
|
<th>3B</th>
|
||||||
|
<th>HR</th>
|
||||||
|
<th>RBI</th>
|
||||||
|
<th>SB</th>
|
||||||
|
<th>CS</th>
|
||||||
|
<th>BB</th>
|
||||||
|
<th>SO</th>
|
||||||
|
<th>BA</th>
|
||||||
|
<th>OBP</th>
|
||||||
|
<th>SLG</th>
|
||||||
|
<th>OPS</th>
|
||||||
|
<th>wOBA</th>
|
||||||
|
<th>K%</th>
|
||||||
|
<th>BPHR</th>
|
||||||
|
<th>BPFO</th>
|
||||||
|
<th>BP1B</th>
|
||||||
|
<th>BPLO</th>
|
||||||
|
<th>GIDP</th>
|
||||||
|
<th>HBP</th>
|
||||||
|
<th>SAC</th>
|
||||||
|
<th>IBB</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="career-batting-table">
|
||||||
|
<tr v-for="stat in battingStats">
|
||||||
|
<td>
|
||||||
|
<RouterLink
|
||||||
|
:to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: stat.player.name } }">
|
||||||
|
{{ stat.player.name }}
|
||||||
|
</RouterLink>
|
||||||
|
</td>
|
||||||
|
<td>{{ stat.pa }}</td>
|
||||||
|
<td>{{ stat.ab }}</td>
|
||||||
|
<td>{{ stat.run }}</td>
|
||||||
|
<td>{{ stat.hit }}</td>
|
||||||
|
<td>{{ stat.double }}</td>
|
||||||
|
<td>{{ stat.triple }}</td>
|
||||||
|
<td>{{ stat.hr }}</td>
|
||||||
|
<td>{{ stat.rbi }}</td>
|
||||||
|
<td>{{ stat.sb }}</td>
|
||||||
|
<td>{{ stat.cs }}</td>
|
||||||
|
<td>{{ stat.bb }}</td>
|
||||||
|
<td>{{ stat.so }}</td>
|
||||||
|
<td>{{ stat.avg.toFixed(3) }}</td>
|
||||||
|
<td>{{ stat.obp.toFixed(3) }}</td>
|
||||||
|
<td>{{ stat.slg.toFixed(3) }}</td>
|
||||||
|
<td>{{ stat.ops.toFixed(3) }}</td>
|
||||||
|
<td>{{ stat.woba.toFixed(3) }}</td>
|
||||||
|
<td>{{ calculateStrikeoutPercent(stat) }}</td>
|
||||||
|
<td>{{ stat.bphr }}</td>
|
||||||
|
<td>{{ stat.bpfo }}</td>
|
||||||
|
<td>{{ stat.bp1b }}</td>
|
||||||
|
<td>{{ stat.bplo }}</td>
|
||||||
|
<td>{{ stat.gidp }}</td>
|
||||||
|
<td>{{ stat.hbp }}</td>
|
||||||
|
<td>{{ stat.sac }}</td>
|
||||||
|
<td>{{ stat.ibb }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr v-if="totalBattingStat">
|
||||||
|
<th>Total</th>
|
||||||
|
<th>{{ totalBattingStat.pa }}</th>
|
||||||
|
<th>{{ totalBattingStat.ab }}</th>
|
||||||
|
<th>{{ totalBattingStat.run }}</th>
|
||||||
|
<th>{{ totalBattingStat.hit }}</th>
|
||||||
|
<th>{{ totalBattingStat.double }}</th>
|
||||||
|
<th>{{ totalBattingStat.triple }}</th>
|
||||||
|
<th>{{ totalBattingStat.hr }}</th>
|
||||||
|
<th>{{ totalBattingStat.rbi }}</th>
|
||||||
|
<th>{{ totalBattingStat.sb }}</th>
|
||||||
|
<th>{{ totalBattingStat.cs }}</th>
|
||||||
|
<th>{{ totalBattingStat.bb }}</th>
|
||||||
|
<th>{{ totalBattingStat.so }}</th>
|
||||||
|
<th>{{ totalBattingStat.avg.toFixed(3) }}</th>
|
||||||
|
<th>{{ totalBattingStat.obp.toFixed(3) }}</th>
|
||||||
|
<th>{{ totalBattingStat.slg.toFixed(3) }}</th>
|
||||||
|
<th>{{ totalBattingStat.ops.toFixed(3) }}</th>
|
||||||
|
<th>{{ totalBattingStat.woba.toFixed(3) }}</th>
|
||||||
|
<th>{{ calculateStrikeoutPercent(totalBattingStat) }}</th>
|
||||||
|
<th>{{ totalBattingStat.bphr }}</th>
|
||||||
|
<th>{{ totalBattingStat.bpfo }}</th>
|
||||||
|
<th>{{ totalBattingStat.bp1b }}</th>
|
||||||
|
<th>{{ totalBattingStat.bplo }}</th>
|
||||||
|
<th>{{ totalBattingStat.gidp }}</th>
|
||||||
|
<th>{{ totalBattingStat.hbp }}</th>
|
||||||
|
<th>{{ totalBattingStat.sac }}</th>
|
||||||
|
<th>{{ totalBattingStat.ibb }}</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { aggregateBattingStats, fetchBattingStatsBySeasonAndTeamId, type BattingStat } from '@/services/battingStatsService'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "TeamBattingTable",
|
||||||
|
props: {
|
||||||
|
seasonNumber: { type: Number, required: true },
|
||||||
|
teamId: { type: Number, required: true },
|
||||||
|
isRegularSeason: { type: Boolean, required: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
battingStats: [] as BattingStat[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
totalBattingStat(): BattingStat | undefined {
|
||||||
|
if (this.battingStats.length > 0) {
|
||||||
|
return aggregateBattingStats(this.battingStats)
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchData(): Promise<void> {
|
||||||
|
const unsortedBattingStats: BattingStat[] = await fetchBattingStatsBySeasonAndTeamId(this.seasonNumber, this.teamId, this.isRegularSeason)
|
||||||
|
this.battingStats = unsortedBattingStats.sort((s1, s2) => s2.pa - s1.pa)
|
||||||
|
},
|
||||||
|
calculateStrikeoutPercent(stat: BattingStat): string {
|
||||||
|
if (!stat.pa) return 'N/A'
|
||||||
|
return (stat.so * 100 / stat.pa).toFixed(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
108
src/components/TeamFieldingTable.vue
Normal file
108
src/components/TeamFieldingTable.vue
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="fieldingStats.length" class="col-sm-6">
|
||||||
|
<h3>Team Fielding {{ isRegularSeason ? '' : ' - Postseason' }}</h3>
|
||||||
|
<div class="table-responsive-xl" style="max-width:40rem">
|
||||||
|
<table class="table table-sm table-striped" id="table-fielding-stats">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Season</th>
|
||||||
|
<th>Pos</th>
|
||||||
|
<th>XCh</th>
|
||||||
|
<th>XH</th>
|
||||||
|
<th>E</th>
|
||||||
|
<th>PB</th>
|
||||||
|
<th>SBa</th>
|
||||||
|
<th>CSc</th>
|
||||||
|
<th>CS%</th>
|
||||||
|
<th>wF%</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="career-fielding-table">
|
||||||
|
<tr v-for="stat in fieldingStats">
|
||||||
|
<td>
|
||||||
|
<RouterLink :to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: stat.player.name } }">
|
||||||
|
{{ stat.player.name }}
|
||||||
|
</RouterLink>
|
||||||
|
</td>
|
||||||
|
<td>{{ stat.pos }}</td>
|
||||||
|
<td>{{ stat.xCheckCount }}</td>
|
||||||
|
<td>{{ stat.hit }}</td>
|
||||||
|
<td>{{ stat.error }}</td>
|
||||||
|
<td>{{ stat.passedBallCount }}</td>
|
||||||
|
<td>{{ stat.stolenBaseCheckCount }}</td>
|
||||||
|
<td>{{ stat.caughtStealingCount }}</td>
|
||||||
|
<td>{{ formatCaughtStealingPercent(stat) }}</td>
|
||||||
|
<td>{{ formatWeightedFieldingPercent(stat) }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr v-for="stat in totalFieldingStat" id="career-fielding-footer">
|
||||||
|
<th>Total</th>
|
||||||
|
<th>{{ stat.pos }}</th>
|
||||||
|
<th>{{ stat.xCheckCount }}</th>
|
||||||
|
<th>{{ stat.hit }}</th>
|
||||||
|
<th>{{ stat.error }}</th>
|
||||||
|
<th>{{ stat.passedBallCount }}</th>
|
||||||
|
<th>{{ stat.stolenBaseCheckCount }}</th>
|
||||||
|
<th>{{ stat.caughtStealingCount }}</th>
|
||||||
|
<th>{{ formatCaughtStealingPercent(stat) }}</th>
|
||||||
|
<th>{{ formatWeightedFieldingPercent(stat) }}</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { aggregateFieldingStats, fetchFieldingStatsBySeasonAndTeamId, totaledFieldingStats, type FieldingStat } from '@/services/fieldingStatsService'
|
||||||
|
import { POS_MAP } from '@/services/utilities'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "TeamFieldingTable",
|
||||||
|
props: {
|
||||||
|
seasonNumber: { type: Number, required: true },
|
||||||
|
teamId: { type: Number, required: true },
|
||||||
|
isRegularSeason: { type: Boolean, required: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fieldingStats: [] as FieldingStat[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
totalFieldingStat(): FieldingStat[] {
|
||||||
|
if (this.fieldingStats.length > 0) {
|
||||||
|
const totaledStats = aggregateFieldingStats(this.fieldingStats).sort((s1, s2) => POS_MAP[s1.pos] - POS_MAP[s2.pos])
|
||||||
|
|
||||||
|
const allPositionsTotalStat = totaledFieldingStats(this.fieldingStats)
|
||||||
|
if (allPositionsTotalStat !== undefined) {
|
||||||
|
totaledStats.push(allPositionsTotalStat)
|
||||||
|
}
|
||||||
|
|
||||||
|
return totaledStats
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchData(): Promise<void> {
|
||||||
|
const unsortedFieldingStats: FieldingStat[] = await fetchFieldingStatsBySeasonAndTeamId(this.seasonNumber, this.teamId, this.isRegularSeason)
|
||||||
|
this.fieldingStats = unsortedFieldingStats.sort((s1, s2) => POS_MAP[s1.pos] - POS_MAP[s2.pos])
|
||||||
|
},
|
||||||
|
formatCaughtStealingPercent(stat: FieldingStat): string {
|
||||||
|
if (stat.stolenBaseCheckCount === 0 || Number.isNaN(stat.caughtStealingPercent)) {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${(stat.caughtStealingPercent * 100).toFixed(1)}%`
|
||||||
|
},
|
||||||
|
formatWeightedFieldingPercent(stat: FieldingStat): string {
|
||||||
|
return stat.weightedFieldingPercent.toFixed(3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -86,6 +86,24 @@ export async function fetchBattingStatsBySeasonAndPlayerId(seasonNumber: number,
|
|||||||
return battingStatsResponse.stats[0]
|
return battingStatsResponse.stats[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchBattingStatsBySeasonAndTeamId(seasonNumber: number, teamId: number, isRegularSeason: boolean): Promise<BattingStat[]> {
|
||||||
|
// different endpoint for pre-modern stats (/plays) era
|
||||||
|
if (seasonNumber < MODERN_STAT_ERA_START) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/plays/batting?season=${seasonNumber}&team_id=${teamId}&group_by=playerteam&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
||||||
|
|
||||||
|
const battingStatsResponse: {
|
||||||
|
count: number
|
||||||
|
stats: BattingStat[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
if (battingStatsResponse.count === 0) return []
|
||||||
|
|
||||||
|
return battingStatsResponse.stats
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchLegacyBattingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<BattingStat | undefined> {
|
async function fetchLegacyBattingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<BattingStat | undefined> {
|
||||||
const response = await fetch(`${SITE_URL}/api/v3/battingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
const response = await fetch(`${SITE_URL}/api/v3/battingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
||||||
|
|
||||||
|
|||||||
@ -70,6 +70,25 @@ export async function fetchFieldingStatsBySeasonAndPlayerId(seasonNumber: number
|
|||||||
return fieldingStatsResponse.stats.map(normalizeFieldingStat)
|
return fieldingStatsResponse.stats.map(normalizeFieldingStat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchFieldingStatsBySeasonAndTeamId(seasonNumber: number, teamId: 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}&team_id=${teamId}&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[]> {
|
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'}`)
|
const response = await fetch(`${SITE_URL}/api/v3/fieldingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
||||||
|
|
||||||
@ -144,6 +163,49 @@ export function aggregateFieldingStats(fieldingStats: FieldingStat[]): FieldingS
|
|||||||
return Object.values(fieldingStatsByPosition)
|
return Object.values(fieldingStatsByPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function totaledFieldingStats(fieldingStats: FieldingStat[]): FieldingStat | undefined {
|
||||||
|
if (fieldingStats.length === 0) return undefined
|
||||||
|
|
||||||
|
let totalStat: FieldingStat = {
|
||||||
|
game: 'TOT',
|
||||||
|
player: fieldingStats[0].player,
|
||||||
|
team: fieldingStats[0].team,
|
||||||
|
pos: 'TOT',
|
||||||
|
xCheckCount: 0,
|
||||||
|
hit: 0,
|
||||||
|
error: 0,
|
||||||
|
stolenBaseCheckCount: 0,
|
||||||
|
stolenBaseCount: 0,
|
||||||
|
caughtStealingCount: 0,
|
||||||
|
passedBallCount: 0,
|
||||||
|
winProbabilityAdded: 0,
|
||||||
|
weightedFieldingPercent: 0,
|
||||||
|
caughtStealingPercent: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldingStats.forEach(stat => {
|
||||||
|
totalStat.xCheckCount += stat.xCheckCount
|
||||||
|
totalStat.hit += stat.hit
|
||||||
|
totalStat.error += stat.error
|
||||||
|
totalStat.stolenBaseCheckCount += stat.stolenBaseCheckCount
|
||||||
|
totalStat.stolenBaseCount += stat.stolenBaseCount
|
||||||
|
totalStat.caughtStealingCount += stat.caughtStealingCount
|
||||||
|
totalStat.passedBallCount += stat.passedBallCount
|
||||||
|
totalStat.winProbabilityAdded += stat.winProbabilityAdded
|
||||||
|
totalStat.weightedFieldingPercent = weightedFieldingPercentage({
|
||||||
|
xChecks: totalStat.xCheckCount,
|
||||||
|
hits: totalStat.hit,
|
||||||
|
errors: totalStat.error
|
||||||
|
})
|
||||||
|
totalStat.caughtStealingPercent = caughtStealingPercentage({
|
||||||
|
stolenBaseAttempts: totalStat.stolenBaseCheckCount,
|
||||||
|
caughtStealingCount: totalStat.caughtStealingCount
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return totalStat
|
||||||
|
}
|
||||||
|
|
||||||
function makeModernFieldingStatFromLegacy(legacyStat: LegacyFieldingStat): FieldingStat | undefined {
|
function makeModernFieldingStatFromLegacy(legacyStat: LegacyFieldingStat): FieldingStat | undefined {
|
||||||
// filter out "PH" fielding stats here which used to occur when position/xchecks were loosely checked/observed
|
// filter out "PH" fielding stats here which used to occur when position/xchecks were loosely checked/observed
|
||||||
if (legacyStat.pos === 'PH') return undefined
|
if (legacyStat.pos === 'PH') return undefined
|
||||||
|
|||||||
@ -153,6 +153,11 @@ export async function fetchPitchingStatsBySeasonAndPlayerId(seasonNumber: number
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchPitchingStatsBySeasonAndTeamId(seasonNumber: number, teamId: number, isRegularSeason: boolean): Promise<PitchingStat[]> {
|
export async function fetchPitchingStatsBySeasonAndTeamId(seasonNumber: number, teamId: number, isRegularSeason: boolean): Promise<PitchingStat[]> {
|
||||||
|
// different endpoint for pre-modern stats (/plays) era
|
||||||
|
if (seasonNumber < MODERN_STAT_ERA_START) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&team_id=${teamId}&group_by=playerteam&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&team_id=${teamId}&group_by=playerteam&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
||||||
|
|
||||||
const pitchingStatsResponse: {
|
const pitchingStatsResponse: {
|
||||||
|
|||||||
@ -6,6 +6,19 @@ export const MODERN_STAT_ERA_START = 8
|
|||||||
|
|
||||||
export const GAMES_PER_SEASON = 72
|
export const GAMES_PER_SEASON = 72
|
||||||
|
|
||||||
|
export const POS_MAP = {
|
||||||
|
'P': 1,
|
||||||
|
'C': 2,
|
||||||
|
'1B': 3,
|
||||||
|
'2B': 4,
|
||||||
|
'3B': 5,
|
||||||
|
'SS': 6,
|
||||||
|
'LF': 7,
|
||||||
|
'CF': 8,
|
||||||
|
'RF': 9,
|
||||||
|
'TOT': 10
|
||||||
|
}
|
||||||
|
|
||||||
// a type guard to tell typescript that undefined has been filtered and to only consider an array
|
// a type guard to tell typescript that undefined has been filtered and to only consider an array
|
||||||
// of the expected types (no undefineds) after filtering
|
// of the expected types (no undefineds) after filtering
|
||||||
export const isNotUndefined = <S>(value: S | undefined): value is S => value != undefined
|
export const isNotUndefined = <S>(value: S | undefined): value is S => value != undefined
|
||||||
|
|||||||
@ -163,6 +163,20 @@
|
|||||||
:team-id="team.id" />
|
:team-id="team.id" />
|
||||||
<TeamPitchingTable v-if="!isFreeAgentTeam && team" :is-regular-season="false" :season-number="seasonNumber"
|
<TeamPitchingTable v-if="!isFreeAgentTeam && team" :is-regular-season="false" :season-number="seasonNumber"
|
||||||
:team-id="team.id" />
|
:team-id="team.id" />
|
||||||
|
|
||||||
|
<!-- Team Batting -->
|
||||||
|
<TeamBattingTable v-if="!isFreeAgentTeam && team" :is-regular-season="true" :season-number="seasonNumber"
|
||||||
|
:team-id="team.id" />
|
||||||
|
<TeamBattingTable v-if="!isFreeAgentTeam && team" :is-regular-season="false" :season-number="seasonNumber"
|
||||||
|
:team-id="team.id" />
|
||||||
|
|
||||||
|
<!-- Team Fielding -->
|
||||||
|
<div class="row">
|
||||||
|
<TeamFieldingTable v-if="!isFreeAgentTeam && team" :is-regular-season="true" :season-number="seasonNumber"
|
||||||
|
:team-id="team.id" />
|
||||||
|
<TeamFieldingTable v-if="!isFreeAgentTeam && team" :is-regular-season="false" :season-number="seasonNumber"
|
||||||
|
:team-id="team.id" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -175,12 +189,16 @@ import { fetchTeam } from '@/services/teamsService'
|
|||||||
import { fetchTransactionsByTeamAndWeek, type Transaction } from '@/services/transactionsService'
|
import { fetchTransactionsByTeamAndWeek, type Transaction } from '@/services/transactionsService'
|
||||||
import TeamScheduleTable from '@/components/TeamScheduleTable.vue'
|
import TeamScheduleTable from '@/components/TeamScheduleTable.vue'
|
||||||
import TeamPitchingTable from '@/components/TeamPitchingTable.vue'
|
import TeamPitchingTable from '@/components/TeamPitchingTable.vue'
|
||||||
|
import TeamBattingTable from '@/components/TeamBattingTable.vue'
|
||||||
|
import TeamFieldingTable from '@/components/TeamFieldingTable.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TeamView",
|
name: "TeamView",
|
||||||
components: {
|
components: {
|
||||||
TeamScheduleTable,
|
TeamScheduleTable,
|
||||||
TeamPitchingTable
|
TeamPitchingTable,
|
||||||
|
TeamBattingTable,
|
||||||
|
TeamFieldingTable
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user