Add post season stat toggle

This commit is contained in:
Peter 2023-10-01 20:43:40 -05:00
parent 057be7ae00
commit 4467dd554a
4 changed files with 135 additions and 79 deletions

View File

@ -67,34 +67,34 @@
</tr> </tr>
</tbody> </tbody>
<tfoot> <tfoot>
<tr v-if="careerBattingStat" id="career-batting-footer"> <tr v-for="(stat, idx) in careerBattingStats">
<th>Career</th> <th>Career{{ idx > 0 ? ' / Playoffs' : '' }}</th>
<th>{{ careerBattingStat.pa }}</th> <th>{{ stat.pa }}</th>
<th>{{ careerBattingStat.ab }}</th> <th>{{ stat.ab }}</th>
<th>{{ careerBattingStat.run }}</th> <th>{{ stat.run }}</th>
<th>{{ careerBattingStat.hit }}</th> <th>{{ stat.hit }}</th>
<th>{{ careerBattingStat.double }}</th> <th>{{ stat.double }}</th>
<th>{{ careerBattingStat.triple }}</th> <th>{{ stat.triple }}</th>
<th>{{ careerBattingStat.hr }}</th> <th>{{ stat.hr }}</th>
<th>{{ careerBattingStat.rbi }}</th> <th>{{ stat.rbi }}</th>
<th>{{ careerBattingStat.sb }}</th> <th>{{ stat.sb }}</th>
<th>{{ careerBattingStat.cs }}</th> <th>{{ stat.cs }}</th>
<th>{{ careerBattingStat.bb }}</th> <th>{{ stat.bb }}</th>
<th>{{ careerBattingStat.so }}</th> <th>{{ stat.so }}</th>
<th>{{ careerBattingStat.avg.toFixed(3) }}</th> <th>{{ stat.avg.toFixed(3) }}</th>
<th>{{ careerBattingStat.obp.toFixed(3) }}</th> <th>{{ stat.obp.toFixed(3) }}</th>
<th>{{ careerBattingStat.slg.toFixed(3) }}</th> <th>{{ stat.slg.toFixed(3) }}</th>
<th>{{ careerBattingStat.ops.toFixed(3) }}</th> <th>{{ stat.ops.toFixed(3) }}</th>
<th>{{ careerBattingStat.woba.toFixed(3) }}</th> <th>{{ stat.woba.toFixed(3) }}</th>
<th>{{ calculateStrikeoutPercent(careerBattingStat) }}</th> <th>{{ calculateStrikeoutPercent(stat) }}</th>
<th>{{ careerBattingStat.bphr }}</th> <th>{{ stat.bphr }}</th>
<th>{{ careerBattingStat.bpfo }}</th> <th>{{ stat.bpfo }}</th>
<th>{{ careerBattingStat.bp1b }}</th> <th>{{ stat.bp1b }}</th>
<th>{{ careerBattingStat.bplo }}</th> <th>{{ stat.bplo }}</th>
<th>{{ careerBattingStat.gidp }}</th> <th>{{ stat.gidp }}</th>
<th>{{ careerBattingStat.hbp }}</th> <th>{{ stat.hbp }}</th>
<th>{{ careerBattingStat.sac }}</th> <th>{{ stat.sac }}</th>
<th>{{ careerBattingStat.ibb }}</th> <th>{{ stat.ibb }}</th>
</tr> </tr>
</tfoot> </tfoot>
</table> </table>
@ -115,19 +115,25 @@ export default {
name: "PlayerCareerBattingTable", name: "PlayerCareerBattingTable",
props: { props: {
regularSeasonBattingStats: { type: Array<BattingStat>, required: true }, regularSeasonBattingStats: { type: Array<BattingStat>, required: true },
postSeasonBattingStats: { type: Array<BattingStat>, required: true } postSeasonBattingStats: { type: Array<BattingStat>, required: true },
showPostSeasonStats: { type: Boolean, required: true }
}, },
computed: { computed: {
hasBattingStats(): boolean { hasBattingStats(): boolean {
return !!(this.regularSeasonBattingStats.length + this.postSeasonBattingStats.length) return !!(this.regularSeasonBattingStats.length + this.postSeasonBattingStats.length)
}, },
careerBattingStat(): BattingStat | undefined { careerBattingStats(): BattingStat[] {
let careerStats = []
if (this.regularSeasonBattingStats.length > 0) { if (this.regularSeasonBattingStats.length > 0) {
// old site behavior just summed regular season stats for the career line total careerStats.push(aggregateBattingStats(this.regularSeasonBattingStats))
return aggregateBattingStats(this.regularSeasonBattingStats)
} }
return undefined if (this.showPostSeasonStats && this.postSeasonBattingStats.length > 0) {
careerStats.push(aggregateBattingStats(this.postSeasonBattingStats))
}
return careerStats
}, },
sortedRegularAndPostSeasonBatting(): BattingStatWithSeason[] { sortedRegularAndPostSeasonBatting(): BattingStatWithSeason[] {
let seasonStats: BattingStatWithSeason[] = [] let seasonStats: BattingStatWithSeason[] = []
@ -141,8 +147,8 @@ export default {
} }
})) }))
} }
// TODO: here would be where you could filter out postseason stats if desired (like Josef requested)
if (this.postSeasonBattingStats?.length) { if (this.showPostSeasonStats && this.postSeasonBattingStats?.length) {
seasonStats = seasonStats.concat(this.postSeasonBattingStats.map(stat => { seasonStats = seasonStats.concat(this.postSeasonBattingStats.map(stat => {
return { return {
...stat, ...stat,

View File

@ -33,7 +33,7 @@
</tr> </tr>
</tbody> </tbody>
<tfoot> <tfoot>
<tr v-for="stat in sortedCareerFieldingStats" id="career-fielding-footer"> <tr v-for="stat in sortedCareerFieldingStats">
<th>Career</th> <th>Career</th>
<th>{{ stat.pos }}</th> <th>{{ stat.pos }}</th>
<th>{{ stat.xCheckCount }}</th> <th>{{ stat.xCheckCount }}</th>
@ -45,6 +45,18 @@
<th>{{ formatCaughtStealingPercent(stat) }}</th> <th>{{ formatCaughtStealingPercent(stat) }}</th>
<th>{{ formatWeightedFieldingPercent(stat) }}</th> <th>{{ formatWeightedFieldingPercent(stat) }}</th>
</tr> </tr>
<tr v-for="stat in sortedPlayoffsCareerFieldingStats">
<th>Career / Playoffs</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> </tfoot>
</table> </table>
</div> </div>
@ -81,7 +93,8 @@ export default {
name: "PlayerCareerFieldingTable", name: "PlayerCareerFieldingTable",
props: { props: {
regularSeasonFieldingStats: { type: Array<FieldingStat>, required: true }, regularSeasonFieldingStats: { type: Array<FieldingStat>, required: true },
postSeasonFieldingStats: { type: Array<FieldingStat>, required: true } postSeasonFieldingStats: { type: Array<FieldingStat>, required: true },
showPostSeasonStats: { type: Boolean, required: true }
}, },
computed: { computed: {
hasFieldingStats(): boolean { hasFieldingStats(): boolean {
@ -96,6 +109,14 @@ export default {
return [] return []
}, },
sortedPlayoffsCareerFieldingStats(): FieldingStat[] {
if (this.showPostSeasonStats && this.postSeasonFieldingStats.length > 0) {
return aggregateFieldingStats(this.postSeasonFieldingStats)
.sort((a, b) => POS_MAP[a.pos] - POS_MAP[b.pos]) //only need to sort careers totals by position
}
return []
},
sortedRegularAndPostSeasonFielding(): FieldingStatWithSeason[] { sortedRegularAndPostSeasonFielding(): FieldingStatWithSeason[] {
let seasonStats: FieldingStatWithSeason[] = [] let seasonStats: FieldingStatWithSeason[] = []
@ -108,8 +129,8 @@ export default {
} }
})) }))
} }
// TODO: here would be where you could filter out postseason stats if desired (like Josef requested)
if (this.postSeasonFieldingStats?.length) { if (this.showPostSeasonStats && this.postSeasonFieldingStats?.length) {
seasonStats = seasonStats.concat(this.postSeasonFieldingStats.map(stat => { seasonStats = seasonStats.concat(this.postSeasonFieldingStats.map(stat => {
return { return {
...stat, ...stat,
@ -118,7 +139,7 @@ export default {
} }
})) }))
} }
// TODO: additionally, fielding stats should sort on position P, C, 1B, ..., CF, RF
return seasonStats.sort(compareFieldingStats) return seasonStats.sort(compareFieldingStats)
}, },
}, },

View File

@ -69,35 +69,35 @@
</tr> </tr>
</tbody> </tbody>
<tfoot> <tfoot>
<tr v-if="careerPitchingStat" id="career-pitching-footer"> <tr v-for="(stat, idx) in careerPitchingStats">
<th>Career</th> <th>Career{{ idx > 0 ? ' / Playoffs' : '' }}</th>
<th>{{ careerPitchingStat.win }}</th> <th>{{ stat.win }}</th>
<th>{{ careerPitchingStat.loss }}</th> <th>{{ stat.loss }}</th>
<th>{{ winPercentage(careerPitchingStat) }}</th> <th>{{ winPercentage(stat) }}</th>
<th>{{ careerPitchingStat.era.toFixed(2) }}</th> <th>{{ stat.era.toFixed(2) }}</th>
<th>{{ careerPitchingStat.games }}</th> <th>{{ stat.games }}</th>
<th>{{ careerPitchingStat.gs }}</th> <th>{{ stat.gs }}</th>
<th>{{ careerPitchingStat.save }}</th> <th>{{ stat.save }}</th>
<th>{{ careerPitchingStat.hold }}</th> <th>{{ stat.hold }}</th>
<th>{{ careerPitchingStat.bsave }}</th> <th>{{ stat.bsave }}</th>
<th>{{ outsToInnings(careerPitchingStat) }}</th> <th>{{ outsToInnings(stat) }}</th>
<th>{{ careerPitchingStat.hits }}</th> <th>{{ stat.hits }}</th>
<th>{{ careerPitchingStat.run }}</th> <th>{{ stat.run }}</th>
<th>{{ careerPitchingStat.e_run }}</th> <th>{{ stat.e_run }}</th>
<th>{{ careerPitchingStat.hr }}</th> <th>{{ stat.hr }}</th>
<th>{{ careerPitchingStat.bb }}</th> <th>{{ stat.bb }}</th>
<th>{{ careerPitchingStat.so }}</th> <th>{{ stat.so }}</th>
<th>{{ careerPitchingStat.hbp }}</th> <th>{{ stat.hbp }}</th>
<th>{{ careerPitchingStat.balk }}</th> <th>{{ stat.balk }}</th>
<th>{{ careerPitchingStat.wp }}</th> <th>{{ stat.wp }}</th>
<th>{{ careerPitchingStat.ir }}</th> <th>{{ stat.ir }}</th>
<th>{{ careerPitchingStat.ir_sc }}</th> <th>{{ stat.ir_sc }}</th>
<th>{{ careerPitchingStat.whip.toFixed(2) }}</th> <th>{{ stat.whip.toFixed(2) }}</th>
<th>{{ hitsPer9(careerPitchingStat) }}</th> <th>{{ hitsPer9(stat) }}</th>
<th>{{ hrsPer9(careerPitchingStat) }}</th> <th>{{ hrsPer9(stat) }}</th>
<th>{{ careerPitchingStat.bbPer9.toFixed(1) }}</th> <th>{{ stat.bbPer9.toFixed(1) }}</th>
<th>{{ careerPitchingStat.kPer9.toFixed(1) }}</th> <th>{{ stat.kPer9.toFixed(1) }}</th>
<th>{{ careerPitchingStat.kPerBB.toFixed(1) }}</th> <th>{{ stat.kPerBB.toFixed(1) }}</th>
</tr> </tr>
</tfoot> </tfoot>
</table> </table>
@ -119,12 +119,26 @@ export default {
name: "PlayerCareerPitchingTable", name: "PlayerCareerPitchingTable",
props: { props: {
regularSeasonPitchingStats: { type: Array<PitchingStat>, required: true }, regularSeasonPitchingStats: { type: Array<PitchingStat>, required: true },
postSeasonPitchingStats: { type: Array<PitchingStat>, required: true } postSeasonPitchingStats: { type: Array<PitchingStat>, required: true },
showPostSeasonStats: { type: Boolean, required: true }
}, },
computed: { computed: {
hasPitchingStats(): boolean { hasPitchingStats(): boolean {
return !!(this.regularSeasonPitchingStats.length + this.postSeasonPitchingStats.length) return !!(this.regularSeasonPitchingStats.length + this.postSeasonPitchingStats.length)
}, },
careerPitchingStats(): PitchingStat[] {
let careerStats = []
if (this.regularSeasonPitchingStats.length > 0) {
careerStats.push(aggregatePitchingStats(this.regularSeasonPitchingStats))
}
if (this.showPostSeasonStats && this.postSeasonPitchingStats.length > 0) {
careerStats.push(aggregatePitchingStats(this.postSeasonPitchingStats))
}
return careerStats
},
careerPitchingStat(): PitchingStat | undefined { careerPitchingStat(): PitchingStat | undefined {
if (this.regularSeasonPitchingStats.length > 0) { if (this.regularSeasonPitchingStats.length > 0) {
// old site behavior just summed regular season stats for the career line total // old site behavior just summed regular season stats for the career line total
@ -145,8 +159,8 @@ export default {
} }
})) }))
} }
// TODO: here would be where you could filter out postseason stats if desired (like Josef requested)
if (this.postSeasonPitchingStats?.length) { if (this.showPostSeasonStats && this.postSeasonPitchingStats?.length) {
seasonStats = seasonStats.concat(this.postSeasonPitchingStats.map(stat => { seasonStats = seasonStats.concat(this.postSeasonPitchingStats.map(stat => {
return { return {
...stat, ...stat,

View File

@ -69,15 +69,20 @@
<LastFourGamesPitchingTable v-else :last4-games-pitching="last4GamesPitching" /> <LastFourGamesPitchingTable v-else :last4-games-pitching="last4GamesPitching" />
</div> </div>
<button v-if="hasPostSeasonStats" @click.stop="setPostSeasonVisiblity(!showPostSeasonStats)"
class="btn btn-sm btn-primary mb-2">
{{ showPostSeasonStats ? 'Hide' : 'Show' }} Postseason Stats
</button>
<!-- Career Stats --> <!-- Career Stats -->
<PlayerCareerBattingTable v-if="isBatter" :regular-season-batting-stats="regularSeasonBattingStats" <PlayerCareerBattingTable v-if="isBatter" :regular-season-batting-stats="regularSeasonBattingStats"
:post-season-batting-stats="postSeasonBattingStats" /> :post-season-batting-stats="postSeasonBattingStats" :show-post-season-stats="showPostSeasonStats" />
<PlayerCareerPitchingTable :regular-season-pitching-stats="regularSeasonPitchingStats" <PlayerCareerPitchingTable :regular-season-pitching-stats="regularSeasonPitchingStats"
:post-season-pitching-stats="postSeasonPitchingStats" /> :post-season-pitching-stats="postSeasonPitchingStats" :show-post-season-stats="showPostSeasonStats" />
<PlayerCareerBattingTable v-if="!isBatter" :regular-season-batting-stats="regularSeasonBattingStats" <PlayerCareerBattingTable v-if="!isBatter" :regular-season-batting-stats="regularSeasonBattingStats"
:post-season-batting-stats="postSeasonBattingStats" /> :post-season-batting-stats="postSeasonBattingStats" :show-post-season-stats="showPostSeasonStats" />
<PlayerCareerFieldingTable :regular-season-fielding-stats="regularSeasonFieldingStats" <PlayerCareerFieldingTable :regular-season-fielding-stats="regularSeasonFieldingStats"
:post-season-fielding-stats="postSeasonFieldingStats" /> :post-season-fielding-stats="postSeasonFieldingStats" :show-post-season-stats="showPostSeasonStats" />
<!-- Transactions and awards --> <!-- Transactions and awards -->
<div v-if="transactions.length || awards.length" class="row" id="transactions-row"> <div v-if="transactions.length || awards.length" class="row" id="transactions-row">
@ -162,7 +167,7 @@ export default {
name: "PlayerView", name: "PlayerView",
data() { data() {
return { return {
isAuthenticated: false as Boolean, isAuthenticated: false,
player: undefined as Player | undefined, player: undefined as Player | undefined,
last2Decisions: [] as Decision[], last2Decisions: [] as Decision[],
// Batting stats // Batting stats
@ -180,7 +185,10 @@ export default {
// Transactions and Awards // Transactions and Awards
transactions: [] as Transaction[], transactions: [] as Transaction[],
awards: [] as Award[] awards: [] as Award[],
// Additional inputs
showPostSeasonStats: false
} }
}, },
components: { components: {
@ -203,7 +211,6 @@ export default {
isCurrentPlayer(): boolean { isCurrentPlayer(): boolean {
return this.seasonNumber === this.playerSeasonNumber return this.seasonNumber === this.playerSeasonNumber
}, },
// TODO use to determine order of stats to display
isBatter(): boolean { isBatter(): boolean {
return !this.player?.pos_1.includes('P') return !this.player?.pos_1.includes('P')
}, },
@ -260,6 +267,11 @@ export default {
return undefined return undefined
return this.postSeasonPitchingStats.find(stat => stat.player.season === CURRENT_SEASON) return this.postSeasonPitchingStats.find(stat => stat.player.season === CURRENT_SEASON)
}, },
hasPostSeasonStats(): boolean {
return this.postSeasonBattingStats.length > 0
|| this.postSeasonPitchingStats.length > 0
|| this.postSeasonFieldingStats.length > 0
},
lastAppearance(): string | undefined { lastAppearance(): string | undefined {
if (!this.last2Decisions?.length) if (!this.last2Decisions?.length)
return undefined return undefined
@ -322,6 +334,9 @@ export default {
}, },
formatDecisionToAppearance(decision: Decision): string { formatDecisionToAppearance(decision: Decision): string {
return `${decision.rest_ip.toFixed(1)}IP w${decision.week}g${decision.game_num}` return `${decision.rest_ip.toFixed(1)}IP w${decision.week}g${decision.game_num}`
},
setPostSeasonVisiblity(shouldBeVisible: boolean): void {
this.showPostSeasonStats = shouldBeVisible
} }
} }
} }