Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Golf Score Tracker</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&family=Playfair+Display:wght@700&display=swap" rel="stylesheet"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #2e8540; | |
| --secondary: #f5f5f5; | |
| --accent: #e6b31e; | |
| --text: #333; | |
| --light-text: #777; | |
| --card-bg: #fff; | |
| --shadow: 0 4px 12px rgba(0, 0, 0, 0.1); | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Montserrat', sans-serif; | |
| color: var(--text); | |
| background-color: var(--secondary); | |
| line-height: 1.6; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| h1, h2, h3 { | |
| font-family: 'Playfair Display', serif; | |
| color: var(--primary); | |
| } | |
| h1 { | |
| text-align: center; | |
| margin-bottom: 30px; | |
| font-size: 2.5rem; | |
| position: relative; | |
| padding-bottom: 10px; | |
| } | |
| h1:after { | |
| content: ""; | |
| position: absolute; | |
| bottom: 0; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| width: 100px; | |
| height: 3px; | |
| background-color: var(--accent); | |
| } | |
| .course-selection { | |
| background-color: var(--card-bg); | |
| border-radius: 10px; | |
| padding: 25px; | |
| margin-bottom: 30px; | |
| box-shadow: var(--shadow); | |
| } | |
| .form-group { | |
| margin-bottom: 20px; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 8px; | |
| font-weight: 600; | |
| color: var(--primary); | |
| } | |
| select, input { | |
| width: 100%; | |
| padding: 12px; | |
| border: 1px solid #ddd; | |
| border-radius: 5px; | |
| font-size: 16px; | |
| transition: all 0.3s; | |
| } | |
| select:focus, input:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| box-shadow: 0 0 0 3px rgba(46, 133, 64, 0.2); | |
| } | |
| button { | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 12px 24px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 16px; | |
| font-weight: 600; | |
| transition: all 0.3s; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| } | |
| button:hover { | |
| background-color: #246b34; | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); | |
| } | |
| button:active { | |
| transform: translateY(0); | |
| } | |
| .scorecard-container { | |
| display: none; | |
| margin-top: 30px; | |
| overflow-x: auto; | |
| } | |
| .scorecard { | |
| width: 100%; | |
| border-collapse: collapse; | |
| background-color: var(--card-bg); | |
| border-radius: 10px; | |
| overflow: hidden; | |
| box-shadow: var(--shadow); | |
| margin-bottom: 30px; | |
| } | |
| .scorecard th, .scorecard td { | |
| padding: 12px 8px; | |
| text-align: center; | |
| border: 1px solid #e0e0e0; | |
| } | |
| .scorecard th { | |
| background-color: var(--primary); | |
| color: white; | |
| font-weight: 600; | |
| } | |
| .scorecard tr:nth-child(even) { | |
| background-color: rgba(46, 133, 64, 0.05); | |
| } | |
| .scorecard tr:hover { | |
| background-color: rgba(46, 133, 64, 0.1); | |
| } | |
| .hole-header { | |
| background-color: var(--primary) ; | |
| color: white; | |
| } | |
| .total-row { | |
| font-weight: 700; | |
| background-color: rgba(46, 133, 64, 0.15) ; | |
| } | |
| .input-section { | |
| background-color: var(--card-bg); | |
| border-radius: 10px; | |
| padding: 25px; | |
| box-shadow: var(--shadow); | |
| margin-bottom: 30px; | |
| } | |
| .input-grid { | |
| display: grid; | |
| grid-template-columns: repeat(9, 1fr); | |
| gap: 10px; | |
| margin-bottom: 20px; | |
| } | |
| .input-group { | |
| margin-bottom: 0; | |
| } | |
| .input-group label { | |
| font-size: 14px; | |
| margin-bottom: 5px; | |
| text-align: center; | |
| } | |
| .input-group input { | |
| padding: 8px; | |
| font-size: 14px; | |
| text-align: center; | |
| } | |
| .stats-container { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | |
| gap: 20px; | |
| margin-top: 30px; | |
| } | |
| .stat-card { | |
| background-color: var(--card-bg); | |
| border-radius: 10px; | |
| padding: 20px; | |
| box-shadow: var(--shadow); | |
| text-align: center; | |
| } | |
| .stat-card h3 { | |
| margin-bottom: 10px; | |
| font-size: 1.2rem; | |
| } | |
| .stat-value { | |
| font-size: 2rem; | |
| font-weight: 700; | |
| color: var(--primary); | |
| } | |
| .golf-ball { | |
| width: 200px; | |
| height: 200px; | |
| background: radial-gradient(circle at 30% 30%, white, #ddd); | |
| border-radius: 50%; | |
| margin: 20px auto; | |
| position: relative; | |
| box-shadow: inset -10px -10px 15px rgba(0, 0, 0, 0.3); | |
| } | |
| .dimples { | |
| position: absolute; | |
| width: 100%; | |
| height: 100%; | |
| border-radius: 50%; | |
| } | |
| .dimple { | |
| position: absolute; | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| background: radial-gradient(circle at 30% 30%, #ddd, #999); | |
| } | |
| @media (max-width: 768px) { | |
| .input-grid { | |
| grid-template-columns: repeat(6, 1fr); | |
| } | |
| .scorecard { | |
| font-size: 14px; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .input-grid { | |
| grid-template-columns: repeat(3, 1fr); | |
| } | |
| .stats-container { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| /* Hole colors based on performance */ | |
| .score-below-par { | |
| background-color: rgba(0, 128, 0, 0.2); | |
| font-weight: 600; | |
| } | |
| .score-par { | |
| background-color: rgba(230, 230, 0, 0.2); | |
| } | |
| .score-above-par { | |
| background-color: rgba(255, 0, 0, 0.2); | |
| font-weight: 600; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1><i class="fas fa-golf-ball"></i> Golf Score Tracker</h1> | |
| <div class="course-selection"> | |
| <div class="form-group"> | |
| <label for="golf-course"><i class="fas fa-flag"></i> Select Golf Course:</label> | |
| <select id="golf-course" class="form-control"> | |
| <option value="">-- Please select a course --</option> | |
| <option value="pinehurst">Pinehurst No. 2 (Par 72)</option> | |
| <option value="pebble">Pebble Beach Golf Links (Par 72)</option> | |
| <option value="augusta">Augusta National (Par 72)</option> | |
| <option value="st-andrews">St. Andrews Old Course (Par 72)</option> | |
| <option value="tpc-sawgrass">TPC Sawgrass (Par 72)</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="player-handicap"><i class="fas fa-user-tie"></i> Your Handicap:</label> | |
| <input type="number" id="player-handicap" class="form-control" min="0" max="36" value="18"> | |
| </div> | |
| <button id="start-round" class="btn"><i class="fas fa-play"></i> Start Round</button> | |
| </div> | |
| <div id="scorecard-container" class="scorecard-container"> | |
| <h2 id="course-name"></h2> | |
| <table class="scorecard"> | |
| <thead> | |
| <tr> | |
| <th>Hole</th> | |
| <th class="hole-header">1</th> | |
| <th class="hole-header">2</th> | |
| <th class="hole-header">3</th> | |
| <th class="hole-header">4</th> | |
| <th class="hole-header">5</th> | |
| <th class="hole-header">6</th> | |
| <th class="hole-header">7</th> | |
| <th class="hole-header">8</th> | |
| <th class="hole-header">9</th> | |
| <th class="hole-header">10</th> | |
| <th class="hole-header">11</th> | |
| <th class="hole-header">12</th> | |
| <th class="hole-header">13</th> | |
| <th class="hole-header">14</th> | |
| <th class="hole-header">15</th> | |
| <th class="hole-header">16</th> | |
| <th class="hole-header">17</th> | |
| <th class="hole-header">18</th> | |
| <th>Total</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>Par</td> | |
| <td id="par-1">4</td> | |
| <td id="par-2">4</td> | |
| <td id="par-3">3</td> | |
| <td id="par-4">5</td> | |
| <td id="par-5">4</td> | |
| <td id="par-6">4</td> | |
| <td id="par-7">3</td> | |
| <td id="par-8">4</td> | |
| <td id="par-9">5</td> | |
| <td id="par-10">4</td> | |
| <td id="par-11">4</td> | |
| <td id="par-12">3</td> | |
| <td id="par-13">5</td> | |
| <td id="par-14">4</td> | |
| <td id="par-15">4</td> | |
| <td id="par-16">3</td> | |
| <td id="par-17">4</td> | |
| <td id="par-18">5</td> | |
| <td id="total-par">72</td> | |
| </tr> | |
| <tr> | |
| <td>Handicap</td> | |
| <td id="hdcp-1">9</td> | |
| <td id="hdcp-2">15</td> | |
| <td id="hdcp-3">11</td> | |
| <td id="hdcp-4">1</td> | |
| <td id="hdcp-5">7</td> | |
| <td id="hdcp-6">17</td> | |
| <td id="hdcp-7">13</td> | |
| <td id="hdcp-8">3</td> | |
| <td id="hdcp-9">5</td> | |
| <td id="hdcp-10">8</td> | |
| <td id="hdcp-11">16</td> | |
| <td id="hdcp-12">12</td> | |
| <td id="hdcp-13">2</td> | |
| <td id="hdcp-14">6</td> | |
| <td id="hdcp-15">18</td> | |
| <td id="hdcp-16">10</td> | |
| <td id="hdcp-17">14</td> | |
| <td id="hdcp-18">4</td> | |
| <td>-</td> | |
| </tr> | |
| <tr> | |
| <td>Yards</td> | |
| <td id="yards-1">410</td> | |
| <td id="yards-2">340</td> | |
| <td id="yards-3">175</td> | |
| <td id="yards-4">565</td> | |
| <td id="yards-5">385</td> | |
| <td id="yards-6">340</td> | |
| <td id="yards-7">195</td> | |
| <td id="yards-8">415</td> | |
| <td id="yards-9">530</td> | |
| <td id="yards-10">430</td> | |
| <td id="yards-11">380</td> | |
| <td id="yards-12">150</td> | |
| <td id="yards-13">540</td> | |
| <td id="yards-14">440</td> | |
| <td id="yards-15">360</td> | |
| <td id="yards-16">190</td> | |
| <td id="yards-17">370</td> | |
| <td id="yards-18">500</td> | |
| <td id="total-yards">7,015</td> | |
| </tr> | |
| <tr> | |
| <td>Net Strokes</td> | |
| <td id="net-1">-</td> | |
| <td id="net-2">-</td> | |
| <td id="net-3">-</td> | |
| <td id="net-4">-</td> | |
| <td id="net-5">-</td> | |
| <td id="net-6">-</td> | |
| <td id="net-7">-</td> | |
| <td id="net-8">-</td> | |
| <td id="net-9">-</td> | |
| <td id="net-10">-</td> | |
| <td id="net-11">-</td> | |
| <td id="net-12">-</td> | |
| <td id="net-13">-</td> | |
| <td id="net-14">-</td> | |
| <td id="net-15">-</td> | |
| <td id="net-16">-</td> | |
| <td id="net-17">-</td> | |
| <td id="net-18">-</td> | |
| <td id="total-net">-</td> | |
| </tr> | |
| <tr> | |
| <td>Your Score</td> | |
| <td id="score-1">-</td> | |
| <td id="score-2">-</td> | |
| <td id="score-3">-</td> | |
| <td id="score-4">-</td> | |
| <td id="score-5">-</td> | |
| <td id="score-6">-</td> | |
| <td id="score-7">-</td> | |
| <td id="score-8">-</td> | |
| <td id="score-9">-</td> | |
| <td id="score-10">-</td> | |
| <td id="score-11">-</td> | |
| <td id="score-12">-</td> | |
| <td id="score-13">-</td> | |
| <td id="score-14">-</td> | |
| <td id="score-15">-</td> | |
| <td id="score-16">-</td> | |
| <td id="score-17">-</td> | |
| <td id="score-18">-</td> | |
| <td id="total-score">-</td> | |
| </tr> | |
| <tr class="total-row"> | |
| <td>To Par</td> | |
| <td id="topar-1">-</td> | |
| <td id="topar-2">-</td> | |
| <td id="topar-3">-</td> | |
| <td id="topar-4">-</td> | |
| <td id="topar-5">-</td> | |
| <td id="topar-6">-</td> | |
| <td id="topar-7">-</td> | |
| <td id="topar-8">-</td> | |
| <td id="topar-9">-</td> | |
| <td id="topar-10">-</td> | |
| <td id="topar-11">-</td> | |
| <td id="topar-12">-</td> | |
| <td id="topar-13">-</td> | |
| <td id="topar-14">-</td> | |
| <td id="topar-15">-</td> | |
| <td id="topar-16">-</td> | |
| <td id="topar-17">-</td> | |
| <td id="topar-18">-</td> | |
| <td id="total-topar">-</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <div class="input-section"> | |
| <h3><i class="fas fa-pencil-alt"></i> Enter Your Scores</h3> | |
| <div class="input-grid"> | |
| <!-- Front 9 --> | |
| <div class="input-group"> | |
| <label for="hole-1">Hole 1 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-1" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-2">Hole 2 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-2" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-3">Hole 3 (Par <span class="par-value">3</span>)</label> | |
| <input type="number" id="hole-3" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-4">Hole 4 (Par <span class="par-value">5</span>)</label> | |
| <input type="number" id="hole-4" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-5">Hole 5 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-5" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-6">Hole 6 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-6" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-7">Hole 7 (Par <span class="par-value">3</span>)</label> | |
| <input type="number" id="hole-7" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-8">Hole 8 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-8" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-9">Hole 9 (Par <span class="par-value">5</span>)</label> | |
| <input type="number" id="hole-9" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <!-- Back 9 --> | |
| <div class="input-group"> | |
| <label for="hole-10">Hole 10 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-10" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-11">Hole 11 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-11" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-12">Hole 12 (Par <span class="par-value">3</span>)</label> | |
| <input type="number" id="hole-12" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-13">Hole 13 (Par <span class="par-value">5</span>)</label> | |
| <input type="number" id="hole-13" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-14">Hole 14 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-14" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-15">Hole 15 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-15" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-16">Hole 16 (Par <span class="par-value">3</span>)</label> | |
| <input type="number" id="hole-16" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-17">Hole 17 (Par <span class="par-value">4</span>)</label> | |
| <input type="number" id="hole-17" min="1" max="15" placeholder="Score"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="hole-18">Hole 18 (Par <span class="par-value">5</span>)</label> | |
| <input type="number" id="hole-18" min="1" max="15" placeholder="Score"> | |
| </div> | |
| </div> | |
| <button id="calculate-scores" class="btn"><i class="fas fa-calculator"></i> Calculate Scores</button> | |
| </div> | |
| <div class="stats-container"> | |
| <div class="stat-card"> | |
| <h3><i class="fas fa-golf-ball"></i> Total Strokes</h3> | |
| <div class="golf-ball"> | |
| <div class="dimples"> | |
| <!-- Dimples will be added with JavaScript --> | |
| </div> | |
| </div> | |
| <div class="stat-value" id="total-strokes">0</div> | |
| </div> | |
| <div class="stat-card"> | |
| <h3><i class="fas fa-flag"></i> Score to Par</h3> | |
| <i class="fas fa-exchange-alt" style="font-size: 3rem; color: var(--accent); margin: 15px 0;"></i> | |
| <div class="stat-value" id="score-to-par">+0</div> | |
| </div> | |
| <div class="stat-card"> | |
| <h3><i class="fas fa-star"></i> Net Score</h3> | |
| <i class="fas fa-adjust" style="font-size: 3rem; color: var(--accent); margin: 15px 0;"></i> | |
| <div class="stat-value" id="net-score">0</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Golf course data | |
| const courses = { | |
| "pinehurst": { | |
| name: "Pinehurst No. 2", | |
| holes: [ | |
| {number: 1, par: 4, handicap: 9, yards: 410}, | |
| {number: 2, par: 4, handicap: 15, yards: 340}, | |
| {number: 3, par: 3, handicap: 11, yards: 175}, | |
| {number: 4, par: 5, handicap: 1, yards: 565}, | |
| {number: 5, par: 4, handicap: 7, yards: 385}, | |
| {number: 6, par: 4, handicap: 17, yards: 340}, | |
| {number: 7, par: 3, handicap: 13, yards: 195}, | |
| {number: 8, par: 4, handicap: 3, yards: 415}, | |
| {number: 9, par: 5, handicap: 5, yards: 530}, | |
| {number: 10, par: 4, handicap: 8, yards: 430}, | |
| {number: 11, par: 4, handicap: 16, yards: 380}, | |
| {number: 12, par: 3, handicap: 12, yards: 150}, | |
| {number: 13, par: 5, handicap: 2, yards: 540}, | |
| {number: 14, par: 4, handicap: 6, yards: 440}, | |
| {number: 15, par: 4, handicap: 18, yards: 360}, | |
| {number: 16, par: 3, handicap: 10, yards: 190}, | |
| {number: 17, par: 4, handicap: 14, yards: 370}, | |
| {number: 18, par: 5, handicap: 4, yards: 500} | |
| ] | |
| }, | |
| "pebble": { | |
| name: "Pebble Beach Golf Links", | |
| holes: [ | |
| {number: 1, par: 4, handicap: 13, yards: 380}, | |
| {number: 2, par: 5, handicap: 5, yards: 516}, | |
| {number: 3, par: 4, handicap: 9, yards: 404}, | |
| {number: 4, par: 4, handicap: 11, yards: 331}, | |
| {number: 5, par: 3, handicap: 15, yards: 195}, | |
| {number: 6, par: 5, handicap: 1, yards: 523}, | |
| {number: 7, par: 3, handicap: 17, yards: 109}, | |
| {number: 8, par: 4, handicap: 7, yards: 428}, | |
| {number: 9, par: 4, handicap: 3, yards: 505}, | |
| {number: 10, par: 4, handicap: 6, yards: 495}, | |
| {number: 11, par: 4, handicap: 14, yards: 390}, | |
| {number: 12, par: 3, handicap: 18, yards: 202}, | |
| {number: 13, par: 4, handicap: 4, yards: 445}, | |
| {number: 14, par: 5, handicap: 2, yards: 580}, | |
| {number: 15, par: 4, handicap: 10, yards: 397}, | |
| {number: 16, par: 4, handicap: 8, yards: 403}, | |
| {number: 17, par: 3, handicap: 16, yards: 208}, | |
| {number: 18, par: 5, handicap: 12, yards: 548} | |
| ] | |
| }, | |
| "augusta": { | |
| name: "Augusta National Golf Club", | |
| holes: [ | |
| {number: 1, par: 4, handicap: 4, yards: 445}, | |
| {number: 2, par: 5, handicap: 12, yards: 575}, | |
| {number: 3, par: 4, handicap: 16, yards: 350}, | |
| {number: 4, par: 3, handicap: 10, yards: 240}, | |
| {number: 5, par: 4, handicap: 2, yards: 495}, | |
| {number: 6, par: 3, handicap: 14, yards: 180}, | |
| {number: 7, par: 4, handicap: 8, yards: 450}, | |
| {number: 8, par: 5, handicap: 6, yards: 570}, | |
| {number: 9, par: 4, handicap: 18, yards: 460}, | |
| {number: 10, par: 4, handicap: 5, yards: 495}, | |
| {number: 11, par: 4, handicap: 1, yards: 505}, | |
| {number: 12, par: 3, handicap: 11, yards: 155}, | |
| {number: 13, par: 5, handicap: 7, yards: 510}, | |
| {number: 14, par: 4, handicap: 13, yards: 440}, | |
| {number: 15, par: 5, handicap: 9, yards: 550}, | |
| {number: 16, par: 3, handicap: 15, yards: 170}, | |
| {number: 17, par: 4, handicap: 3, yards: 440}, | |
| {number: 18, par: 4, handicap: 17, yards: 465} | |
| ] | |
| }, | |
| "st-andrews": { | |
| name: "St. Andrews Old Course", | |
| holes: [ | |
| {number: 1, par: 4, handicap: 6, yards: 376}, | |
| {number: 2, par: 4, handicap: 14, yards: 453}, | |
| {number: 3, par: 4, handicap: 12, yards: 397}, | |
| {number: 4, par: 4, handicap: 8, yards: 480}, | |
| {number: 5, par: 5, handicap: 4, yards: 568}, | |
| {number: 6, par: 4, handicap: 16, yards: 412}, | |
| {number: 7, par: 4, handicap: 18, yards: 371}, | |
| {number: 8, par: 3, handicap: 10, yards: 175}, | |
| {number: 9, par: 4, handicap: 2, yards: 352}, | |
| {number: 10, par: 4, handicap: 5, yards: 386}, | |
| {number: 11, par: 3, handicap: 17, yards: 174}, | |
| {number: 12, par: 4, handicap: 1, yards: 348}, | |
| {number: 13, par: 4, handicap: 7, yards: 465}, | |
| {number: 14, par: 5, handicap: 9, yards: 618}, | |
| {number: 15, par: 4, handicap: 13, yards: 455}, | |
| {number: 16, par: 4, handicap: 3, yards: 423}, | |
| {number: 17, par: 4, handicap: 11, yards: 495}, | |
| {number: 18, par: 4, handicap: 15, yards: 357} | |
| ] | |
| }, | |
| "tpc-sawgrass": { | |
| name: "TPC Sawgrass (Stadium Course)", | |
| holes: [ | |
| {number: 1, par: 4, handicap: 11, yards: 423}, | |
| {number: 2, par: 5, handicap: 17, yards: 532}, | |
| {number: 3, par: 3, handicap: 13, yards: 177}, | |
| {number: 4, par: 4, handicap: 5, yards: 384}, | |
| {number: 5, par: 4, handicap: 9, yards: 471}, | |
| {number: 6, par: 4, handicap: 7, yards: 393}, | |
| {number: 7, par: 4, handicap: 1, yards: 442}, | |
| {number: 8, par: 3, handicap: 15, yards: 219}, | |
| {number: 9, par: 5, handicap: 3, yards: 583}, | |
| {number: 10, par: 4, handicap: 12, yards: 424}, | |
| {number: 11, par: 5, handicap: 10, yards: 535}, | |
| {number: 12, par: 4, handicap: 6, yards: 358}, | |
| {number: 13, par: 3, handicap: 18, yards: 181}, | |
| {number: 14, par: 4, handicap: 4, yards: 467}, | |
| {number: 15, par: 4, handicap: 14, yards: 449}, | |
| {number: 16, par: 5, handicap: 8, yards: 523}, | |
| {number: 17, par: 3, handicap: 16, yards: 137}, | |
| {number: 18, par: 4, handicap: 2, yards: 462} | |
| ] | |
| } | |
| }; | |
| // DOM elements | |
| const courseSelect = document.getElementById('golf-course'); | |
| const handicapInput = document.getElementById('player-handicap'); | |
| const startRoundBtn = document.getElementById('start-round'); | |
| const scorecardContainer = document.getElementById('scorecard-container'); | |
| const courseNameElement = document.getElementById('course-name'); | |
| const calculateScoresBtn = document.getElementById('calculate-scores'); | |
| const totalStrokesElement = document.getElementById('total-strokes'); | |
| const scoreToParElement = document.getElementById('score-to-par'); | |
| const netScoreElement = document.getElementById('net-score'); | |
| const dimplesContainer = document.querySelector('.dimples'); | |
| // Create dimples on golf ball | |
| function createDimples() { | |
| const dimpleCount = 300; | |
| dimplesContainer.innerHTML = ''; | |
| for (let i = 0; i < dimpleCount; i++) { | |
| const dimple = document.createElement('div'); | |
| dimple.className = 'dimple'; | |
| // Random polar coordinates | |
| const theta = Math.random() * Math.PI * 2; | |
| // We use acos to get a uniform distribution on the sphere | |
| const phi = Math.acos(2 * Math.random() - 1); | |
| // Convert to Cartesian coordinates | |
| const u = Math.random(); | |
| const radius = 80 * Math.sqrt(u); | |
| const x = radius * Math.cos(theta) * Math.sin(phi); | |
| const y = radius * Math.sin(theta) * Math.sin(phi); | |
| // Position the dimples | |
| dimple.style.left = `calc(50% + ${x}px)`; | |
| dimple.style.top = `calc(50% + ${y}px)`; | |
| // Random size variation | |
| const size = 3 + Math.random() * 4; | |
| dimple.style.width = `${size}px`; | |
| dimple.style.height = `${size}px`; | |
| dimplesContainer.appendChild(dimple); | |
| } | |
| } | |
| // Initialize golf course | |
| function initCourse() { | |
| const selectedCourse = courseSelect.value; | |
| if (!selectedCourse) { | |
| alert('Please select a golf course'); | |
| return; | |
| } | |
| const course = courses[selectedCourse]; | |
| const handicap = parseInt(handicapInput.value) || 0; | |
| // Set course name | |
| courseNameElement.textContent = course.name; | |
| // Populate scorecard | |
| let totalYards = 0; | |
| let totalPar = 0; | |
| course.holes.forEach(hole => { | |
| // Update par row | |
| document.getElementById(`par-${hole.number}`).textContent = hole.par; | |
| // Update handicap row | |
| document.getElementById(`hdcp-${hole.number}`).textContent = hole.handicap; | |
| // Update yards row | |
| document.getElementById(`yards-${hole.number}`).textContent = hole.yards; | |
| // Update input labels | |
| const inputLabel = document.querySelector(`label[for="hole-${hole.number}"] .par-value`); | |
| if (inputLabel) { | |
| inputLabel.textContent = hole.par; | |
| } | |
| totalYards += hole.yards; | |
| totalPar += hole.par; | |
| }); | |
| // Update totals | |
| document.getElementById('total-par').textContent = totalPar; | |
| document.getElementById('total-yards').textContent = totalYards.toLocaleString(); | |
| // Clear scores | |
| for (let i = 1; i <= 18; i++) { | |
| document.getElementById(`score-${i}`).textContent = '-'; | |
| document.getElementById(`net-${i}`).textContent = '-'; | |
| document.getElementById(`topar-${i}`).textContent = '-'; | |
| // Remove any styling | |
| document.getElementById(`score-${i}`).className = ''; | |
| } | |
| document.getElementById('total-score').textContent = '-'; | |
| document.getElementById('total-net').textContent = '-'; | |
| document.getElementById('total-topar').textContent = '-'; | |
| totalStrokesElement.textContent = '0'; | |
| scoreToParElement.textContent = '+0'; | |
| netScoreElement.textContent = '0'; | |
| // Show scorecard | |
| scorecardContainer.style.display = 'block'; | |
| // Clear all input fields | |
| for (let i = 1; i <= 18; i++) { | |
| document.getElementById(`hole-${i}`).value = ''; | |
| } | |
| // Scroll to scorecard | |
| scorecardContainer.scrollIntoView({ behavior: 'smooth' }); | |
| } | |
| // Calculate scores | |
| function calculateScores() { | |
| const selectedCourse = courseSelect.value; | |
| if (!selectedCourse) { | |
| alert('Please select a golf course first'); | |
| return; | |
| } | |
| const course = courses[selectedCourse]; | |
| const handicap = parseInt(handicapInput.value) || 0; | |
| let totalScore = 0; | |
| let totalNetScore = 0; | |
| let totalToPar = 0; | |
| course.holes.forEach(hole => { | |
| const scoreInput = document.getElementById(`hole-${hole.number}`); | |
| const score = parseInt(scoreInput.value) || 0; | |
| if (score > 0) { | |
| // Calculate net score based on handicap | |
| let netScore = score; | |
| let strokesGiven = Math.floor(handicap / 18); | |
| // Assign additional strokes to the hardest holes (lowest handicap numbers) | |
| if (hole.handicap <= handicap % 18) { | |
| strokesGiven += 1; | |
| } | |
| netScore = Math.max(score - strokesGiven, 1); | |
| // Update scorecard | |
| document.getElementById(`score-${hole.number}`).textContent = score; | |
| document.getElementById(`net-${hole.number}`).textContent = netScore; | |
| // Calculate to par for this hole | |
| const toPar = score - hole.par; | |
| const toParDisplay = toPar > 0 ? `+${toPar}` : toPar === 0 ? 'E' : toPar; | |
| document.getElementById(`topar-${hole.number}`).textContent = toParDisplay; | |
| // Style based on performance | |
| const scoreCell = document.getElementById(`score-${hole.number}`); | |
| scoreCell.className = ''; | |
| if (toPar < 0) { | |
| scoreCell.classList.add('score-below-par'); | |
| } else if (toPar === 0) { | |
| scoreCell.classList.add('score-par'); | |
| } else { | |
| scoreCell.classList.add('score-above-par'); | |
| } | |
| // Update totals | |
| totalScore += score; | |
| totalNetScore += netScore; | |
| totalToPar += toPar; | |
| } | |
| }); | |
| // Update totals | |
| if (totalScore > 0) { | |
| document.getElementById('total-score').textContent = totalScore; | |
| document.getElementById('total-net').textContent = totalNetScore; | |
| const toParDisplay = totalToPar > 0 ? `+${totalToPar}` : totalToPar === 0 ? 'E' : totalToPar; | |
| document.getElementById('total-topar').textContent = toParDisplay; | |
| // Update stats | |
| totalStrokesElement.textContent = totalScore; | |
| scoreToParElement.textContent = toParDisplay; | |
| netScoreElement.textContent = totalNetScore; | |
| // Animate golf ball based on performance | |
| const golfBall = document.querySelector('.golf-ball'); | |
| golfBall.style.transform = ''; | |
| void golfBall.offsetWidth; // Trigger reflow | |
| if (totalToPar < 0) { | |
| golfBall.style.transform = 'rotate(360deg)'; | |
| } else if (totalToPar > 5) { | |
| golfBall.style.animation = 'shake 0.5s linear 3'; | |
| } | |
| } | |
| } | |
| // Event listeners | |
| startRoundBtn.addEventListener('click', initCourse); | |
| calculateScoresBtn.addEventListener('click', calculateScores); | |
| // Initialize dimples on golf ball | |
| createDimples(); | |
| // Add animation for shake effect | |
| const style = document.createElement('style'); | |
| style.textContent = ` | |
| @keyframes shake { | |
| 0% { transform: translateX(0); } | |
| 25% { transform: translateX(-5px); } | |
| 50% { transform: translateX(0); } | |
| 75% { transform: translateX(5px); } | |
| 100% { transform: translateX(0); } | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: absolute; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">This website has been generated by <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> | |
| </html> |