player stats updated badges
This commit is contained in:
@@ -182,6 +182,8 @@
|
||||
"average_score": "Average Score",
|
||||
"highest_score": "Highest Score",
|
||||
"worst_score": "Worst Score",
|
||||
"hit_rate": "Hit Rate",
|
||||
"most_common": "Most Common",
|
||||
"completed": "Completed",
|
||||
"position": "Position",
|
||||
"points": "Points",
|
||||
|
||||
@@ -188,6 +188,8 @@
|
||||
"average_score": "Povprečni Rezultat",
|
||||
"highest_score": "Najvišji Rezultat",
|
||||
"worst_score": "Najslabši Rezultat",
|
||||
"hit_rate": "Stopnja Uspešnosti",
|
||||
"most_common": "Najpogostejši",
|
||||
"completed": "Zaključeno",
|
||||
"position": "Uvrstitev",
|
||||
"points": "Točke",
|
||||
|
||||
@@ -73,6 +73,45 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Tournament Badge Styling */
|
||||
.stat-badge.tournament-badge {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tournament-scores {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 8px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tournament-score-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.tournament-type {
|
||||
font-size: 0.65rem;
|
||||
color: #999;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.tournament-emoji {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.tournament-best {
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
/* Charts Section */
|
||||
.charts-section {
|
||||
min-height: 450px;
|
||||
@@ -625,6 +664,49 @@
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
/* Shot Count Cards */
|
||||
.shot-count-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 25px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.shot-count-card {
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 10px;
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 90px;
|
||||
}
|
||||
|
||||
.shot-count-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(40, 167, 69, 0.15);
|
||||
transform: translateY(-2px);
|
||||
border-color: #28a745;
|
||||
}
|
||||
|
||||
.shot-score {
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
color: #28a745;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.shot-count {
|
||||
font-size: 1.8rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.history-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
@@ -968,6 +1050,90 @@
|
||||
min-height: 300px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* Responsive Shot Count Cards */
|
||||
.shot-count-cards {
|
||||
grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
|
||||
gap: 8px;
|
||||
margin-top: 20px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.shot-count-card {
|
||||
min-height: 80px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.shot-score {
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.shot-count {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
/* Responsive Overall Accuracy Dashboard */
|
||||
.overall-top-section {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.gauge-section {
|
||||
flex: 0 0 100%;
|
||||
min-height: 250px;
|
||||
}
|
||||
|
||||
.stat-card-group {
|
||||
flex: 0 0 100%;
|
||||
grid-template-columns: 2fr 2fr;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.overall-bottom-section {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 15px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.overall-bar-chart,
|
||||
.overall-radar-chart {
|
||||
min-height: 280px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.stat-card-icon {
|
||||
font-size: 1.4rem;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.stat-card-value {
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.stat-card-label {
|
||||
font-size: 0.65rem;
|
||||
}
|
||||
|
||||
.gauge-stats {
|
||||
gap: 15px;
|
||||
padding: 8px 12px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.gauge-stat-value {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.accuracy-gauge-wrapper {
|
||||
height: 250px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script src="/static/js/i18n.js"></script>
|
||||
@@ -986,25 +1152,30 @@
|
||||
<div class="container">
|
||||
<!-- Stats Overview -->
|
||||
<div class="stats-badges">
|
||||
<div class="stat-badge">
|
||||
<span class="stat-icon">🏆</span>
|
||||
<div class="stat-number">{{ stats.total_tournaments }}</div>
|
||||
<div class="stat-label" data-i18n="tournament.tournaments">Tournaments</div>
|
||||
<div class="stat-badge tournament-badge">
|
||||
<div class="tournament-scores">
|
||||
<div class="tournament-score-item">
|
||||
<div class="tournament-emoji">🎯</div>
|
||||
<div class="tournament-type">4T</div>
|
||||
<div class="tournament-best" id="best-4">{{ stats.best_4_targets_score if stats.best_4_targets_score > 0 else 0 }}</div>
|
||||
</div>
|
||||
<div class="tournament-score-item">
|
||||
<div class="tournament-emoji">⚡</div>
|
||||
<div class="tournament-type">20T</div>
|
||||
<div class="tournament-best" id="best-20">{{ stats.best_20_targets_score if stats.best_20_targets_score > 0 else 0 }}</div>
|
||||
</div>
|
||||
<div class="tournament-score-item">
|
||||
<div class="tournament-emoji">💪</div>
|
||||
<div class="tournament-type">40T</div>
|
||||
<div class="tournament-best" id="best-40">{{ stats.best_40_targets_score if stats.best_40_targets_score > 0 else 0 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-label">Best Scores</div>
|
||||
</div>
|
||||
<div class="stat-badge">
|
||||
<span class="stat-icon">🎖️</span>
|
||||
<div class="stat-number">{{ stats.total_leagues }}</div>
|
||||
<div class="stat-label" data-i18n="league.league">Leagues</div>
|
||||
</div>
|
||||
<div class="stat-badge">
|
||||
<span class="stat-icon">⭐</span>
|
||||
<div class="stat-number">{{ stats.best_tournament_score }}</div>
|
||||
<div class="stat-label" data-i18n="results.best_score">Best Score</div>
|
||||
</div>
|
||||
<div class="stat-badge">
|
||||
<span class="stat-icon">📊</span>
|
||||
<div class="stat-number">{{ stats.average_tournament_score|round|int if stats.average_tournament_score > 0 else 0 }}</div>
|
||||
<div class="stat-label" data-i18n="results.average_score">Average</div>
|
||||
<span class="stat-icon">🎯</span>
|
||||
<div class="stat-number" id="mostCommon-badge">0</div>
|
||||
<div class="stat-label" data-i18n="results.most_common">Most Common</div>
|
||||
</div>
|
||||
<div class="stat-badge">
|
||||
<span class="stat-icon">🔫</span>
|
||||
@@ -1012,25 +1183,81 @@
|
||||
<div class="stat-label" data-i18n="results.total_shots">Total Shots</div>
|
||||
</div>
|
||||
<div class="stat-badge">
|
||||
<span class="stat-icon">📉</span>
|
||||
<div class="stat-number">{{ stats.worst_tournament_score if stats.worst_tournament_score > 0 else 0 }}</div>
|
||||
<div class="stat-label" data-i18n="results.worst_score">Worst Score</div>
|
||||
<span class="stat-icon">🏆</span>
|
||||
<div class="stat-number">{{ stats.total_tournaments }}</div>
|
||||
<div class="stat-label" data-i18n="tournament.tournaments">Tournaments</div>
|
||||
</div>
|
||||
<div class="stat-badge">
|
||||
<span class="stat-icon">👑</span>
|
||||
<div class="stat-number">{{ stats.total_leagues|default(0) }}</div>
|
||||
<div class="stat-label" data-i18n="league.league">Leagues</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 1: Overall Accuracy (Colorful - No Filters) -->
|
||||
<!-- Card 1: Overall Accuracy (Bar + Pie Charts) -->
|
||||
<div class="overall-accuracy-card">
|
||||
<div class="panel-title">📊 <span data-i18n="analysis.shot_accuracy">Overall Shot Accuracy</span></div>
|
||||
|
||||
<!-- Overall Shot Accuracy Section -->
|
||||
<!-- Charts Section -->
|
||||
<div class="overall-content-wrapper">
|
||||
<!-- Bar Chart: All Shots -->
|
||||
<div class="overall-chart-left">
|
||||
<canvas id="overallAccuracyChart"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Pie/Radar Chart -->
|
||||
<div class="overall-radar-right">
|
||||
<canvas id="overallRadarChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Shot Count Cards -->
|
||||
<div class="shot-count-cards">
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">10</div>
|
||||
<div class="shot-count" id="count-10">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">9</div>
|
||||
<div class="shot-count" id="count-9">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">8</div>
|
||||
<div class="shot-count" id="count-8">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">7</div>
|
||||
<div class="shot-count" id="count-7">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">6</div>
|
||||
<div class="shot-count" id="count-6">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">5</div>
|
||||
<div class="shot-count" id="count-5">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">4</div>
|
||||
<div class="shot-count" id="count-4">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">3</div>
|
||||
<div class="shot-count" id="count-3">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">2</div>
|
||||
<div class="shot-count" id="count-2">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">1</div>
|
||||
<div class="shot-count" id="count-1">0</div>
|
||||
</div>
|
||||
<div class="shot-count-card">
|
||||
<div class="shot-score">0</div>
|
||||
<div class="shot-count" id="count-0">0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 2: Filtered Accuracy (Main Outer Card - White) -->
|
||||
@@ -1058,13 +1285,17 @@
|
||||
<div class="chart-stat-value" id="gameCount">0</div>
|
||||
<div class="chart-stat-label" data-i18n="tournament.tournaments">Games</div>
|
||||
</div>
|
||||
<div class="chart-stat">
|
||||
<div class="chart-stat-value" id="bestScore">0</div>
|
||||
<div class="chart-stat-label" data-i18n="results.best_score">Best</div>
|
||||
</div>
|
||||
<div class="chart-stat">
|
||||
<div class="chart-stat-value" id="avgScore">0</div>
|
||||
<div class="chart-stat-label" data-i18n="results.average_score">Average</div>
|
||||
</div>
|
||||
<div class="chart-stat">
|
||||
<div class="chart-stat-value" id="bestScore">0</div>
|
||||
<div class="chart-stat-label" data-i18n="results.best_score">Best</div>
|
||||
<div class="chart-stat-value" id="mostCommonShot">0</div>
|
||||
<div class="chart-stat-label">Most Common</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1342,11 +1573,75 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Create overall accuracy bar chart
|
||||
// Create overall bar chart
|
||||
createOverallAccuracyChart(totalCounts);
|
||||
|
||||
// Create overall radar chart
|
||||
// Create overall pie chart
|
||||
createOverallRadarChart(totalCounts);
|
||||
|
||||
// Populate shot count cards
|
||||
populateShotCountCards(totalCounts);
|
||||
}
|
||||
|
||||
// Populate shot count cards below charts
|
||||
function populateShotCountCards(totalCounts) {
|
||||
const scoreMap = {
|
||||
10: totalCounts.tens,
|
||||
9: totalCounts.nines,
|
||||
8: totalCounts.eights,
|
||||
7: totalCounts.sevens,
|
||||
6: totalCounts.sixes,
|
||||
5: totalCounts.fives,
|
||||
4: totalCounts.fours,
|
||||
3: totalCounts.threes,
|
||||
2: totalCounts.twos,
|
||||
1: totalCounts.ones,
|
||||
0: totalCounts.zeros
|
||||
};
|
||||
|
||||
// Update shot count cards
|
||||
for (const [score, count] of Object.entries(scoreMap)) {
|
||||
const countElement = document.getElementById(`count-${score}`);
|
||||
if (countElement) {
|
||||
countElement.textContent = count;
|
||||
}
|
||||
}
|
||||
|
||||
// Update top stat badges
|
||||
updateTopStatsBadges(totalCounts);
|
||||
}
|
||||
|
||||
// Update top stat badges with overall metrics
|
||||
function updateTopStatsBadges(totalCounts) {
|
||||
// Perfect 10s count
|
||||
const totalTensBadge = document.getElementById('totalTens-badge');
|
||||
if (totalTensBadge) {
|
||||
totalTensBadge.textContent = totalCounts.tens;
|
||||
}
|
||||
|
||||
// Calculate most common shot value
|
||||
let mostCommonShot = 0;
|
||||
let maxCount = 0;
|
||||
|
||||
const shotScores = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
|
||||
const shotCountsArray = [
|
||||
totalCounts.tens, totalCounts.nines, totalCounts.eights,
|
||||
totalCounts.sevens, totalCounts.sixes, totalCounts.fives,
|
||||
totalCounts.fours, totalCounts.threes, totalCounts.twos,
|
||||
totalCounts.ones, totalCounts.zeros
|
||||
];
|
||||
|
||||
for (let i = 0; i < shotScores.length; i++) {
|
||||
if (shotCountsArray[i] > maxCount) {
|
||||
maxCount = shotCountsArray[i];
|
||||
mostCommonShot = shotScores[i];
|
||||
}
|
||||
}
|
||||
|
||||
const mostCommonBadge = document.getElementById('mostCommon-badge');
|
||||
if (mostCommonBadge) {
|
||||
mostCommonBadge.textContent = mostCommonShot;
|
||||
}
|
||||
}
|
||||
|
||||
// Create overall accuracy bar chart
|
||||
@@ -1505,6 +1800,124 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Create accuracy gauge chart (doughnut showing overall accuracy percentage)
|
||||
let accuracyGaugeChartInstance = null;
|
||||
|
||||
function createAccuracyGaugeChart(totalCounts) {
|
||||
const canvas = document.getElementById('accuracyGaugeChart');
|
||||
if (!canvas) {
|
||||
console.warn('Accuracy gauge chart canvas not found');
|
||||
return;
|
||||
}
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Destroy existing chart if it exists
|
||||
if (accuracyGaugeChartInstance) {
|
||||
accuracyGaugeChartInstance.destroy();
|
||||
}
|
||||
|
||||
// Calculate accuracy percentage (perfect shots 8-10 / total shots)
|
||||
const perfectShots = totalCounts.tens + totalCounts.nines + totalCounts.eights;
|
||||
const totalShots = Object.values(totalCounts).reduce((a, b) => a + b, 0);
|
||||
const accuracyPercentage = totalShots > 0 ? Math.round((perfectShots / totalShots) * 100) : 0;
|
||||
|
||||
// Calculate consistency score (lower variance = higher consistency)
|
||||
const shotValues = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
|
||||
const shotCounts = [totalCounts.tens, totalCounts.nines, totalCounts.eights, totalCounts.sevens, totalCounts.sixes, totalCounts.fives, totalCounts.fours, totalCounts.threes, totalCounts.twos, totalCounts.ones, totalCounts.zeros];
|
||||
|
||||
let mean = 0;
|
||||
if (totalShots > 0) {
|
||||
mean = shotValues.reduce((sum, val, i) => sum + (val * shotCounts[i]), 0) / totalShots;
|
||||
}
|
||||
|
||||
let variance = 0;
|
||||
if (totalShots > 0) {
|
||||
variance = shotValues.reduce((sum, val, i) => sum + (Math.pow(val - mean, 2) * shotCounts[i]), 0) / totalShots;
|
||||
}
|
||||
const consistency = Math.max(0, Math.round(100 - (variance * 5))); // Scale variance to 0-100
|
||||
|
||||
// Update DOM with percentages
|
||||
document.getElementById('accuracyPercentage').textContent = accuracyPercentage + '%';
|
||||
document.getElementById('consistencyScore').textContent = consistency;
|
||||
|
||||
const gaugeData = [accuracyPercentage, 100 - accuracyPercentage];
|
||||
|
||||
accuracyGaugeChartInstance = new Chart(ctx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ['Accuracy', 'Missed'],
|
||||
datasets: [{
|
||||
data: gaugeData,
|
||||
backgroundColor: ['#28a745', '#f0f0f0'],
|
||||
borderColor: ['#28a745', '#e0e0e0'],
|
||||
borderWidth: 3,
|
||||
circumference: 180,
|
||||
rotation: 270
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
return context.label + ': ' + context.parsed + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Update stat cards with performance metrics
|
||||
function updateStatCards(statsData, totalCounts) {
|
||||
try {
|
||||
// Count tournaments
|
||||
const tournaments = statsData.tournament_history ? statsData.tournament_history.length : 0;
|
||||
document.getElementById('totalTournaments').textContent = tournaments;
|
||||
|
||||
// Count total 10s
|
||||
const totalTens = totalCounts.tens || 0;
|
||||
document.getElementById('totalTens').textContent = totalTens;
|
||||
|
||||
// Calculate variance
|
||||
const shotValues = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
|
||||
const shotCounts = [totalCounts.tens, totalCounts.nines, totalCounts.eights, totalCounts.sevens, totalCounts.sixes, totalCounts.fives, totalCounts.fours, totalCounts.threes, totalCounts.twos, totalCounts.ones, totalCounts.zeros];
|
||||
const totalShots = shotCounts.reduce((a, b) => a + b, 0);
|
||||
|
||||
let mean = 0;
|
||||
if (totalShots > 0) {
|
||||
mean = shotValues.reduce((sum, val, i) => sum + (val * shotCounts[i]), 0) / totalShots;
|
||||
}
|
||||
|
||||
let variance = 0;
|
||||
if (totalShots > 0) {
|
||||
variance = shotValues.reduce((sum, val, i) => sum + (Math.pow(val - mean, 2) * shotCounts[i]), 0) / totalShots;
|
||||
}
|
||||
document.getElementById('scoreVariance').textContent = variance.toFixed(2);
|
||||
|
||||
// Calculate range (highest - lowest non-zero score)
|
||||
let minScore = null;
|
||||
let maxScore = null;
|
||||
|
||||
for (let i = 0; i < shotValues.length; i++) {
|
||||
if (shotCounts[i] > 0) {
|
||||
if (maxScore === null) maxScore = shotValues[i];
|
||||
minScore = shotValues[i];
|
||||
}
|
||||
}
|
||||
|
||||
const range = maxScore !== null ? (maxScore - minScore) : 0;
|
||||
document.getElementById('scoreRange').textContent = range;
|
||||
} catch (error) {
|
||||
console.error('Error updating stat cards:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Load shot accuracy data from template context
|
||||
function loadShotAccuracyData() {
|
||||
try {
|
||||
@@ -1672,10 +2085,41 @@
|
||||
const avgScore = gameCount > 0 ? Math.round(scores.reduce((a, b) => a + b, 0) / gameCount) : 0;
|
||||
const bestScore = gameCount > 0 ? Math.max(...scores) : 0;
|
||||
|
||||
// Calculate most common shot value
|
||||
let mostCommonShot = 0;
|
||||
const shotCounts = { 10: 0, 9: 0, 8: 0, 7: 0, 6: 0, 5: 0, 4: 0, 3: 0, 2: 0, 1: 0, 0: 0 };
|
||||
|
||||
tournaments.forEach(tournament => {
|
||||
if (tournament.shot_breakdown) {
|
||||
const breakdown = tournament.shot_breakdown;
|
||||
shotCounts[10] += breakdown.tens || 0;
|
||||
shotCounts[9] += breakdown.nines || 0;
|
||||
shotCounts[8] += breakdown.eights || 0;
|
||||
shotCounts[7] += breakdown.sevens || 0;
|
||||
shotCounts[6] += breakdown.sixes || 0;
|
||||
shotCounts[5] += breakdown.fives || 0;
|
||||
shotCounts[4] += breakdown.fours || 0;
|
||||
shotCounts[3] += breakdown.threes || 0;
|
||||
shotCounts[2] += breakdown.twos || 0;
|
||||
shotCounts[1] += breakdown.ones || 0;
|
||||
shotCounts[0] += breakdown.zeros || 0;
|
||||
}
|
||||
});
|
||||
|
||||
// Find shot value with highest count
|
||||
let maxCount = 0;
|
||||
for (const [score, count] of Object.entries(shotCounts)) {
|
||||
if (count > maxCount) {
|
||||
maxCount = count;
|
||||
mostCommonShot = parseInt(score);
|
||||
}
|
||||
}
|
||||
|
||||
// Update basic stats
|
||||
document.getElementById('gameCount').textContent = gameCount;
|
||||
document.getElementById('avgScore').textContent = avgScore;
|
||||
document.getElementById('bestScore').textContent = bestScore;
|
||||
document.getElementById('avgScore').textContent = avgScore;
|
||||
document.getElementById('mostCommonShot').textContent = mostCommonShot;
|
||||
|
||||
// Update shot accuracy stats (if available in tournament data)
|
||||
updateAccuracyStats(tournaments);
|
||||
@@ -1767,17 +2211,17 @@
|
||||
function generateColorfulArray() {
|
||||
// Color mapping from green (perfect 10) to red (misses 0): labels are [10,9,8,7,6,5,4,3,2,1,0]
|
||||
return [
|
||||
'#2E7D32', // 10 - green (perfect)
|
||||
'#388E3C', // 9 - green
|
||||
'#43A047', // 8 - green
|
||||
'#558B2F', // 7 - light green
|
||||
'#9CCC65', // 6 - lime green
|
||||
'#FDD835', // 5 - yellow
|
||||
'#FBC02D', // 4 - golden yellow
|
||||
'#FFA726', // 3 - orange
|
||||
'#FF7043', // 2 - light orange-red
|
||||
'#E53935', // 1 - red
|
||||
'#C62828' // 0 - dark red (miss)
|
||||
'#4A9D6F', // 10 - medium green (perfect)
|
||||
'#5BA97A', // 9 - medium green
|
||||
'#6CB585', // 8 - medium green
|
||||
'#7DC285', // 7 - medium light green
|
||||
'#8FCC7F', // 6 - medium lime green
|
||||
'#D4B84D', // 5 - medium yellow
|
||||
'#CDA642', // 4 - medium golden yellow
|
||||
'#D99A5D', // 3 - medium orange
|
||||
'#D87A6C', // 2 - medium light orange-red
|
||||
'#C85C5C', // 1 - medium red
|
||||
'#B84A4A' // 0 - medium dark red (miss)
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -223,6 +223,9 @@ def analyze_player_performance(player_id, archives_data):
|
||||
'best_tournament_score': 0,
|
||||
'worst_tournament_score': float('inf'),
|
||||
'average_tournament_score': 0,
|
||||
'best_4_targets_score': 0,
|
||||
'best_20_targets_score': 0,
|
||||
'best_40_targets_score': 0,
|
||||
'total_shots_fired': 0,
|
||||
'performance_trend': [],
|
||||
'tournament_history': [],
|
||||
@@ -264,6 +267,17 @@ def analyze_player_performance(player_id, archives_data):
|
||||
|
||||
player_stats['total_shots_fired'] += shots_in_tournament
|
||||
|
||||
# Track format-specific best scores
|
||||
if tournament_type == '4_targets':
|
||||
if score > player_stats['best_4_targets_score']:
|
||||
player_stats['best_4_targets_score'] = score
|
||||
elif tournament_type == '20_targets':
|
||||
if score > player_stats['best_20_targets_score']:
|
||||
player_stats['best_20_targets_score'] = score
|
||||
elif tournament_type == '40_targets':
|
||||
if score > player_stats['best_40_targets_score']:
|
||||
player_stats['best_40_targets_score'] = score
|
||||
|
||||
# Calculate and aggregate shot accuracy
|
||||
if tournament_type in player_stats['shot_accuracy']:
|
||||
shot_accuracy = calculate_shot_accuracy(participant)
|
||||
|
||||
Reference in New Issue
Block a user