Well, obviously that was horrible. Similar to the the last 2024 loss to Oklahoma, then the 2025 SECCG loss, I’m not going to try to talk you out of this one. (Notably, I’m not including the the Florida
State loss, which was actually closer than it looked, nor the 2018 title loss to Clemson, where the scoreboard and efficiency metrics were bizarrely flipped).
So I’ll do a quick tour of the graveyard before I present some silver linings in this historic Alabama loss.
The bad stuff (scroll down to skip)
.cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .chart-content { height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767317416809-s7qitf381 .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767317416809_s7qitf381() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767317416809-s7qitf381'); const caret = document.getElementById('caret_cfb-chart-1767317416809-s7qitf381'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767317416809-s7qitf381'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767317416809-s7qitf381'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "labels": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129 ], "datasets": [ { "label": "Win Probability", "data": [ { "x": 0, "y": 41.40433073043823 }, { "x": 1, "y": 46.84382081031799 }, { "x": 2, "y": 42.02837347984314 }, { "x": 3, "y": 53.27779948711395 }, { "x": 4, "y": 48.06778430938721 }, { "x": 5, "y": 46.97570204734802 }, { "x": 6, "y": 45.269423723220825 }, { "x": 7, "y": 50.802844762802124 }, { "x": 8, "y": 51.15268528461456 }, { "x": 9, "y": 52.1688312292099 }, { "x": 10, "y": 50.436654686927795 }, { "x": 11, "y": 46.09171748161316 }, { "x": 12, "y": 45.4551100730896 }, { "x": 13, "y": 44.55268979072571 }, { "x": 14, "y": 44.204169511795044 }, { "x": 15, "y": 44.192737340927124 }, { "x": 16, "y": 43.4902548789978 }, { "x": 17, "y": 41.3402795791626 }, { "x": 18, "y": 42.30695962905884 }, { "x": 19, "y": 40.32871127128601 }, { "x": 20, "y": 42.34618544578552 }, { "x": 21, "y": 34.92523431777954 }, { "x": 22, "y": 35.38596034049988 }, { "x": 23, "y": 33.880025148391724 }, { "x": 24, "y": 35.711246728897095 }, { "x": 25, "y": 34.799474477767944 }, { "x": 26, "y": 38.65419030189514 }, { "x": 27, "y": 41.69473052024841 }, { "x": 28, "y": 42.078328132629395 }, { "x": 29, "y": 36.35261058807373 }, { "x": 30, "y": 32.63196349143982 }, { "x": 31, "y": 31.45318031311035 }, { "x": 32, "y": 30.11992573738098 }, { "x": 33, "y": 29.777556657791138 }, { "x": 34, "y": 28.359907865524292 }, { "x": 35, "y": 29.067903757095337 }, { "x": 36, "y": 27.194654941558838 }, { "x": 37, "y": 27.042680978775024 }, { "x": 38, "y": 16.05970859527588 }, { "x": 39, "y": 16.201913356781006 }, { "x": 40, "y": 15.926790237426758 }, { "x": 41, "y": 17.301535606384277 }, { "x": 42, "y": 16.77185297012329 }, { "x": 43, "y": 15.554165840148926 }, { "x": 44, "y": 15.214306116104126 }, { "x": 45, "y": 18.058323860168457 }, { "x": 46, "y": 18.514937162399292 }, { "x": 47, "y": 17.461055517196655 }, { "x": 48, "y": 19.685709476470947 }, { "x": 49, "y": 17.005300521850586 }, { "x": 50, "y": 17.17855930328369 }, { "x": 51, "y": 17.305946350097656 }, { "x": 52, "y": 17.542123794555664 }, { "x": 53, "y": 19.066905975341797 }, { "x": 54, "y": 20.043498277664185 }, { "x": 55, "y": 18.86775493621826 }, { "x": 56, "y": 16.411620378494263 }, { "x": 57, "y": 15.677106380462646 }, { "x": 58, "y": 4.103535413742065 }, { "x": 59, "y": 13.873708248138428 }, { "x": 60, "y": 13.653945922851562 }, { "x": 61, "y": 13.332575559616089 }, { "x": 62, "y": 12.747472524642944 }, { "x": 63, "y": 13.435256481170654 }, { "x": 64, "y": 13.735431432723999 }, { "x": 65, "y": 15.10348916053772 }, { "x": 66, "y": 5.934673547744751 }, { "x": 67, "y": 3.818678855895996 }, { "x": 68, "y": 3.4718096256256104 }, { "x": 69, "y": 5.117344856262207 }, { "x": 70, "y": 3.6463677883148193 }, { "x": 71, "y": 2.994281053543091 }, { "x": 72, "y": 1.3249993324279785 }, { "x": 73, "y": 3.7302732467651367 }, { "x": 74, "y": 3.810971975326538 }, { "x": 75, "y": 3.7460148334503174 }, { "x": 76, "y": 2.9154062271118164 }, { "x": 77, "y": 2.3249268531799316 }, { "x": 78, "y": 2.126026153564453 }, { "x": 79, "y": 1.7264366149902344 }, { "x": 80, "y": 1.9168555736541748 }, { "x": 81, "y": 2.420574426651001 }, { "x": 82, "y": 0.16747713088989258 }, { "x": 83, "y": 0.9652256965637207 }, { "x": 84, "y": 1.087886095046997 }, { "x": 85, "y": 2.659153938293457 }, { "x": 86, "y": 2.1353542804718018 }, { "x": 87, "y": 3.9226174354553223 }, { "x": 88, "y": 4.416280984878551 }, { "x": 89, "y": 4.1341960430146045 }, { "x": 90, "y": 1.70473456382767 }, { "x": 91, "y": 0.19190907478350283 }, { "x": 92, "y": 2.292853593826283 }, { "x": 93, "y": 2.5264322757719837 }, { "x": 94, "y": 2.696776390075162 }, { "x": 95, "y": 0.25421977043347255 }, { "x": 96, "y": 0.13681054116028157 }, { "x": 97, "y": 0 }, { "x": 98, "y": 0 }, { "x": 99, "y": 0.3481984139674821 }, { "x": 100, "y": 0 }, { "x": 101, "y": 0 }, { "x": 102, "y": 0 }, { "x": 103, "y": 0.03216266723371497 }, { "x": 104, "y": 1.4652848262230234 }, { "x": 105, "y": 1.425617938654311 }, { "x": 106, "y": 0 }, { "x": 107, "y": 0 }, { "x": 108, "y": 0.01105100197095199 }, { "x": 109, "y": 1.2588508812442556 }, { "x": 110, "y": 1.5237304272211705 }, { "x": 111, "y": 0.5561097336832632 }, { "x": 112, "y": 1.8457187622392013 }, { "x": 113, "y": 1.3932903367845362 }, { "x": 114, "y": 0 }, { "x": 115, "y": 1.811110175656827 }, { "x": 116, "y": 2.090799901868323 }, { "x": 117, "y": 0.95158857738189 }, { "x": 118, "y": 0 }, { "x": 119, "y": 0.14545122426259383 }, { "x": 120, "y": 0 }, { "x": 121, "y": 0.6733272955304237 }, { "x": 122, "y": 0.29466478078606917 }, { "x": 123, "y": 0 }, { "x": 124, "y": 1.208910346031189 }, { "x": 125, "y": 3.319263458251953 }, { "x": 126, "y": 2.6072272777784677 }, { "x": 127, "y": 1.881781747684208 }, { "x": 128, "y": 4.320339555057407 }, { "x": 129, "y": 0 } ], "borderColor": "#af283c", "backgroundColor": "transparent", "pointBackgroundColor": [ "rgb(153, 0, 0)", "rgb(159, 12, 17)", "rgb(153, 0, 0)", "rgb(169, 29, 43)", "rgb(161, 15, 22)", "rgb(160, 12, 18)", "rgb(157, 7, 11)", "rgb(165, 22, 33)", "rgb(166, 23, 35)", "rgb(167, 26, 39)", "rgb(165, 21, 32)", "rgb(158, 10, 14)", "rgb(157, 8, 12)", "rgb(156, 5, 8)", "rgb(155, 5, 7)", "rgb(155, 5, 7)", "rgb(154, 3, 4)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)" ], "pointBorderColor": [ "rgb(153, 0, 0)", "rgb(159, 12, 17)", "rgb(153, 0, 0)", "rgb(169, 29, 43)", "rgb(161, 15, 22)", "rgb(160, 12, 18)", "rgb(157, 7, 11)", "rgb(165, 22, 33)", "rgb(166, 23, 35)", "rgb(167, 26, 39)", "rgb(165, 21, 32)", "rgb(158, 10, 14)", "rgb(157, 8, 12)", "rgb(156, 5, 8)", "rgb(155, 5, 7)", "rgb(155, 5, 7)", "rgb(154, 3, 4)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)" ], "pointRadius": 0, "pointHoverRadius": 4, "tension": 0.15, "borderWidth": 2.2, "fill": false, "selectedTeam": "Alabama", "opponentTeam": "Indiana", "isSelectedTeamHome": false, "playTexts": [ "(15:00) Shotgun #15 F.Mendoza sacked for loss of 2 yards to the IND23 (#42 Y.Pierre, #0 D.Lawson)", "(14:26) Shotgun #1 R.Hemby rush right for 8 yards gain to the IND31 (#10 J.Jefferson)", "(13:49) Shotgun #15 F.Mendoza sacked for loss of 11 yards to the IND20 (#18 B.Hubbard)", "(13:06) #44 M.McCarthy punt 39 yards to the ALA41, out of bounds at ALA41", "(13:00) Shotgun #15 T.Simpson pass incomplete short left to #80 J.Cuevas thrown to ALA45 QB hurried by #97 M.Landino", "(12:54) Shotgun #15 T.Simpson pass complete short left to #2 R.Williams caught at ALA44, for 4 yards to the ALA45 (#22 J.Sharpe)", "(12:23) No Huddle-Shotgun #15 T.Simpson pass complete short middle to #4 D.Hill caught at ALA50, for 6 yards to the IND49 (#4 A.Fisher), 1ST DOWN", "(11:49) #15 T.Simpson pass complete short right to #80 J.Cuevas caught at IND44, for 6 yards to the IND43 (#21 R.Hardy)", "(11:04) #4 D.Hill rush left for 6 yards gain to the IND37 (#7 L.Moore), 1ST DOWN", "(10:29) No Huddle-Shotgun #4 D.Hill rush right for 0 yards to the IND37 (#7 L.Moore; #21 R.Hardy)", "(09:50) No Huddle-Shotgun #15 T.Simpson pass complete short left to #4 D.Hill caught at IND43, for 4 yards loss to the IND41 (#12 D.Boykin)", "(09:07) No Huddle-Shotgun #15 T.Simpson pass incomplete deep left to #2 R.Williams thrown to IND06 broken up by #7 L.Moore QB hurried by #2 B.Baldwin Jr.", "(08:58) #38 B.Doud punt 38 yards to the IND03", "(08:52) Shotgun #8 K.Black rush middle for 2 yards gain to the IND05 (#90 L.Simmons)", "(08:17) Shotgun #8 K.Black rush middle for 6 yards gain to the IND11 (#4 Q.Russaw; #41 N.Hill-Green)", "(07:40) Shotgun #15 F.Mendoza pass complete short middle to #13 E.Sarratt caught at IND15, for 7 yards to the IND18 (#2 Z.Brown), 1ST DOWN", "(07:04) Shotgun #15 F.Mendoza pass complete short left to #13 E.Sarratt caught at IND25, for 9 yards to the IND27 (#41 N.Hill-Green; #0 D.Lawson)", "(06:24) Shotgun #15 F.Mendoza pass complete short right to #13 E.Sarratt caught at IND26, for 0 yards to the IND27 (#2 Z.Brown)", "(05:49) #1 R.Hemby rush middle for 2 yards gain to the IND29 (#18 B.Hubbard), 1ST DOWN", "(05:17) Shotgun #1 R.Hemby rush left for 1 yard gain to the IND30 (#3 K.Sabb; #11 J.Renaud)", "(04:41) Shotgun #15 F.Mendoza pass complete deep right to #80 C.Becker caught at ALA40, for 30 yards to the ALA40 (#2 Z.Brown), out of bounds, 1ST DOWN", "(04:35) Shotgun #8 K.Black rush left for 5 yards gain to the ALA35 (#42 Y.Pierre)", "(03:52) Shotgun #8 K.Black rush middle for 6 yards gain to the ALA29 (#22 L.Overton), 1ST DOWN", "(03:12) Shotgun #15 F.Mendoza pass complete short right to #7 E.Williams Jr. caught at ALA26, for 9 yards to the ALA20 (#2 Z.Brown), out of bounds", "(02:31) Shotgun #8 K.Black rush middle for 7 yards gain to the ALA13 (#3 K.Sabb; #22 L.Overton), 1ST DOWN", "(01:49) Shotgun #1 R.Hemby rush middle for 1 yard gain to the ALA12 (#94 E.Hill)", "(01:07) Shotgun #15 F.Mendoza pass complete short middle to #37 R.Nowakowski caught at ALA12, for 0 yards to the ALA12 (#96 T.Keenan III)", "(00:22) Shotgun #1 R.Hemby rush middle for 1 yard loss to the ALA13 (#41 N.Hill-Green; #18 B.Hubbard)", "End of 1st quarter.", "(14:59) #15 N.Radicic field goal attempt from 31 yards GOOD (H: #44 M.McCarthy, LS: #47 M.Langston), clock 14:57", "(14:57) #28 K.Riley rush left for 0 yards to the ALA25 (#46 I.Jones)", "(14:11) #28 K.Riley rush middle for 2 yards gain to the ALA27 (#46 I.Jones; #0 H.Wheeler)", "(13:30) Shotgun #15 T.Simpson rush right for 7 yards gain to the ALA34 (#4 A.Fisher)", "(12:44) Shotgun #4 D.Hill pass complete short middle to #5 G.Bernard caught at ALA32, for 0 yards to the ALA34 (#46 I.Jones; #21 R.Hardy), TURNOVER ON DOWNS", "(12:35) Shotgun #15 F.Mendoza rush left for 4 yards gain to the ALA30 (#10 J.Jefferson), out of bounds PENALTY IND Holding (#65 C.Smith) 10 yards from ALA34 to ALA44. NO PLAY", "(12:05) Shotgun #1 R.Hemby rush right for 21 yards gain to the ALA23 (#18 B.Hubbard), 1ST DOWN", "(11:39) No Huddle-Shotgun #1 R.Hemby rush middle for 2 yards gain to the ALA21 (#90 L.Simmons; #41 N.Hill-Green)", "(10:58) Shotgun #15 F.Mendoza pass incomplete short left to #80 C.Becker thrown to ALA11 broken up by #7 D.Jones", "(10:55) Shotgun #15 F.Mendoza pass complete deep middle to #80 C.Becker caught at ALA00, for 21 yards to the ALA00 TOUCHDOWN, clock 10:49, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)", "(10:44) Shotgun #15 T.Simpson pass complete short left to #2 R.Williams caught at ALA18, for 5 yards to the ALA19 (#22 J.Sharpe)", "(10:04) #15 T.Simpson pass complete short left to #5 G.Bernard caught at ALA29, for 18 yards to the ALA37 (#4 A.Fisher), out of bounds, 1ST DOWN", "(09:27) #15 T.Simpson pass incomplete short right to #5 G.Bernard thrown to ALA34", "(09:25) Shotgun #4 D.Hill rush middle for 0 yards to the ALA37 (#97 M.Landino)", "(08:48) Shotgun #15 T.Simpson rush middle for 1 yard gain to the ALA38 (#17 D.Ndukwe)", "(08:12) #38 B.Doud punt 36 yards to the IND26 #0 J.Brady return 17 yards to the IND43 (#12 Z.Mincey)", "(08:02) Shotgun #15 F.Mendoza sacked for loss of 9 yards to the IND34 (#42 Y.Pierre)", "(07:24) Shotgun #8 K.Black rush middle for 7 yards gain to the IND41 (#12 Z.Mincey)", "(06:56) Shotgun #15 F.Mendoza pass incomplete short middle to #37 R.Nowakowski thrown to ALA43 broken up by #5 D.Lee Jr.", "(06:48) #44 M.McCarthy punt 44 yards to the ALA15 fair catch by #7 C.Adams at ALA15", "(06:42) Shotgun #15 T.Simpson pass complete short right to #80 J.Cuevas caught at ALA21, for 8 yards to the ALA23 (#5 D.Ponds)", "(06:17) No Huddle-Shotgun #15 T.Simpson pass complete short middle to #4 D.Hill caught at ALA27, for 5 yards to the ALA28 (#21 R.Hardy), 1ST DOWN", "(05:42) No Huddle-Shotgun #4 D.Hill rush left for 5 yards gain to the ALA33 (#12 D.Boykin)", "(05:16) No Huddle-Shotgun #15 T.Simpson pass complete short left to #2 R.Williams caught at ALA46, for 13 yards to the ALA46 (#5 D.Ponds), 1ST DOWN", "(04:48) No Huddle-Shotgun #15 T.Simpson pass complete short left to #4 D.Hill caught at ALA46, for 3 yards to the ALA49 (#12 D.Boykin), out of bounds", "(04:05) #28 K.Riley rush right for 0 yards to the ALA49 (#91 D.Ratcliff)", "(03:22) Shotgun #15 T.Simpson rush left for 9 yards gain to the IND42 fumbled by #15 T.Simpson at IND42 forced by #5 D.Ponds recovered by IND #46 I.Jones at IND42, End Of Play", "(03:07) Shotgun #1 R.Hemby rush middle for 4 yards gain to the IND46 (#16 R.Morgan)", "(02:34) Shotgun #15 F.Mendoza rush right for 3 yards gain to the IND49 (#3 K.Sabb)", "(02:00) Shotgun #15 F.Mendoza rush middle for 7 yards gain to the ALA44 (#1 D.Jackson), 1ST DOWN", "(01:28) Shotgun #1 R.Hemby rush left for 8 yards gain to the ALA36 (#1 D.Jackson), out of bounds", "(01:22) Shotgun #1 R.Hemby rush middle for 3 yards gain to the ALA33 (#18 B.Hubbard), 1ST DOWN. The previous play is under automatic review - \"First down\". CALL OVERTURNED. (Original Play: (01:22) Shotgun #1 R.Hemby rush middle for 1 yard gain to the ALA35 (#18 B.Hubbard))", "(01:12) Shotgun #1 R.Hemby rush left for 7 yards gain to the ALA26 (#18 B.Hubbard)", "(01:07) Shotgun #15 F.Mendoza pass complete short right to #8 K.Black caught at ALA22, for 11 yards to the ALA15 (#18 B.Hubbard), 1ST DOWN", "(00:52) Shotgun #15 F.Mendoza pass complete short left to #37 R.Nowakowski caught at ALA10, for 5 yards to the ALA10, out of bounds at ALA10", "(00:50) Shotgun #8 K.Black rush middle for 5 yards gain to the ALA05 (#5 D.Lee Jr.), 1ST DOWN", "(00:25) Shotgun #8 K.Black rush middle for 4 yards gain to the ALA01 (#90 L.Simmons)", "(00:20) #15 F.Mendoza pass complete short left to #3 O.Cooper Jr. caught at ALA00, for 1 yard to the ALA00 TOUCHDOWN, clock 00:17 Timeout Indiana, clock 00:21 #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)", "(00:15) Kneel down by #15 T.Simpson at ALA24 for loss of 1 yard", "End of 2nd quarter.", "(15:00) Shotgun #15 T.Simpson pass complete short right to #2 R.Williams caught at ALA20, for 2 yards loss to the ALA23 (#12 D.Boykin)", "(14:20) Shotgun #15 T.Simpson pass incomplete short middle to #80 J.Cuevas thrown to ALA23 broken up by #97 M.Landino", "(14:17) Shotgun #15 T.Simpson pass complete short left to #80 J.Cuevas caught at ALA25, for 5 yards to the ALA28 (#22 J.Sharpe)", "(13:34) #38 B.Doud punt 50 yards to the IND22 #0 J.Brady return for loss of 1 yard to the IND21 (#17 L.Brooks)", "(13:26) Shotgun #1 R.Hemby rush left for 4 yards gain to the IND25 (#10 J.Jefferson), out of bounds", "(12:51) Shotgun #1 R.Hemby rush middle for 3 yards gain to the IND28 (#0 D.Lawson)", "(12:15) Shotgun #15 F.Mendoza rush middle for 8 yards gain to the IND36 (#0 D.Lawson), 1ST DOWN", "(11:40) Shotgun #8 K.Black rush left for 5 yards gain to the IND41 (#42 Y.Pierre)", "(11:09) Shotgun #15 F.Mendoza rush right for 12 yards gain to the ALA47 (#2 Z.Brown), out of bounds, 1ST DOWN", "(10:28) Shotgun #15 F.Mendoza pass complete short left to #3 O.Cooper Jr. caught at IND49, for 6 yards to the ALA41 (#16 R.Morgan; #22 L.Overton)", "(09:49) Shotgun #8 K.Black rush middle for 8 yards gain to the ALA33 (#22 L.Overton), 1ST DOWN", "(09:11) Shotgun #1 R.Hemby rush left for 1 yard gain to the ALA32 (#31 K.Keeley)", "(08:33) Shotgun #15 F.Mendoza rush middle for 8 yards gain to the ALA24 (#41 N.Hill-Green)", "(07:52) Shotgun #15 F.Mendoza pass complete deep left to #13 E.Sarratt caught at ALA00, for 24 yards to the ALA00 TOUCHDOWN, clock 07:46, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)", "(07:46) Shotgun #10 A.Mack pass complete short left to #26 J.Miller caught at ALA20, for 1 yard to the ALA26 (#17 D.Ndukwe), out of bounds", "(07:09) Shotgun #10 A.Mack rush right for 13 yards gain to the ALA39 (#4 A.Fisher), out of bounds, 1ST DOWN", "(06:32) Shotgun #4 D.Hill rush middle for 2 yards gain to the ALA41 (#46 I.Jones; #4 A.Fisher)", "(05:57) No Huddle-Shotgun #10 A.Mack pass complete deep right to #5 G.Bernard caught at IND36, for 34 yards to the IND25, out of bounds at IND25, 1ST DOWN", "(05:13) Shotgun #10 A.Mack pass complete short right to #80 J.Cuevas caught at IND09, for 16 yards to the IND09, End Of Play, 1ST DOWN", "(04:38) Shotgun #10 A.Mack rush left for 4 yards gain to the IND05 (#12 D.Boykin)", "(03:53) Shotgun #10 A.Mack pass complete short right to #4 D.Hill caught at IND10, for 5 yards loss to the IND10, End Of Play", "(02:50) Shotgun #10 A.Mack pass incomplete short right to #17 L.Brooks thrown to IND03 QB hurried by #21 R.Hardy", "(02:45) #31 C.Talty field goal attempt from 28 yards GOOD (H: #38 B.Doud, LS: #44 A.Rozier), clock 02:44", "(02:42) Shotgun #8 K.Black rush middle for 0 yards to the IND25 (#22 L.Overton)", "(02:05) Shotgun #8 K.Black rush left for 2 yards gain to the IND27 (#13 I.Taylor)", "(01:22) Shotgun #15 F.Mendoza pass complete short left to #37 R.Nowakowski caught at IND31, for 31 yards to the ALA42 (#2 Z.Brown), out of bounds, 1ST DOWN", "(00:37) Shotgun #8 K.Black rush middle for 15 yards gain to the ALA27 (#18 B.Hubbard), 1ST DOWN", "End of 3rd quarter.", "(15:00) Shotgun #8 K.Black rush middle for 2 yards gain to the ALA25 (#96 T.Keenan III)", "(14:27) Shotgun #8 K.Black rush right for 25 yards gain to the ALA00 TOUCHDOWN, clock 14:21, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)", "(14:21) Shotgun #10 A.Mack pass incomplete short right thrown to ALA42 QB hurried by #46 I.Jones", "(14:11) Shotgun #10 A.Mack sacked for loss of 10 yards to the ALA15 (#6 M.Kamara)", "(13:30) Shotgun #10 A.Mack pass incomplete deep right thrown to ALA36", "(13:27) #38 B.Doud punt 48 yards to the IND37", "(13:17) Shotgun #1 R.Hemby rush middle for 2 yards loss to the IND35 (#41 N.Hill-Green)", "(12:42) Shotgun #1 R.Hemby rush middle for 4 yards gain to the IND39 (#10 J.Jefferson)", "(12:03) Shotgun #15 F.Mendoza pass complete deep right to #3 O.Cooper Jr. caught at ALA33, for 38 yards to the ALA23 (#7 D.Jones), 1ST DOWN", "(11:19) Shotgun #1 R.Hemby rush right for 5 yards gain to the ALA18 (#22 L.Overton)", "(10:39) Shotgun #1 R.Hemby rush middle for 18 yards gain to the ALA00 TOUCHDOWN, clock 10:33, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)", "(10:32) Shotgun #10 A.Mack pass complete short right to #1 I.Horton caught at ALA35, for 10 yards to the ALA35, End Of Play, 1ST DOWN", "(10:08) No Huddle-Shotgun #10 A.Mack pass complete short right to #1 I.Horton caught at ALA39, for 6 yards to the ALA41 (#21 R.Hardy), out of bounds", "(09:28) Shotgun #10 A.Mack pass incomplete short right to #28 K.Riley thrown to ALA41 broken up by #95 T.Tucker", "(09:22) Shotgun #10 A.Mack pass complete short left to #5 G.Bernard caught at ALA49, for 8 yards to the ALA49, out of bounds at ALA49, 1ST DOWN", "(08:49) No Huddle-Shotgun #10 A.Mack pass complete short right to #4 D.Hill caught at ALA44, for 1 yard to the ALA50 (#12 D.Boykin; #4 A.Fisher), out of bounds", "(08:03) Shotgun #10 A.Mack sacked for loss of 8 yards to the ALA42 (#12 D.Boykin)", "(07:25) Shotgun #10 A.Mack pass complete short left to #2 R.Williams caught at ALA35, for 26 yards to the IND32 (#0 H.Wheeler), 1ST DOWN", "(06:48) Shotgun #10 A.Mack pass complete short right to #2 R.Williams caught at IND37, for 7 yards to the IND25 (#1 A.Ferrell), out of bounds", "(06:26) Shotgun #10 A.Mack pass incomplete short right to #28 K.Riley thrown to IND26 QB hurried by #21 R.Hardy", "(06:23) No Huddle-Shotgun #10 A.Mack pass complete short right to #4 D.Hill caught at IND31, for 1 yard loss to the IND26 (#21 R.Hardy)", "(05:48) No Huddle-Shotgun #10 A.Mack sacked for loss of 7 yards to the IND33 (#4 A.Fisher), fumble by #10 A.Mack recovered by ALA #10 A.Mack at IND33, End Of Play, TURNOVER ON DOWNS", "(05:40) Shotgun #28 K.Martin rush middle for 4 yards gain to the IND37 (#8 J.Hill)", "(04:55) Shotgun #28 K.Martin rush middle for 2 yards gain to the IND39 (#22 L.Overton)", "(04:09) Shotgun #16 A.Mendoza rush left for 5 yards gain to the IND44 (#12 Z.Mincey), out of bounds, 1ST DOWN", "(03:26) Shotgun #16 A.Mendoza rush middle for 1 yard gain to the IND45 (#13 I.Taylor)", "(02:45) Shotgun #28 K.Martin rush right for 4 yards gain to the IND49 (#9 C.Calhoun; #12 Z.Mincey), out of bounds", "(02:04) Shotgun #28 K.Martin rush middle for 1 yard gain to the IND50 (#36 Q.Reese)", "PENALTY ALA Offside (#18 B.Hubbard) 5 yards from IND50 to ALA45, 1ST DOWN. NO PLAY", "(02:00) Kneel down by #16 A.Mendoza at ALA47 for loss of 2 yards", "(01:21) Kneel down by #16 A.Mendoza at ALA49 for loss of 2 yards", "(00:41) Kneel down by #16 A.Mendoza at IND49 for loss of 2 yards", "Game ended" ], "segmentColors": [ "rgb(153, 0, 0)", "rgb(159, 12, 17)", "rgb(153, 0, 0)", "rgb(169, 29, 43)", "rgb(161, 15, 22)", "rgb(160, 12, 18)", "rgb(157, 7, 11)", "rgb(165, 22, 33)", "rgb(166, 23, 35)", "rgb(167, 26, 39)", "rgb(165, 21, 32)", "rgb(158, 10, 14)", "rgb(157, 8, 12)", "rgb(156, 5, 8)", "rgb(155, 5, 7)", "rgb(155, 5, 7)", "rgb(154, 3, 4)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)", "rgb(153, 0, 0)" ] }, { "label": "50% Line", "data": [ { "x": 0, "y": 50 }, { "x": 129, "y": 50 } ], "borderColor": "rgba(0,0,0,0.3)", "borderWidth": 1.5, "borderDash": [ 5, 5 ], "backgroundColor": "transparent", "pointRadius": 0, "showLine": true, "fill": false, "tension": 0, "order": 90, "datalabels": { "display": false } }, { "label": "Quarters", "data": [ { "x": 29, "y": 0 }, { "x": 29, "y": 100 }, { "x": 129, "y": 100 }, { "x": 129, "y": 0 }, { "x": 69, "y": 0 }, { "x": 69, "y": 100 }, { "x": 129, "y": 100 }, { "x": 129, "y": 0 }, { "x": 97, "y": 0 }, { "x": 97, "y": 100 }, { "x": 129, "y": 100 }, { "x": 129, "y": 0 } ], "borderColor": "rgba(0,0,0,0.1)", "borderWidth": 1, "pointRadius": 0, "showLine": true, "fill": false, "tension": 0, "order": 100, "datalabels": { "display": false } } ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" } }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'line' === 'line' ? 'win-probability'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'win-probability' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'win-probability'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('line' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('win-probability' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('win-probability'.includes('top-rushers') || 'win-probability'.includes('top-passers') || 'win-probability'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'win-probability' === 'win-probability' ? { display: false } : 'line' === 'line' ? { position: 'top', align: 'start', labels: 'win-probability'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'win-probability' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('win-probability'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'line', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767317416809-s7qitf381').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
.cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .chart-content { height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767317427678-teo62qwvr .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767317427678_teo62qwvr() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767317427678-teo62qwvr'); const caret = document.getElementById('caret_cfb-chart-1767317427678-teo62qwvr'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767317427678-teo62qwvr'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767317427678-teo62qwvr'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "labels": [ "Alabama", "Indiana" ], "datasets": [ { "label": "Explosiveness Rate (XR)", "data": [ 0.08333333333333333, 0.13636363636363635 ], "backgroundColor": [ "rgba(101, 0, 20, 0.8)", "rgba(102, 0, 0, 0.8)" ], "stack": "SRXR", "datalabels": { "display": false } }, { "label": "Success Rate (SR)", "data": [ 0.3541666666666667, 0.5151515151515151 ], "backgroundColor": [ "rgba(175, 40, 60, 0.8)", "rgba(153, 0, 0, 0.8)" ], "stack": "SRXR", "datalabels": { "display": true }, "playCountData": [ 48, 66 ] }, { "type": "line", "data": [ 0.42, 0.42 ], "label": "NCAA Avg SR", "borderColor": "#757575", "borderWidth": 2, "borderDash": [ 3, 3 ], "pointRadius": 0, "datalabels": { "display": false } }, { "type": "line", "data": [ null, null ], "label": "# Plays", "backgroundColor": "rgba(0, 0, 0, 0)", "borderColor": "rgba(0, 0, 0, 0)", "borderWidth": 0, "pointRadius": 0, "showLine": false, "fill": false, "datalabels": { "display": false } } ], "teamColors": { "success": "rgba(175, 40, 60, 0.8)", "explosive": "rgba(101, 0, 20, 0.8)", "light": "rgba(245, 229, 233, 0.8)" }, "opponentColors": { "success": "rgba(153, 0, 0, 0.8)", "explosive": "rgba(102, 0, 0, 0.8)", "light": "rgba(255, 230, 230, 0.8)" }, "teamPlayCount": 48, "opponentPlayCount": 66, "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" } }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'bar' === 'line' ? 'overall-team-performance'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'overall-team-performance' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'overall-team-performance'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('bar' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('overall-team-performance' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('overall-team-performance'.includes('top-rushers') || 'overall-team-performance'.includes('top-passers') || 'overall-team-performance'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'overall-team-performance' === 'win-probability' ? { display: false } : 'bar' === 'line' ? { position: 'top', align: 'start', labels: 'overall-team-performance'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'overall-team-performance' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('overall-team-performance'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'bar', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767317427678-teo62qwvr').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
.cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .chart-content { height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767317434020-d88cz7q9x .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767317434020_d88cz7q9x() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767317434020-d88cz7q9x'); const caret = document.getElementById('caret_cfb-chart-1767317434020-d88cz7q9x'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767317434020-d88cz7q9x'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767317434020-d88cz7q9x'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "datasets": [ { "label": "NCAA Avg SR", "data": [ { "x": 1, "y": 0 }, { "x": 1, "y": 0.42 }, { "x": 114, "y": 0.42 }, { "x": 114, "y": 0 } ], "backgroundColor": "rgba(0,0,0,0.03)", "borderColor": "transparent", "pointRadius": 0, "fill": true, "tension": 0, "showLine": true, "datalabels": { "display": false } }, { "data": [ { "x": 4, "y": 0, "text": "T.Simpson pass incomplete short left to #80 J.Cuevas thrown to ALA45 QB hurried by #97 M.Landino" }, { "x": 5, "y": 0, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA44, for 4 yards to the ALA45 (#22 J.Sharpe)" }, { "x": 6, "y": 0, "text": "T.Simpson pass complete short middle to #4 D.Hill caught at ALA50, for 6 yards to the IND49 (#4 A.Fisher), 1ST DOWN" }, { "x": 7, "y": 0, "text": "T.Simpson pass complete short right to #80 J.Cuevas caught at IND44, for 6 yards to the IND43 (#21 R.Hardy)" }, { "x": 8, "y": 0, "text": "D.Hill rush left for 6 yards gain to the IND37 (#7 L.Moore), 1ST DOWN" }, { "x": 9, "y": 0, "text": "D.Hill rush right for 0 yards to the IND37 (#7 L.Moore; #21 R.Hardy)" }, { "x": 10, "y": 0, "text": "T.Simpson pass complete short left to #4 D.Hill caught at IND43, for 4 yards loss to the IND41 (#12 D.Boykin)" }, { "x": 11, "y": 0, "text": "T.Simpson pass incomplete deep left to #2 R.Williams thrown to IND06 broken up by #7 L.Moore QB hurried by #2 B.Baldwin Jr." }, { "x": 27, "y": 0, "text": "K.Riley rush left for 0 yards to the ALA25 (#46 I.Jones)" }, { "x": 28, "y": 0, "text": "K.Riley rush middle for 2 yards gain to the ALA27 (#46 I.Jones; #0 H.Wheeler)" }, { "x": 29, "y": 0, "text": "T.Simpson rush right for 7 yards gain to the ALA34 (#4 A.Fisher)" }, { "x": 30, "y": 0, "text": "D.Hill pass complete short middle to #5 G.Bernard caught at ALA32, for 0 yards to the ALA34 (#46 I.Jones; #21 R.Hardy), TURNOVER ON DOWNS" }, { "x": 35, "y": 0, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA18, for 5 yards to the ALA19 (#22 J.Sharpe)" }, { "x": 36, "y": 0.07142857142857142, "text": "T.Simpson pass complete short left to #5 G.Bernard caught at ALA29, for 18 yards to the ALA37 (#4 A.Fisher), out of bounds, 1ST DOWN" }, { "x": 37, "y": 0.06666666666666667, "text": "T.Simpson pass incomplete short right to #5 G.Bernard thrown to ALA34" }, { "x": 38, "y": 0.0625, "text": "D.Hill rush middle for 0 yards to the ALA37 (#97 M.Landino)" }, { "x": 39, "y": 0.058823529411764705, "text": "T.Simpson rush middle for 1 yard gain to the ALA38 (#17 D.Ndukwe)" }, { "x": 43, "y": 0.05555555555555555, "text": "T.Simpson pass complete short right to #80 J.Cuevas caught at ALA21, for 8 yards to the ALA23 (#5 D.Ponds)" }, { "x": 44, "y": 0.05263157894736842, "text": "T.Simpson pass complete short middle to #4 D.Hill caught at ALA27, for 5 yards to the ALA28 (#21 R.Hardy), 1ST DOWN" }, { "x": 45, "y": 0.05, "text": "D.Hill rush left for 5 yards gain to the ALA33 (#12 D.Boykin)" }, { "x": 46, "y": 0.047619047619047616, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA46, for 13 yards to the ALA46 (#5 D.Ponds), 1ST DOWN" }, { "x": 47, "y": 0.045454545454545456, "text": "T.Simpson pass complete short left to #4 D.Hill caught at ALA46, for 3 yards to the ALA49 (#12 D.Boykin), out of bounds" }, { "x": 48, "y": 0.043478260869565216, "text": "K.Riley rush right for 0 yards to the ALA49 (#91 D.Ratcliff)" }, { "x": 60, "y": 0.041666666666666664, "text": "T.Simpson at ALA24 for loss of 1 yard" }, { "x": 61, "y": 0.04, "text": "T.Simpson pass complete short right to #2 R.Williams caught at ALA20, for 2 yards loss to the ALA23 (#12 D.Boykin)" }, { "x": 62, "y": 0.038461538461538464, "text": "T.Simpson pass incomplete short middle to #80 J.Cuevas thrown to ALA23 broken up by #97 M.Landino" }, { "x": 63, "y": 0.037037037037037035, "text": "T.Simpson pass complete short left to #80 J.Cuevas caught at ALA25, for 5 yards to the ALA28 (#22 J.Sharpe)" }, { "x": 74, "y": 0.03571428571428571, "text": "A.Mack pass complete short left to #26 J.Miller caught at ALA20, for 1 yard to the ALA26 (#17 D.Ndukwe), out of bounds" }, { "x": 75, "y": 0.034482758620689655, "text": "A.Mack rush right for 13 yards gain to the ALA39 (#4 A.Fisher), out of bounds, 1ST DOWN" }, { "x": 76, "y": 0.03333333333333333, "text": "D.Hill rush middle for 2 yards gain to the ALA41 (#46 I.Jones; #4 A.Fisher)" }, { "x": 77, "y": 0.06451612903225806, "text": "A.Mack pass complete deep right to #5 G.Bernard caught at IND36, for 34 yards to the IND25, out of bounds at IND25, 1ST DOWN" }, { "x": 78, "y": 0.09375, "text": "A.Mack pass complete short right to #80 J.Cuevas caught at IND09, for 16 yards to the IND09, End Of Play, 1ST DOWN" }, { "x": 79, "y": 0.09090909090909091, "text": "A.Mack rush left for 4 yards gain to the IND05 (#12 D.Boykin)" }, { "x": 80, "y": 0.08823529411764706, "text": "A.Mack pass complete short right to #4 D.Hill caught at IND10, for 5 yards loss to the IND10, End Of Play" }, { "x": 81, "y": 0.08571428571428572, "text": "A.Mack pass incomplete short right to #17 L.Brooks thrown to IND03 QB hurried by #21 R.Hardy" }, { "x": 88, "y": 0.08333333333333333, "text": "A.Mack pass incomplete short right thrown to ALA42 QB hurried by #46 I.Jones" }, { "x": 89, "y": 0.08108108108108109, "text": "A.Mack sacked for loss of 10 yards to the ALA15 (#6 M.Kamara)" }, { "x": 90, "y": 0.07894736842105263, "text": "A.Mack pass incomplete deep right thrown to ALA36" }, { "x": 96, "y": 0.07692307692307693, "text": "A.Mack pass complete short right to #1 I.Horton caught at ALA35, for 10 yards to the ALA35, End Of Play, 1ST DOWN" }, { "x": 97, "y": 0.075, "text": "A.Mack pass complete short right to #1 I.Horton caught at ALA39, for 6 yards to the ALA41 (#21 R.Hardy), out of bounds" }, { "x": 98, "y": 0.07317073170731707, "text": "A.Mack pass incomplete short right to #28 K.Riley thrown to ALA41 broken up by #95 T.Tucker" }, { "x": 99, "y": 0.07142857142857142, "text": "A.Mack pass complete short left to #5 G.Bernard caught at ALA49, for 8 yards to the ALA49, out of bounds at ALA49, 1ST DOWN" }, { "x": 100, "y": 0.06976744186046512, "text": "A.Mack pass complete short right to #4 D.Hill caught at ALA44, for 1 yard to the ALA50 (#12 D.Boykin; #4 A.Fisher), out of bounds" }, { "x": 101, "y": 0.06818181818181818, "text": "A.Mack sacked for loss of 8 yards to the ALA42 (#12 D.Boykin)" }, { "x": 102, "y": 0.08888888888888889, "text": "A.Mack pass complete short left to #2 R.Williams caught at ALA35, for 26 yards to the IND32 (#0 H.Wheeler), 1ST DOWN" }, { "x": 103, "y": 0.08695652173913043, "text": "A.Mack pass complete short right to #2 R.Williams caught at IND37, for 7 yards to the IND25 (#1 A.Ferrell), out of bounds" }, { "x": 104, "y": 0.0851063829787234, "text": "A.Mack pass incomplete short right to #28 K.Riley thrown to IND26 QB hurried by #21 R.Hardy" }, { "x": 105, "y": 0.08333333333333333, "text": "A.Mack pass complete short right to #4 D.Hill caught at IND31, for 1 yard loss to the IND26 (#21 R.Hardy)" } ], "label": "Alabama XR", "borderColor": "rgba(101, 0, 20, 0.8)", "borderWidth": 2.2, "fill": false }, { "data": [ { "x": 4, "y": 0, "text": "T.Simpson pass incomplete short left to #80 J.Cuevas thrown to ALA45 QB hurried by #97 M.Landino" }, { "x": 5, "y": 0, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA44, for 4 yards to the ALA45 (#22 J.Sharpe)" }, { "x": 6, "y": 0.3333333333333333, "text": "T.Simpson pass complete short middle to #4 D.Hill caught at ALA50, for 6 yards to the IND49 (#4 A.Fisher), 1ST DOWN" }, { "x": 7, "y": 0.5, "text": "T.Simpson pass complete short right to #80 J.Cuevas caught at IND44, for 6 yards to the IND43 (#21 R.Hardy)" }, { "x": 8, "y": 0.6, "text": "D.Hill rush left for 6 yards gain to the IND37 (#7 L.Moore), 1ST DOWN" }, { "x": 9, "y": 0.5, "text": "D.Hill rush right for 0 yards to the IND37 (#7 L.Moore; #21 R.Hardy)" }, { "x": 10, "y": 0.42857142857142855, "text": "T.Simpson pass complete short left to #4 D.Hill caught at IND43, for 4 yards loss to the IND41 (#12 D.Boykin)" }, { "x": 11, "y": 0.375, "text": "T.Simpson pass incomplete deep left to #2 R.Williams thrown to IND06 broken up by #7 L.Moore QB hurried by #2 B.Baldwin Jr." }, { "x": 27, "y": 0.3333333333333333, "text": "K.Riley rush left for 0 yards to the ALA25 (#46 I.Jones)" }, { "x": 28, "y": 0.3, "text": "K.Riley rush middle for 2 yards gain to the ALA27 (#46 I.Jones; #0 H.Wheeler)" }, { "x": 29, "y": 0.2727272727272727, "text": "T.Simpson rush right for 7 yards gain to the ALA34 (#4 A.Fisher)" }, { "x": 30, "y": 0.25, "text": "D.Hill pass complete short middle to #5 G.Bernard caught at ALA32, for 0 yards to the ALA34 (#46 I.Jones; #21 R.Hardy), TURNOVER ON DOWNS" }, { "x": 35, "y": 0.3076923076923077, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA18, for 5 yards to the ALA19 (#22 J.Sharpe)" }, { "x": 36, "y": 0.35714285714285715, "text": "T.Simpson pass complete short left to #5 G.Bernard caught at ALA29, for 18 yards to the ALA37 (#4 A.Fisher), out of bounds, 1ST DOWN" }, { "x": 37, "y": 0.3333333333333333, "text": "T.Simpson pass incomplete short right to #5 G.Bernard thrown to ALA34" }, { "x": 38, "y": 0.3125, "text": "D.Hill rush middle for 0 yards to the ALA37 (#97 M.Landino)" }, { "x": 39, "y": 0.29411764705882354, "text": "T.Simpson rush middle for 1 yard gain to the ALA38 (#17 D.Ndukwe)" }, { "x": 43, "y": 0.3333333333333333, "text": "T.Simpson pass complete short right to #80 J.Cuevas caught at ALA21, for 8 yards to the ALA23 (#5 D.Ponds)" }, { "x": 44, "y": 0.3684210526315789, "text": "T.Simpson pass complete short middle to #4 D.Hill caught at ALA27, for 5 yards to the ALA28 (#21 R.Hardy), 1ST DOWN" }, { "x": 45, "y": 0.4, "text": "D.Hill rush left for 5 yards gain to the ALA33 (#12 D.Boykin)" }, { "x": 46, "y": 0.42857142857142855, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA46, for 13 yards to the ALA46 (#5 D.Ponds), 1ST DOWN" }, { "x": 47, "y": 0.4090909090909091, "text": "T.Simpson pass complete short left to #4 D.Hill caught at ALA46, for 3 yards to the ALA49 (#12 D.Boykin), out of bounds" }, { "x": 48, "y": 0.391304347826087, "text": "K.Riley rush right for 0 yards to the ALA49 (#91 D.Ratcliff)" }, { "x": 60, "y": 0.375, "text": "T.Simpson at ALA24 for loss of 1 yard" }, { "x": 61, "y": 0.36, "text": "T.Simpson pass complete short right to #2 R.Williams caught at ALA20, for 2 yards loss to the ALA23 (#12 D.Boykin)" }, { "x": 62, "y": 0.34615384615384615, "text": "T.Simpson pass incomplete short middle to #80 J.Cuevas thrown to ALA23 broken up by #97 M.Landino" }, { "x": 63, "y": 0.3333333333333333, "text": "T.Simpson pass complete short left to #80 J.Cuevas caught at ALA25, for 5 yards to the ALA28 (#22 J.Sharpe)" }, { "x": 74, "y": 0.32142857142857145, "text": "A.Mack pass complete short left to #26 J.Miller caught at ALA20, for 1 yard to the ALA26 (#17 D.Ndukwe), out of bounds" }, { "x": 75, "y": 0.3448275862068966, "text": "A.Mack rush right for 13 yards gain to the ALA39 (#4 A.Fisher), out of bounds, 1ST DOWN" }, { "x": 76, "y": 0.3333333333333333, "text": "D.Hill rush middle for 2 yards gain to the ALA41 (#46 I.Jones; #4 A.Fisher)" }, { "x": 77, "y": 0.3548387096774194, "text": "A.Mack pass complete deep right to #5 G.Bernard caught at IND36, for 34 yards to the IND25, out of bounds at IND25, 1ST DOWN" }, { "x": 78, "y": 0.375, "text": "A.Mack pass complete short right to #80 J.Cuevas caught at IND09, for 16 yards to the IND09, End Of Play, 1ST DOWN" }, { "x": 79, "y": 0.36363636363636365, "text": "A.Mack rush left for 4 yards gain to the IND05 (#12 D.Boykin)" }, { "x": 80, "y": 0.35294117647058826, "text": "A.Mack pass complete short right to #4 D.Hill caught at IND10, for 5 yards loss to the IND10, End Of Play" }, { "x": 81, "y": 0.34285714285714286, "text": "A.Mack pass incomplete short right to #17 L.Brooks thrown to IND03 QB hurried by #21 R.Hardy" }, { "x": 88, "y": 0.3333333333333333, "text": "A.Mack pass incomplete short right thrown to ALA42 QB hurried by #46 I.Jones" }, { "x": 89, "y": 0.32432432432432434, "text": "A.Mack sacked for loss of 10 yards to the ALA15 (#6 M.Kamara)" }, { "x": 90, "y": 0.3157894736842105, "text": "A.Mack pass incomplete deep right thrown to ALA36" }, { "x": 96, "y": 0.3333333333333333, "text": "A.Mack pass complete short right to #1 I.Horton caught at ALA35, for 10 yards to the ALA35, End Of Play, 1ST DOWN" }, { "x": 97, "y": 0.35, "text": "A.Mack pass complete short right to #1 I.Horton caught at ALA39, for 6 yards to the ALA41 (#21 R.Hardy), out of bounds" }, { "x": 98, "y": 0.34146341463414637, "text": "A.Mack pass incomplete short right to #28 K.Riley thrown to ALA41 broken up by #95 T.Tucker" }, { "x": 99, "y": 0.35714285714285715, "text": "A.Mack pass complete short left to #5 G.Bernard caught at ALA49, for 8 yards to the ALA49, out of bounds at ALA49, 1ST DOWN" }, { "x": 100, "y": 0.3488372093023256, "text": "A.Mack pass complete short right to #4 D.Hill caught at ALA44, for 1 yard to the ALA50 (#12 D.Boykin; #4 A.Fisher), out of bounds" }, { "x": 101, "y": 0.3409090909090909, "text": "A.Mack sacked for loss of 8 yards to the ALA42 (#12 D.Boykin)" }, { "x": 102, "y": 0.35555555555555557, "text": "A.Mack pass complete short left to #2 R.Williams caught at ALA35, for 26 yards to the IND32 (#0 H.Wheeler), 1ST DOWN" }, { "x": 103, "y": 0.3695652173913043, "text": "A.Mack pass complete short right to #2 R.Williams caught at IND37, for 7 yards to the IND25 (#1 A.Ferrell), out of bounds" }, { "x": 104, "y": 0.3617021276595745, "text": "A.Mack pass incomplete short right to #28 K.Riley thrown to IND26 QB hurried by #21 R.Hardy" }, { "x": 105, "y": 0.3541666666666667, "text": "A.Mack pass complete short right to #4 D.Hill caught at IND31, for 1 yard loss to the IND26 (#21 R.Hardy)" } ], "label": "Alabama SR", "borderColor": "rgba(175, 40, 60, 0.8)", "borderWidth": 2.2, "fill": false }, { "data": [ { "x": 1, "y": 0, "text": "F.Mendoza sacked for loss of 2 yards to the IND23 (#42 Y.Pierre, #0 D.Lawson)" }, { "x": 2, "y": 0, "text": "R.Hemby rush right for 8 yards gain to the IND31 (#10 J.Jefferson)" }, { "x": 3, "y": 0, "text": "F.Mendoza sacked for loss of 11 yards to the IND20 (#18 B.Hubbard)" }, { "x": 12, "y": 0, "text": "K.Black rush middle for 2 yards gain to the IND05 (#90 L.Simmons)" }, { "x": 13, "y": 0, "text": "K.Black rush middle for 6 yards gain to the IND11 (#4 Q.Russaw; #41 N.Hill-Green)" }, { "x": 14, "y": 0, "text": "F.Mendoza pass complete short middle to #13 E.Sarratt caught at IND15, for 7 yards to the IND18 (#2 Z.Brown), 1ST DOWN" }, { "x": 15, "y": 0, "text": "F.Mendoza pass complete short left to #13 E.Sarratt caught at IND25, for 9 yards to the IND27 (#41 N.Hill-Green; #0 D.Lawson)" }, { "x": 16, "y": 0, "text": "F.Mendoza pass complete short right to #13 E.Sarratt caught at IND26, for 0 yards to the IND27 (#2 Z.Brown)" }, { "x": 17, "y": 0, "text": "R.Hemby rush middle for 2 yards gain to the IND29 (#18 B.Hubbard), 1ST DOWN" }, { "x": 18, "y": 0, "text": "R.Hemby rush left for 1 yard gain to the IND30 (#3 K.Sabb; #11 J.Renaud)" }, { "x": 19, "y": 0.09090909090909091, "text": "F.Mendoza pass complete deep right to #80 C.Becker caught at ALA40, for 30 yards to the ALA40 (#2 Z.Brown), out of bounds, 1ST DOWN" }, { "x": 20, "y": 0.08333333333333333, "text": "K.Black rush left for 5 yards gain to the ALA35 (#42 Y.Pierre)" }, { "x": 21, "y": 0.07692307692307693, "text": "K.Black rush middle for 6 yards gain to the ALA29 (#22 L.Overton), 1ST DOWN" }, { "x": 22, "y": 0.07142857142857142, "text": "F.Mendoza pass complete short right to #7 E.Williams Jr. caught at ALA26, for 9 yards to the ALA20 (#2 Z.Brown), out of bounds" }, { "x": 23, "y": 0.06666666666666667, "text": "K.Black rush middle for 7 yards gain to the ALA13 (#3 K.Sabb; #22 L.Overton), 1ST DOWN" }, { "x": 24, "y": 0.0625, "text": "R.Hemby rush middle for 1 yard gain to the ALA12 (#94 E.Hill)" }, { "x": 25, "y": 0.058823529411764705, "text": "F.Mendoza pass complete short middle to #37 R.Nowakowski caught at ALA12, for 0 yards to the ALA12 (#96 T.Keenan III)" }, { "x": 26, "y": 0.05555555555555555, "text": "R.Hemby rush middle for 1 yard loss to the ALA13 (#41 N.Hill-Green; #18 B.Hubbard)" }, { "x": 31, "y": 0.10526315789473684, "text": "R.Hemby rush right for 21 yards gain to the ALA23 (#18 B.Hubbard), 1ST DOWN" }, { "x": 32, "y": 0.1, "text": "R.Hemby rush middle for 2 yards gain to the ALA21 (#90 L.Simmons; #41 N.Hill-Green)" }, { "x": 33, "y": 0.09523809523809523, "text": "F.Mendoza pass incomplete short left to #80 C.Becker thrown to ALA11 broken up by #7 D.Jones" }, { "x": 34, "y": 0.13636363636363635, "text": "F.Mendoza pass complete deep middle to #80 C.Becker caught at ALA00, for 21 yards to the ALA00 TOUCHDOWN, clock 10:49, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 40, "y": 0.13043478260869565, "text": "F.Mendoza sacked for loss of 9 yards to the IND34 (#42 Y.Pierre)" }, { "x": 41, "y": 0.125, "text": "K.Black rush middle for 7 yards gain to the IND41 (#12 Z.Mincey)" }, { "x": 42, "y": 0.12, "text": "F.Mendoza pass incomplete short middle to #37 R.Nowakowski thrown to ALA43 broken up by #5 D.Lee Jr." }, { "x": 49, "y": 0.11538461538461539, "text": "R.Hemby rush middle for 4 yards gain to the IND46 (#16 R.Morgan)" }, { "x": 50, "y": 0.1111111111111111, "text": "F.Mendoza rush right for 3 yards gain to the IND49 (#3 K.Sabb)" }, { "x": 51, "y": 0.10714285714285714, "text": "F.Mendoza rush middle for 7 yards gain to the ALA44 (#1 D.Jackson), 1ST DOWN" }, { "x": 52, "y": 0.10344827586206896, "text": "R.Hemby rush left for 8 yards gain to the ALA36 (#1 D.Jackson), out of bounds" }, { "x": 53, "y": 0.1, "text": "R.Hemby rush middle for 3 yards gain to the ALA33 (#18 B.Hubbard), 1ST DOWN. The previous play is under automatic review - \"First down\". CALL OVERTURNED. (Original Play: (01:22) Shotgun #1 R.Hemby rush middle for 1 yard gain to the ALA35 (#18 B.Hubbard))" }, { "x": 54, "y": 0.0967741935483871, "text": "R.Hemby rush left for 7 yards gain to the ALA26 (#18 B.Hubbard)" }, { "x": 55, "y": 0.09375, "text": "F.Mendoza pass complete short right to #8 K.Black caught at ALA22, for 11 yards to the ALA15 (#18 B.Hubbard), 1ST DOWN" }, { "x": 56, "y": 0.09090909090909091, "text": "F.Mendoza pass complete short left to #37 R.Nowakowski caught at ALA10, for 5 yards to the ALA10, out of bounds at ALA10" }, { "x": 57, "y": 0.08823529411764706, "text": "K.Black rush middle for 5 yards gain to the ALA05 (#5 D.Lee Jr.), 1ST DOWN" }, { "x": 58, "y": 0.08571428571428572, "text": "K.Black rush middle for 4 yards gain to the ALA01 (#90 L.Simmons)" }, { "x": 59, "y": 0.08333333333333333, "text": "F.Mendoza pass complete short left to #3 O.Cooper Jr. caught at ALA00, for 1 yard to the ALA00 TOUCHDOWN, clock 00:17 Timeout Indiana, clock 00:21 #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 64, "y": 0.08108108108108109, "text": "R.Hemby rush left for 4 yards gain to the IND25 (#10 J.Jefferson), out of bounds" }, { "x": 65, "y": 0.07894736842105263, "text": "R.Hemby rush middle for 3 yards gain to the IND28 (#0 D.Lawson)" }, { "x": 66, "y": 0.07692307692307693, "text": "F.Mendoza rush middle for 8 yards gain to the IND36 (#0 D.Lawson), 1ST DOWN" }, { "x": 67, "y": 0.075, "text": "K.Black rush left for 5 yards gain to the IND41 (#42 Y.Pierre)" }, { "x": 68, "y": 0.07317073170731707, "text": "F.Mendoza rush right for 12 yards gain to the ALA47 (#2 Z.Brown), out of bounds, 1ST DOWN" }, { "x": 69, "y": 0.07142857142857142, "text": "F.Mendoza pass complete short left to #3 O.Cooper Jr. caught at IND49, for 6 yards to the ALA41 (#16 R.Morgan; #22 L.Overton)" }, { "x": 70, "y": 0.06976744186046512, "text": "K.Black rush middle for 8 yards gain to the ALA33 (#22 L.Overton), 1ST DOWN" }, { "x": 71, "y": 0.06818181818181818, "text": "R.Hemby rush left for 1 yard gain to the ALA32 (#31 K.Keeley)" }, { "x": 72, "y": 0.06666666666666667, "text": "F.Mendoza rush middle for 8 yards gain to the ALA24 (#41 N.Hill-Green)" }, { "x": 73, "y": 0.08695652173913043, "text": "F.Mendoza pass complete deep left to #13 E.Sarratt caught at ALA00, for 24 yards to the ALA00 TOUCHDOWN, clock 07:46, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 82, "y": 0.0851063829787234, "text": "K.Black rush middle for 0 yards to the IND25 (#22 L.Overton)" }, { "x": 83, "y": 0.08333333333333333, "text": "K.Black rush left for 2 yards gain to the IND27 (#13 I.Taylor)" }, { "x": 84, "y": 0.10204081632653061, "text": "F.Mendoza pass complete short left to #37 R.Nowakowski caught at IND31, for 31 yards to the ALA42 (#2 Z.Brown), out of bounds, 1ST DOWN" }, { "x": 85, "y": 0.12, "text": "K.Black rush middle for 15 yards gain to the ALA27 (#18 B.Hubbard), 1ST DOWN" }, { "x": 86, "y": 0.11764705882352941, "text": "K.Black rush middle for 2 yards gain to the ALA25 (#96 T.Keenan III)" }, { "x": 87, "y": 0.1346153846153846, "text": "K.Black rush right for 25 yards gain to the ALA00 TOUCHDOWN, clock 14:21, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 91, "y": 0.1320754716981132, "text": "R.Hemby rush middle for 2 yards loss to the IND35 (#41 N.Hill-Green)" }, { "x": 92, "y": 0.12962962962962962, "text": "R.Hemby rush middle for 4 yards gain to the IND39 (#10 J.Jefferson)" }, { "x": 93, "y": 0.14545454545454545, "text": "F.Mendoza pass complete deep right to #3 O.Cooper Jr. caught at ALA33, for 38 yards to the ALA23 (#7 D.Jones), 1ST DOWN" }, { "x": 94, "y": 0.14285714285714285, "text": "R.Hemby rush right for 5 yards gain to the ALA18 (#22 L.Overton)" }, { "x": 95, "y": 0.15789473684210525, "text": "R.Hemby rush middle for 18 yards gain to the ALA00 TOUCHDOWN, clock 10:33, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 106, "y": 0.15517241379310345, "text": "K.Martin rush middle for 4 yards gain to the IND37 (#8 J.Hill)" }, { "x": 107, "y": 0.15254237288135594, "text": "K.Martin rush middle for 2 yards gain to the IND39 (#22 L.Overton)" }, { "x": 108, "y": 0.15, "text": "A.Mendoza rush left for 5 yards gain to the IND44 (#12 Z.Mincey), out of bounds, 1ST DOWN" }, { "x": 109, "y": 0.14754098360655737, "text": "A.Mendoza rush middle for 1 yard gain to the IND45 (#13 I.Taylor)" }, { "x": 110, "y": 0.14516129032258066, "text": "K.Martin rush right for 4 yards gain to the IND49 (#9 C.Calhoun; #12 Z.Mincey), out of bounds" }, { "x": 111, "y": 0.14285714285714285, "text": "K.Martin rush middle for 1 yard gain to the IND50 (#36 Q.Reese)" }, { "x": 112, "y": 0.140625, "text": "A.Mendoza at ALA47 for loss of 2 yards" }, { "x": 113, "y": 0.13846153846153847, "text": "A.Mendoza at ALA49 for loss of 2 yards" }, { "x": 114, "y": 0.13636363636363635, "text": "A.Mendoza at IND49 for loss of 2 yards" } ], "label": "Indiana XR", "borderColor": "rgba(102, 0, 0, 0.8)", "borderWidth": 2.2, "borderDash": [ 4, 4 ], "fill": false }, { "data": [ { "x": 1, "y": 0, "text": "F.Mendoza sacked for loss of 2 yards to the IND23 (#42 Y.Pierre, #0 D.Lawson)" }, { "x": 2, "y": 0, "text": "R.Hemby rush right for 8 yards gain to the IND31 (#10 J.Jefferson)" }, { "x": 3, "y": 0, "text": "F.Mendoza sacked for loss of 11 yards to the IND20 (#18 B.Hubbard)" }, { "x": 12, "y": 0, "text": "K.Black rush middle for 2 yards gain to the IND05 (#90 L.Simmons)" }, { "x": 13, "y": 0.2, "text": "K.Black rush middle for 6 yards gain to the IND11 (#4 Q.Russaw; #41 N.Hill-Green)" }, { "x": 14, "y": 0.3333333333333333, "text": "F.Mendoza pass complete short middle to #13 E.Sarratt caught at IND15, for 7 yards to the IND18 (#2 Z.Brown), 1ST DOWN" }, { "x": 15, "y": 0.42857142857142855, "text": "F.Mendoza pass complete short left to #13 E.Sarratt caught at IND25, for 9 yards to the IND27 (#41 N.Hill-Green; #0 D.Lawson)" }, { "x": 16, "y": 0.375, "text": "F.Mendoza pass complete short right to #13 E.Sarratt caught at IND26, for 0 yards to the IND27 (#2 Z.Brown)" }, { "x": 17, "y": 0.4444444444444444, "text": "R.Hemby rush middle for 2 yards gain to the IND29 (#18 B.Hubbard), 1ST DOWN" }, { "x": 18, "y": 0.4, "text": "R.Hemby rush left for 1 yard gain to the IND30 (#3 K.Sabb; #11 J.Renaud)" }, { "x": 19, "y": 0.45454545454545453, "text": "F.Mendoza pass complete deep right to #80 C.Becker caught at ALA40, for 30 yards to the ALA40 (#2 Z.Brown), out of bounds, 1ST DOWN" }, { "x": 20, "y": 0.5, "text": "K.Black rush left for 5 yards gain to the ALA35 (#42 Y.Pierre)" }, { "x": 21, "y": 0.5384615384615384, "text": "K.Black rush middle for 6 yards gain to the ALA29 (#22 L.Overton), 1ST DOWN" }, { "x": 22, "y": 0.5714285714285714, "text": "F.Mendoza pass complete short right to #7 E.Williams Jr. caught at ALA26, for 9 yards to the ALA20 (#2 Z.Brown), out of bounds" }, { "x": 23, "y": 0.6, "text": "K.Black rush middle for 7 yards gain to the ALA13 (#3 K.Sabb; #22 L.Overton), 1ST DOWN" }, { "x": 24, "y": 0.5625, "text": "R.Hemby rush middle for 1 yard gain to the ALA12 (#94 E.Hill)" }, { "x": 25, "y": 0.5294117647058824, "text": "F.Mendoza pass complete short middle to #37 R.Nowakowski caught at ALA12, for 0 yards to the ALA12 (#96 T.Keenan III)" }, { "x": 26, "y": 0.5, "text": "R.Hemby rush middle for 1 yard loss to the ALA13 (#41 N.Hill-Green; #18 B.Hubbard)" }, { "x": 31, "y": 0.5263157894736842, "text": "R.Hemby rush right for 21 yards gain to the ALA23 (#18 B.Hubbard), 1ST DOWN" }, { "x": 32, "y": 0.5, "text": "R.Hemby rush middle for 2 yards gain to the ALA21 (#90 L.Simmons; #41 N.Hill-Green)" }, { "x": 33, "y": 0.47619047619047616, "text": "F.Mendoza pass incomplete short left to #80 C.Becker thrown to ALA11 broken up by #7 D.Jones" }, { "x": 34, "y": 0.5, "text": "F.Mendoza pass complete deep middle to #80 C.Becker caught at ALA00, for 21 yards to the ALA00 TOUCHDOWN, clock 10:49, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 40, "y": 0.4782608695652174, "text": "F.Mendoza sacked for loss of 9 yards to the IND34 (#42 Y.Pierre)" }, { "x": 41, "y": 0.4583333333333333, "text": "K.Black rush middle for 7 yards gain to the IND41 (#12 Z.Mincey)" }, { "x": 42, "y": 0.44, "text": "F.Mendoza pass incomplete short middle to #37 R.Nowakowski thrown to ALA43 broken up by #5 D.Lee Jr." }, { "x": 49, "y": 0.4230769230769231, "text": "R.Hemby rush middle for 4 yards gain to the IND46 (#16 R.Morgan)" }, { "x": 50, "y": 0.4074074074074074, "text": "F.Mendoza rush right for 3 yards gain to the IND49 (#3 K.Sabb)" }, { "x": 51, "y": 0.42857142857142855, "text": "F.Mendoza rush middle for 7 yards gain to the ALA44 (#1 D.Jackson), 1ST DOWN" }, { "x": 52, "y": 0.4482758620689655, "text": "R.Hemby rush left for 8 yards gain to the ALA36 (#1 D.Jackson), out of bounds" }, { "x": 53, "y": 0.4666666666666667, "text": "R.Hemby rush middle for 3 yards gain to the ALA33 (#18 B.Hubbard), 1ST DOWN. The previous play is under automatic review - \"First down\". CALL OVERTURNED. (Original Play: (01:22) Shotgun #1 R.Hemby rush middle for 1 yard gain to the ALA35 (#18 B.Hubbard))" }, { "x": 54, "y": 0.4838709677419355, "text": "R.Hemby rush left for 7 yards gain to the ALA26 (#18 B.Hubbard)" }, { "x": 55, "y": 0.5, "text": "F.Mendoza pass complete short right to #8 K.Black caught at ALA22, for 11 yards to the ALA15 (#18 B.Hubbard), 1ST DOWN" }, { "x": 56, "y": 0.5151515151515151, "text": "F.Mendoza pass complete short left to #37 R.Nowakowski caught at ALA10, for 5 yards to the ALA10, out of bounds at ALA10" }, { "x": 57, "y": 0.5294117647058824, "text": "K.Black rush middle for 5 yards gain to the ALA05 (#5 D.Lee Jr.), 1ST DOWN" }, { "x": 58, "y": 0.5428571428571428, "text": "K.Black rush middle for 4 yards gain to the ALA01 (#90 L.Simmons)" }, { "x": 59, "y": 0.5555555555555556, "text": "F.Mendoza pass complete short left to #3 O.Cooper Jr. caught at ALA00, for 1 yard to the ALA00 TOUCHDOWN, clock 00:17 Timeout Indiana, clock 00:21 #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 64, "y": 0.5405405405405406, "text": "R.Hemby rush left for 4 yards gain to the IND25 (#10 J.Jefferson), out of bounds" }, { "x": 65, "y": 0.5263157894736842, "text": "R.Hemby rush middle for 3 yards gain to the IND28 (#0 D.Lawson)" }, { "x": 66, "y": 0.5384615384615384, "text": "F.Mendoza rush middle for 8 yards gain to the IND36 (#0 D.Lawson), 1ST DOWN" }, { "x": 67, "y": 0.55, "text": "K.Black rush left for 5 yards gain to the IND41 (#42 Y.Pierre)" }, { "x": 68, "y": 0.5609756097560976, "text": "F.Mendoza rush right for 12 yards gain to the ALA47 (#2 Z.Brown), out of bounds, 1ST DOWN" }, { "x": 69, "y": 0.5714285714285714, "text": "F.Mendoza pass complete short left to #3 O.Cooper Jr. caught at IND49, for 6 yards to the ALA41 (#16 R.Morgan; #22 L.Overton)" }, { "x": 70, "y": 0.5813953488372093, "text": "K.Black rush middle for 8 yards gain to the ALA33 (#22 L.Overton), 1ST DOWN" }, { "x": 71, "y": 0.5681818181818182, "text": "R.Hemby rush left for 1 yard gain to the ALA32 (#31 K.Keeley)" }, { "x": 72, "y": 0.5777777777777777, "text": "F.Mendoza rush middle for 8 yards gain to the ALA24 (#41 N.Hill-Green)" }, { "x": 73, "y": 0.5869565217391305, "text": "F.Mendoza pass complete deep left to #13 E.Sarratt caught at ALA00, for 24 yards to the ALA00 TOUCHDOWN, clock 07:46, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 82, "y": 0.574468085106383, "text": "K.Black rush middle for 0 yards to the IND25 (#22 L.Overton)" }, { "x": 83, "y": 0.5625, "text": "K.Black rush left for 2 yards gain to the IND27 (#13 I.Taylor)" }, { "x": 84, "y": 0.5714285714285714, "text": "F.Mendoza pass complete short left to #37 R.Nowakowski caught at IND31, for 31 yards to the ALA42 (#2 Z.Brown), out of bounds, 1ST DOWN" }, { "x": 85, "y": 0.58, "text": "K.Black rush middle for 15 yards gain to the ALA27 (#18 B.Hubbard), 1ST DOWN" }, { "x": 86, "y": 0.5686274509803921, "text": "K.Black rush middle for 2 yards gain to the ALA25 (#96 T.Keenan III)" }, { "x": 87, "y": 0.5769230769230769, "text": "K.Black rush right for 25 yards gain to the ALA00 TOUCHDOWN, clock 14:21, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 91, "y": 0.5660377358490566, "text": "R.Hemby rush middle for 2 yards loss to the IND35 (#41 N.Hill-Green)" }, { "x": 92, "y": 0.5555555555555556, "text": "R.Hemby rush middle for 4 yards gain to the IND39 (#10 J.Jefferson)" }, { "x": 93, "y": 0.5636363636363636, "text": "F.Mendoza pass complete deep right to #3 O.Cooper Jr. caught at ALA33, for 38 yards to the ALA23 (#7 D.Jones), 1ST DOWN" }, { "x": 94, "y": 0.5714285714285714, "text": "R.Hemby rush right for 5 yards gain to the ALA18 (#22 L.Overton)" }, { "x": 95, "y": 0.5789473684210527, "text": "R.Hemby rush middle for 18 yards gain to the ALA00 TOUCHDOWN, clock 10:33, 1ST DOWN #15 N.Radicic kick attempt good (H: #44 M.McCarthy, LS: #47 M.Langston)" }, { "x": 106, "y": 0.5689655172413793, "text": "K.Martin rush middle for 4 yards gain to the IND37 (#8 J.Hill)" }, { "x": 107, "y": 0.559322033898305, "text": "K.Martin rush middle for 2 yards gain to the IND39 (#22 L.Overton)" }, { "x": 108, "y": 0.5666666666666667, "text": "A.Mendoza rush left for 5 yards gain to the IND44 (#12 Z.Mincey), out of bounds, 1ST DOWN" }, { "x": 109, "y": 0.5573770491803278, "text": "A.Mendoza rush middle for 1 yard gain to the IND45 (#13 I.Taylor)" }, { "x": 110, "y": 0.5483870967741935, "text": "K.Martin rush right for 4 yards gain to the IND49 (#9 C.Calhoun; #12 Z.Mincey), out of bounds" }, { "x": 111, "y": 0.5396825396825397, "text": "K.Martin rush middle for 1 yard gain to the IND50 (#36 Q.Reese)" }, { "x": 112, "y": 0.53125, "text": "A.Mendoza at ALA47 for loss of 2 yards" }, { "x": 113, "y": 0.5230769230769231, "text": "A.Mendoza at ALA49 for loss of 2 yards" }, { "x": 114, "y": 0.5151515151515151, "text": "A.Mendoza at IND49 for loss of 2 yards" } ], "label": "Indiana SR", "borderColor": "rgba(153, 0, 0, 0.8)", "borderWidth": 2.2, "borderDash": [ 4, 4 ], "fill": false }, { "label": "Quarters", "data": [ { "x": 1, "y": 0 }, { "x": 1, "y": 1 }, { "x": 114, "y": 1 }, { "x": 114, "y": 0 }, { "x": 27, "y": 0 }, { "x": 27, "y": 1 }, { "x": 114, "y": 1 }, { "x": 114, "y": 0 }, { "x": 61, "y": 0 }, { "x": 61, "y": 1 }, { "x": 114, "y": 1 }, { "x": 114, "y": 0 }, { "x": 86, "y": 0 }, { "x": 86, "y": 1 }, { "x": 114, "y": 1 }, { "x": 114, "y": 0 } ], "borderColor": "rgba(0,0,0,0.1)", "borderWidth": 1, "tension": 0, "fill": false, "pointRadius": 0, "showLine": true, "datalabels": { "display": false } } ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" } }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'line' === 'line' ? 'team-lines'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'team-lines' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'team-lines'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('line' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('team-lines' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('team-lines'.includes('top-rushers') || 'team-lines'.includes('top-passers') || 'team-lines'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'team-lines' === 'win-probability' ? { display: false } : 'line' === 'line' ? { position: 'top', align: 'start', labels: 'team-lines'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'team-lines' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('team-lines'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'line', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767317434020-d88cz7q9x').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
.cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .chart-content { height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767317451099-w23sxvnzx .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767317451099_w23sxvnzx() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767317451099-w23sxvnzx'); const caret = document.getElementById('caret_cfb-chart-1767317451099-w23sxvnzx'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767317451099-w23sxvnzx'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767317451099-w23sxvnzx'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "labels": [ "Rush", "Pass" ], "datasets": [ { "data": [ 0, 0.11428571428571428 ], "stack": "Team", "label": "Alabama XR", "backgroundColor": "rgba(101, 0, 20, 0.8)", "datalabels": { "display": false } }, { "data": [ 0.23076923076923078, 0.4 ], "stack": "Team", "label": "Alabama SR", "backgroundColor": "rgba(175, 40, 60, 0.8)", "datalabels": { "display": true } }, { "data": [ 0.0851063829787234, 0.2631578947368421 ], "stack": "Opponent", "label": "Indiana XR", "backgroundColor": "rgba(102, 0, 0, 0.8)", "datalabels": { "display": false } }, { "data": [ 0.46808510638297873, 0.631578947368421 ], "stack": "Opponent", "label": "Indiana SR", "backgroundColor": "rgba(153, 0, 0, 0.8)", "datalabels": { "display": true } }, { "type": "line", "data": [ 0.42, 0.42 ], "label": "NCAA Avg SR", "borderColor": "#757575", "borderWidth": 2, "borderDash": [ 3, 3 ], "pointRadius": 0, "datalabels": { "display": false } }, { "type": "line", "data": [ null, null ], "label": "# Plays", "backgroundColor": "rgba(0, 0, 0, 0)", "borderColor": "rgba(0, 0, 0, 0)", "borderWidth": 0, "pointRadius": 0, "showLine": false, "fill": false, "datalabels": { "display": false } } ], "teamCounts": [ 13, 35 ], "oppCounts": [ 47, 19 ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" } }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'bar' === 'line' ? 'play-type-bars'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'play-type-bars' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'play-type-bars'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('bar' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('play-type-bars' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('play-type-bars'.includes('top-rushers') || 'play-type-bars'.includes('top-passers') || 'play-type-bars'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'play-type-bars' === 'win-probability' ? { display: false } : 'bar' === 'line' ? { position: 'top', align: 'start', labels: 'play-type-bars'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'play-type-bars' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('play-type-bars'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'bar', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767317451099-w23sxvnzx').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
.cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .chart-content { height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767317461837-0h7fh4uc3 .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767317461837_0h7fh4uc3() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767317461837-0h7fh4uc3'); const caret = document.getElementById('caret_cfb-chart-1767317461837-0h7fh4uc3'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767317461837-0h7fh4uc3'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767317461837-0h7fh4uc3'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "labels": [ "Red Zone", "Other" ], "datasets": [ { "data": [ 0, 0.08888888888888889 ], "stack": "Team", "label": "Alabama XR", "backgroundColor": "rgba(101, 0, 20, 0.8)", "datalabels": { "display": false } }, { "data": [ 0, 0.37777777777777777 ], "stack": "Team", "label": "Alabama SR", "backgroundColor": "rgba(175, 40, 60, 0.8)", "datalabels": { "display": true } }, { "data": [ 0.1111111111111111, 0.14035087719298245 ], "stack": "Opponent", "label": "Indiana XR", "backgroundColor": "rgba(102, 0, 0, 0.8)", "datalabels": { "display": false } }, { "data": [ 0.6666666666666666, 0.49122807017543857 ], "stack": "Opponent", "label": "Indiana SR", "backgroundColor": "rgba(153, 0, 0, 0.8)", "datalabels": { "display": true } }, { "type": "line", "data": [ 0.42, 0.42 ], "label": "NCAA Avg SR", "borderColor": "#757575", "borderWidth": 2, "borderDash": [ 3, 3 ], "pointRadius": 0, "datalabels": { "display": false } }, { "type": "line", "data": [ null, null ], "label": "# Plays", "backgroundColor": "rgba(0, 0, 0, 0)", "borderColor": "rgba(0, 0, 0, 0)", "borderWidth": 0, "pointRadius": 0, "showLine": false, "fill": false, "datalabels": { "display": false } } ], "teamCounts": [ 3, 45 ], "oppCounts": [ 9, 57 ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" } }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'bar' === 'line' ? 'red-zone-bars'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'red-zone-bars' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'red-zone-bars'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('bar' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('red-zone-bars' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('red-zone-bars'.includes('top-rushers') || 'red-zone-bars'.includes('top-passers') || 'red-zone-bars'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'red-zone-bars' === 'win-probability' ? { display: false } : 'bar' === 'line' ? { position: 'top', align: 'start', labels: 'red-zone-bars'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'red-zone-bars' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('red-zone-bars'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'bar', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767317461837-0h7fh4uc3').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
Welp, that was terrible. Things actually started out pretty well, almost as if it was going to be a good game between two top-flight teams. But, Indiana surged at the end of the first quarter, taking a few breaks and some great plays to start building their lead. (Don’t look, but Alabama was still hanging with them, at least on efficiencies, late in that 2nd quarter).
Indiana came out of halftime with something — adjustments, confidence, magical helmets? — and continued their momentum from the last drive in the 1st quarter. And that’s that … every time the Tide showed flashes, something bad would happen, and Indiana would convert a bunch of 3rd-and-longs en route to easy-looking TD’s once they got into the Red Zone.
But, hey, you already know that Alabama got their butts kicked, right? So let’s try to squeeze out even the most spare, tiny silver linings we can. No point in crying charting over spilt milk.
The silver linings
Now, before we get into it … I’m really stretching for some of these. That 2018 title loss to Clemson was bizarre, but this blowout loss was a more conventional 38-to-3 beatdown that leaves fewer surprises in the data.
But there are a few nuggets. Let’s eat.
Box Score – Alabama vs Indiana body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; background: #f8fafc; } .embed-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; max-width: 800px; margin: 0 auto; padding: 0; } .header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .table-wrapper { padding: 0; } table { min-width: 100%; table-layout: fixed; border-collapse: collapse; } .col-stat { width: auto; } .col-team { width: 140px; } thead tr { background-color: #525252; color: white; } th { padding: 12px 16px; text-align: left; font-size: 14px; font-weight: 600; border-bottom: 4px solid #475569; text-align: center; } th.stat-header { text-align: left; } tbody tr { border-bottom: 1px solid #e5e5e5; } .bg-white { background-color: #ffffff; } .bg-neutral-50 { background-color: #fafafa; } .px-4 { padding-left: 1rem; padding-right: 1rem; } .py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; } .text-sm { font-size: 0.875rem; } .font-medium { font-weight: 500; } .font-semibold { font-weight: 600; } .text-neutral-900 { color: #171717; } .text-center { text-align: center; } .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .embed-footer-top { display: flex; justify-content: center; align-items: center; padding: 12px 16px; } .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .embed-footer-link:hover { color: #525252; text-decoration: underline; } @media (max-width: 640px) { .header { padding: 12px 16px; } th, td { padding: 8px 12px; } .title { font-size: 16px; } .embed-footer-top { padding: 8px 12px; } .col-team { width: 80px; } th, td { font-size: 13px; } }
| Alabama |
Indiana |
| Points |
3 |
38 |
| Game Excitement |
3.0 |
3.0 |
| Total yards |
193 |
407 |
| Rush yards |
23 |
215 |
| Rush attempts |
17 |
50 |
| Yards per rush |
1.4 |
4.3 |
| Pass yards |
170 |
192 |
| Pass attempts |
24-33 |
14-16 |
| Yards per pass |
5.2 |
12.0 |
| 1st downs |
11 |
22 |
| 3rd down eff |
3-11 |
9-14 |
| 4th down eff |
0-2 |
0-0 |
| Explosiveness |
1.83 |
1.14 |
| Turnovers |
1 |
0 |
| Tackles |
48 |
31 |
| Sacks |
3 |
3 |
| Penalties-Yds |
1-5 |
1-10 |
| Possession |
25:39 |
34:21 |
Ahem, ok there’s not much here given the massive disparities in points, yardage, and the other important stuff. But there are a few lines to take solace in:
- Alabama’s Explosiveness Index was much higher, at 1.83 vs. the Hoosiers’ 1.14. Unfortunately, that’s probably because the Tide was so inefficient that their few explosive plays were a greater share of their successful plays. Let’s move on.
- Only 1 penalty for 5 yards! Unfortunately it was an offsides right at the end of the game, which snuffed out one more chance to get a measly touchdown.
- We got 11 first downs. Honestly, the Tide was moving the ball pretty well at times against this pretty awesome defense. And we only got 12 first downs in that 10-point CFP win vs. Oklahoma! They just couldn’t string the good plays together in a sequence to get into the dang end zone.
- We got 3 sacks. Which was looking like our only winning statistic … until a few sacks on Austin Mack late in the game.
- TOP honestly wasn’t that bad. It’s not great either, but honestly it’s not like we just 3-and-out’ed the whole night … there were some real drives in there.
.cfb-chart-embed-cfb-chart-1767325440686-yb643iylg { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .chart-content { height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767325440686-yb643iylg .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767325440686_yb643iylg() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767325440686-yb643iylg'); const caret = document.getElementById('caret_cfb-chart-1767325440686-yb643iylg'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767325440686-yb643iylg'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767325440686-yb643iylg'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "datasets": [ { "label": "NCAA Avg SR", "data": [ { "x": 1, "y": 0 }, { "x": 1, "y": 0.42 }, { "x": 48, "y": 0.42 }, { "x": 48, "y": 0 } ], "backgroundColor": "rgba(0,0,0,0.03)", "borderColor": "transparent", "pointRadius": 0, "fill": true, "tension": 0, "showLine": true, "datalabels": { "display": false } }, { "data": [ { "x": 1, "y": 0, "text": "T.Simpson pass incomplete short left to #80 J.Cuevas thrown to ALA45 QB hurried by #97 M.Landino" }, { "x": 2, "y": 0, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA44, for 4 yards to the ALA45 (#22 J.Sharpe)" }, { "x": 3, "y": 0, "text": "T.Simpson pass complete short middle to #4 D.Hill caught at ALA50, for 6 yards to the IND49 (#4 A.Fisher), 1ST DOWN" }, { "x": 4, "y": 0, "text": "T.Simpson pass complete short right to #80 J.Cuevas caught at IND44, for 6 yards to the IND43 (#21 R.Hardy)" }, { "x": 5, "y": 1, "text": "D.Hill rush left for 6 yards gain to the IND37 (#7 L.Moore), 1ST DOWN" }, { "x": 6, "y": 0.5, "text": "D.Hill rush right for 0 yards to the IND37 (#7 L.Moore; #21 R.Hardy)" }, { "x": 7, "y": 0.5, "text": "T.Simpson pass complete short left to #4 D.Hill caught at IND43, for 4 yards loss to the IND41 (#12 D.Boykin)" }, { "x": 8, "y": 0.5, "text": "T.Simpson pass incomplete deep left to #2 R.Williams thrown to IND06 broken up by #7 L.Moore QB hurried by #2 B.Baldwin Jr." }, { "x": 9, "y": 0.3333333333333333, "text": "K.Riley rush left for 0 yards to the ALA25 (#46 I.Jones)" }, { "x": 10, "y": 0.25, "text": "K.Riley rush middle for 2 yards gain to the ALA27 (#46 I.Jones; #0 H.Wheeler)" }, { "x": 11, "y": 0.2, "text": "T.Simpson rush right for 7 yards gain to the ALA34 (#4 A.Fisher)" }, { "x": 12, "y": 0.2, "text": "D.Hill pass complete short middle to #5 G.Bernard caught at ALA32, for 0 yards to the ALA34 (#46 I.Jones; #21 R.Hardy), TURNOVER ON DOWNS" }, { "x": 13, "y": 0.2, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA18, for 5 yards to the ALA19 (#22 J.Sharpe)" }, { "x": 14, "y": 0.2, "text": "T.Simpson pass complete short left to #5 G.Bernard caught at ALA29, for 18 yards to the ALA37 (#4 A.Fisher), out of bounds, 1ST DOWN" }, { "x": 15, "y": 0.2, "text": "T.Simpson pass incomplete short right to #5 G.Bernard thrown to ALA34" }, { "x": 16, "y": 0.16666666666666666, "text": "D.Hill rush middle for 0 yards to the ALA37 (#97 M.Landino)" }, { "x": 17, "y": 0.14285714285714285, "text": "T.Simpson rush middle for 1 yard gain to the ALA38 (#17 D.Ndukwe)" }, { "x": 18, "y": 0.14285714285714285, "text": "T.Simpson pass complete short right to #80 J.Cuevas caught at ALA21, for 8 yards to the ALA23 (#5 D.Ponds)" }, { "x": 19, "y": 0.14285714285714285, "text": "T.Simpson pass complete short middle to #4 D.Hill caught at ALA27, for 5 yards to the ALA28 (#21 R.Hardy), 1ST DOWN" }, { "x": 20, "y": 0.25, "text": "D.Hill rush left for 5 yards gain to the ALA33 (#12 D.Boykin)" }, { "x": 21, "y": 0.25, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA46, for 13 yards to the ALA46 (#5 D.Ponds), 1ST DOWN" }, { "x": 22, "y": 0.25, "text": "T.Simpson pass complete short left to #4 D.Hill caught at ALA46, for 3 yards to the ALA49 (#12 D.Boykin), out of bounds" }, { "x": 23, "y": 0.2222222222222222, "text": "K.Riley rush right for 0 yards to the ALA49 (#91 D.Ratcliff)" }, { "x": 24, "y": 0.2, "text": "T.Simpson at ALA24 for loss of 1 yard" }, { "x": 25, "y": 0.2, "text": "T.Simpson pass complete short right to #2 R.Williams caught at ALA20, for 2 yards loss to the ALA23 (#12 D.Boykin)" }, { "x": 26, "y": 0.2, "text": "T.Simpson pass incomplete short middle to #80 J.Cuevas thrown to ALA23 broken up by #97 M.Landino" }, { "x": 27, "y": 0.2, "text": "T.Simpson pass complete short left to #80 J.Cuevas caught at ALA25, for 5 yards to the ALA28 (#22 J.Sharpe)" }, { "x": 28, "y": 0.2, "text": "A.Mack pass complete short left to #26 J.Miller caught at ALA20, for 1 yard to the ALA26 (#17 D.Ndukwe), out of bounds" }, { "x": 29, "y": 0.2727272727272727, "text": "A.Mack rush right for 13 yards gain to the ALA39 (#4 A.Fisher), out of bounds, 1ST DOWN" }, { "x": 30, "y": 0.25, "text": "D.Hill rush middle for 2 yards gain to the ALA41 (#46 I.Jones; #4 A.Fisher)" }, { "x": 31, "y": 0.25, "text": "A.Mack pass complete deep right to #5 G.Bernard caught at IND36, for 34 yards to the IND25, out of bounds at IND25, 1ST DOWN" }, { "x": 32, "y": 0.25, "text": "A.Mack pass complete short right to #80 J.Cuevas caught at IND09, for 16 yards to the IND09, End Of Play, 1ST DOWN" }, { "x": 33, "y": 0.23076923076923078, "text": "A.Mack rush left for 4 yards gain to the IND05 (#12 D.Boykin)" }, { "x": 34, "y": 0.23076923076923078, "text": "A.Mack pass complete short right to #4 D.Hill caught at IND10, for 5 yards loss to the IND10, End Of Play" }, { "x": 35, "y": 0.23076923076923078, "text": "A.Mack pass incomplete short right to #17 L.Brooks thrown to IND03 QB hurried by #21 R.Hardy" }, { "x": 36, "y": 0.23076923076923078, "text": "A.Mack pass incomplete short right thrown to ALA42 QB hurried by #46 I.Jones" }, { "x": 37, "y": 0.23076923076923078, "text": "A.Mack sacked for loss of 10 yards to the ALA15 (#6 M.Kamara)" }, { "x": 38, "y": 0.23076923076923078, "text": "A.Mack pass incomplete deep right thrown to ALA36" }, { "x": 39, "y": 0.23076923076923078, "text": "A.Mack pass complete short right to #1 I.Horton caught at ALA35, for 10 yards to the ALA35, End Of Play, 1ST DOWN" }, { "x": 40, "y": 0.23076923076923078, "text": "A.Mack pass complete short right to #1 I.Horton caught at ALA39, for 6 yards to the ALA41 (#21 R.Hardy), out of bounds" }, { "x": 41, "y": 0.23076923076923078, "text": "A.Mack pass incomplete short right to #28 K.Riley thrown to ALA41 broken up by #95 T.Tucker" }, { "x": 42, "y": 0.23076923076923078, "text": "A.Mack pass complete short left to #5 G.Bernard caught at ALA49, for 8 yards to the ALA49, out of bounds at ALA49, 1ST DOWN" }, { "x": 43, "y": 0.23076923076923078, "text": "A.Mack pass complete short right to #4 D.Hill caught at ALA44, for 1 yard to the ALA50 (#12 D.Boykin; #4 A.Fisher), out of bounds" }, { "x": 44, "y": 0.23076923076923078, "text": "A.Mack sacked for loss of 8 yards to the ALA42 (#12 D.Boykin)" }, { "x": 45, "y": 0.23076923076923078, "text": "A.Mack pass complete short left to #2 R.Williams caught at ALA35, for 26 yards to the IND32 (#0 H.Wheeler), 1ST DOWN" }, { "x": 46, "y": 0.23076923076923078, "text": "A.Mack pass complete short right to #2 R.Williams caught at IND37, for 7 yards to the IND25 (#1 A.Ferrell), out of bounds" }, { "x": 47, "y": 0.23076923076923078, "text": "A.Mack pass incomplete short right to #28 K.Riley thrown to IND26 QB hurried by #21 R.Hardy" }, { "x": 48, "y": 0.23076923076923078, "text": "A.Mack pass complete short right to #4 D.Hill caught at IND31, for 1 yard loss to the IND26 (#21 R.Hardy)" } ], "label": "Alabama Rush SR", "borderColor": "rgba(101, 0, 20, 0.8)", "backgroundColor": [ "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(175, 40, 60, 0.8)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(175, 40, 60, 0.8)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(175, 40, 60, 0.8)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)" ], "borderWidth": 2, "pointStyle": "circle", "pointRadius": [ 0, 0, 0, 0, 4, 4, 0, 0, 4, 4, 4, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, 4, 4, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "pointBorderWidth": 1, "pointBorderColor": "rgba(101, 0, 20, 0.8)", "showLine": true }, { "data": [ { "x": 1, "y": 0, "text": "T.Simpson pass incomplete short left to #80 J.Cuevas thrown to ALA45 QB hurried by #97 M.Landino" }, { "x": 2, "y": 0, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA44, for 4 yards to the ALA45 (#22 J.Sharpe)" }, { "x": 3, "y": 0.3333333333333333, "text": "T.Simpson pass complete short middle to #4 D.Hill caught at ALA50, for 6 yards to the IND49 (#4 A.Fisher), 1ST DOWN" }, { "x": 4, "y": 0.5, "text": "T.Simpson pass complete short right to #80 J.Cuevas caught at IND44, for 6 yards to the IND43 (#21 R.Hardy)" }, { "x": 5, "y": 0.5, "text": "D.Hill rush left for 6 yards gain to the IND37 (#7 L.Moore), 1ST DOWN" }, { "x": 6, "y": 0.5, "text": "D.Hill rush right for 0 yards to the IND37 (#7 L.Moore; #21 R.Hardy)" }, { "x": 7, "y": 0.4, "text": "T.Simpson pass complete short left to #4 D.Hill caught at IND43, for 4 yards loss to the IND41 (#12 D.Boykin)" }, { "x": 8, "y": 0.3333333333333333, "text": "T.Simpson pass incomplete deep left to #2 R.Williams thrown to IND06 broken up by #7 L.Moore QB hurried by #2 B.Baldwin Jr." }, { "x": 9, "y": 0.3333333333333333, "text": "K.Riley rush left for 0 yards to the ALA25 (#46 I.Jones)" }, { "x": 10, "y": 0.3333333333333333, "text": "K.Riley rush middle for 2 yards gain to the ALA27 (#46 I.Jones; #0 H.Wheeler)" }, { "x": 11, "y": 0.3333333333333333, "text": "T.Simpson rush right for 7 yards gain to the ALA34 (#4 A.Fisher)" }, { "x": 12, "y": 0.2857142857142857, "text": "D.Hill pass complete short middle to #5 G.Bernard caught at ALA32, for 0 yards to the ALA34 (#46 I.Jones; #21 R.Hardy), TURNOVER ON DOWNS" }, { "x": 13, "y": 0.375, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA18, for 5 yards to the ALA19 (#22 J.Sharpe)" }, { "x": 14, "y": 0.4444444444444444, "text": "T.Simpson pass complete short left to #5 G.Bernard caught at ALA29, for 18 yards to the ALA37 (#4 A.Fisher), out of bounds, 1ST DOWN" }, { "x": 15, "y": 0.4, "text": "T.Simpson pass incomplete short right to #5 G.Bernard thrown to ALA34" }, { "x": 16, "y": 0.4, "text": "D.Hill rush middle for 0 yards to the ALA37 (#97 M.Landino)" }, { "x": 17, "y": 0.4, "text": "T.Simpson rush middle for 1 yard gain to the ALA38 (#17 D.Ndukwe)" }, { "x": 18, "y": 0.45454545454545453, "text": "T.Simpson pass complete short right to #80 J.Cuevas caught at ALA21, for 8 yards to the ALA23 (#5 D.Ponds)" }, { "x": 19, "y": 0.5, "text": "T.Simpson pass complete short middle to #4 D.Hill caught at ALA27, for 5 yards to the ALA28 (#21 R.Hardy), 1ST DOWN" }, { "x": 20, "y": 0.5, "text": "D.Hill rush left for 5 yards gain to the ALA33 (#12 D.Boykin)" }, { "x": 21, "y": 0.5384615384615384, "text": "T.Simpson pass complete short left to #2 R.Williams caught at ALA46, for 13 yards to the ALA46 (#5 D.Ponds), 1ST DOWN" }, { "x": 22, "y": 0.5, "text": "T.Simpson pass complete short left to #4 D.Hill caught at ALA46, for 3 yards to the ALA49 (#12 D.Boykin), out of bounds" }, { "x": 23, "y": 0.5, "text": "K.Riley rush right for 0 yards to the ALA49 (#91 D.Ratcliff)" }, { "x": 24, "y": 0.5, "text": "T.Simpson at ALA24 for loss of 1 yard" }, { "x": 25, "y": 0.4666666666666667, "text": "T.Simpson pass complete short right to #2 R.Williams caught at ALA20, for 2 yards loss to the ALA23 (#12 D.Boykin)" }, { "x": 26, "y": 0.4375, "text": "T.Simpson pass incomplete short middle to #80 J.Cuevas thrown to ALA23 broken up by #97 M.Landino" }, { "x": 27, "y": 0.4117647058823529, "text": "T.Simpson pass complete short left to #80 J.Cuevas caught at ALA25, for 5 yards to the ALA28 (#22 J.Sharpe)" }, { "x": 28, "y": 0.3888888888888889, "text": "A.Mack pass complete short left to #26 J.Miller caught at ALA20, for 1 yard to the ALA26 (#17 D.Ndukwe), out of bounds" }, { "x": 29, "y": 0.3888888888888889, "text": "A.Mack rush right for 13 yards gain to the ALA39 (#4 A.Fisher), out of bounds, 1ST DOWN" }, { "x": 30, "y": 0.3888888888888889, "text": "D.Hill rush middle for 2 yards gain to the ALA41 (#46 I.Jones; #4 A.Fisher)" }, { "x": 31, "y": 0.42105263157894735, "text": "A.Mack pass complete deep right to #5 G.Bernard caught at IND36, for 34 yards to the IND25, out of bounds at IND25, 1ST DOWN" }, { "x": 32, "y": 0.45, "text": "A.Mack pass complete short right to #80 J.Cuevas caught at IND09, for 16 yards to the IND09, End Of Play, 1ST DOWN" }, { "x": 33, "y": 0.45, "text": "A.Mack rush left for 4 yards gain to the IND05 (#12 D.Boykin)" }, { "x": 34, "y": 0.42857142857142855, "text": "A.Mack pass complete short right to #4 D.Hill caught at IND10, for 5 yards loss to the IND10, End Of Play" }, { "x": 35, "y": 0.4090909090909091, "text": "A.Mack pass incomplete short right to #17 L.Brooks thrown to IND03 QB hurried by #21 R.Hardy" }, { "x": 36, "y": 0.391304347826087, "text": "A.Mack pass incomplete short right thrown to ALA42 QB hurried by #46 I.Jones" }, { "x": 37, "y": 0.375, "text": "A.Mack sacked for loss of 10 yards to the ALA15 (#6 M.Kamara)" }, { "x": 38, "y": 0.36, "text": "A.Mack pass incomplete deep right thrown to ALA36" }, { "x": 39, "y": 0.38461538461538464, "text": "A.Mack pass complete short right to #1 I.Horton caught at ALA35, for 10 yards to the ALA35, End Of Play, 1ST DOWN" }, { "x": 40, "y": 0.4074074074074074, "text": "A.Mack pass complete short right to #1 I.Horton caught at ALA39, for 6 yards to the ALA41 (#21 R.Hardy), out of bounds" }, { "x": 41, "y": 0.39285714285714285, "text": "A.Mack pass incomplete short right to #28 K.Riley thrown to ALA41 broken up by #95 T.Tucker" }, { "x": 42, "y": 0.41379310344827586, "text": "A.Mack pass complete short left to #5 G.Bernard caught at ALA49, for 8 yards to the ALA49, out of bounds at ALA49, 1ST DOWN" }, { "x": 43, "y": 0.4, "text": "A.Mack pass complete short right to #4 D.Hill caught at ALA44, for 1 yard to the ALA50 (#12 D.Boykin; #4 A.Fisher), out of bounds" }, { "x": 44, "y": 0.3870967741935484, "text": "A.Mack sacked for loss of 8 yards to the ALA42 (#12 D.Boykin)" }, { "x": 45, "y": 0.40625, "text": "A.Mack pass complete short left to #2 R.Williams caught at ALA35, for 26 yards to the IND32 (#0 H.Wheeler), 1ST DOWN" }, { "x": 46, "y": 0.42424242424242425, "text": "A.Mack pass complete short right to #2 R.Williams caught at IND37, for 7 yards to the IND25 (#1 A.Ferrell), out of bounds" }, { "x": 47, "y": 0.4117647058823529, "text": "A.Mack pass incomplete short right to #28 K.Riley thrown to IND26 QB hurried by #21 R.Hardy" }, { "x": 48, "y": 0.4, "text": "A.Mack pass complete short right to #4 D.Hill caught at IND31, for 1 yard loss to the IND26 (#21 R.Hardy)" } ], "label": "Alabama Pass SR", "borderColor": "rgba(101, 0, 20, 0.8)", "backgroundColor": [ "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(175, 40, 60, 0.8)", "rgba(101, 0, 20, 0.8)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)", "rgba(255,255,255,0.9)", "rgba(175, 40, 60, 0.8)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(101, 0, 20, 0.8)", "rgba(101, 0, 20, 0.8)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)", "rgba(255,255,255,0.9)", "rgba(175, 40, 60, 0.8)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)", "rgba(101, 0, 20, 0.8)", "rgba(175, 40, 60, 0.8)", "rgba(255,255,255,0.9)", "rgba(255,255,255,0.9)" ], "borderWidth": 2, "pointStyle": "triangle", "pointRadius": [ 6, 6, 6, 6, 0, 0, 6, 6, 0, 0, 0, 6, 6, 6, 6, 0, 0, 6, 6, 0, 6, 6, 0, 0, 6, 6, 6, 6, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 ], "pointBorderWidth": 1, "pointBorderColor": "rgba(101, 0, 20, 0.8)", "borderDash": [ 4, 4 ], "showLine": true }, { "label": "Quarters", "data": [ { "x": 1, "y": 0 }, { "x": 1, "y": 1 }, { "x": 48, "y": 1 }, { "x": 48, "y": 0 }, { "x": 9, "y": 0 }, { "x": 9, "y": 1 }, { "x": 48, "y": 1 }, { "x": 48, "y": 0 }, { "x": 25, "y": 0 }, { "x": 25, "y": 1 }, { "x": 48, "y": 1 }, { "x": 48, "y": 0 }, { "x": 36, "y": 0 }, { "x": 36, "y": 1 }, { "x": 48, "y": 1 }, { "x": 48, "y": 0 } ], "borderColor": "rgba(0,0,0,0.1)", "borderWidth": 1, "tension": 0, "fill": false, "pointRadius": 0, "showLine": true, "datalabels": { "display": false } } ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" } }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'line' === 'line' ? 'team-play-type-lines'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'team-play-type-lines' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'team-play-type-lines'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('line' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('team-play-type-lines' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('team-play-type-lines'.includes('top-rushers') || 'team-play-type-lines'.includes('top-passers') || 'team-play-type-lines'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'team-play-type-lines' === 'win-probability' ? { display: false } : 'line' === 'line' ? { position: 'top', align: 'start', labels: 'team-play-type-lines'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'team-play-type-lines' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('team-play-type-lines'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'line', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767325440686-yb643iylg').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
True to form, the running game was terrible. (This 23% Rushing XR was actually the worst rushing efficiency we’ve had all year, tied with the SECCG, which is saying something). You can actually see that in this fancy new chart from the Team Trends collection I’ve been working on (more on that soon):
.cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .chart-content { padding: 20px 24px 24px !important; height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767325450132-k8xk9ye63 .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion function toggleDefinitions_cfb_chart_1767325450132_k8xk9ye63() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767325450132-k8xk9ye63'); const caret = document.getElementById('caret_cfb-chart-1767325450132-k8xk9ye63'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Initialize chart (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; function showError(message) { const canvas = document.getElementById('cfb-chart-1767325450132-k8xk9ye63'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } const canvas = document.getElementById('cfb-chart-1767325450132-k8xk9ye63'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { Chart.register(ChartDataLabels); const chartData = { "labels": [ "@ Florida State", "vs UL Monroe", "vs Wisconsin", "@ Georgia", "vs Vanderbilt", "@ Missouri", "vs Tennessee", "@ South Carolina", "vs LSU", "vs Oklahoma", "vs Eastern Illinois", "@ Auburn", "vs Georgia", "@ Oklahoma*", "@ Indiana*" ], "datasets": [ { "label": "Alabama Rush SR", "data": [ 38.46153846153847, 47.22222222222222, 38.095238095238095, 29.72972972972973, 50, 35, 48.38709677419355, 38.095238095238095, 28.000000000000004, 44.827586206896555, 65.3061224489796, 41.17647058823529, 23.076923076923077, 23.809523809523807, 23.076923076923077 ], "borderColor": "rgba(101, 0, 20, 0.8)", "backgroundColor": "transparent", "borderWidth": 2.5, "pointRadius": 4, "pointStyle": "circle", "tension": 0.15, "datalabels": { "display": false } }, { "label": "Alabama Pass SR", "data": [ 37.77777777777778, 69.6969696969697, 64.51612903225806, 50, 48.57142857142857, 45.714285714285715, 55.172413793103445, 44.44444444444444, 41.66666666666667, 47.72727272727273, 66.66666666666666, 28.947368421052634, 30.23255813953488, 27.27272727272727, 40 ], "borderColor": "rgba(101, 0, 20, 0.8)", "backgroundColor": "transparent", "borderWidth": 2.5, "borderDash": [ 4, 4 ], "pointRadius": 5, "pointStyle": "triangle", "tension": 0.15, "datalabels": { "display": false } }, { "label": "Opp Rush SR", "data": [ 41.66666666666667, 22.58064516129032, 46.666666666666664, 45.16129032258064, 35.294117647058826, 52, 60, 40, 22.727272727272727, 19.230769230769234, 7.4074074074074066, 47.05882352941176, 32.5, 32.142857142857146, 46.808510638297875 ], "borderColor": "#9CA3AF", "backgroundColor": "transparent", "borderWidth": 2, "pointRadius": 3, "pointStyle": "circle", "tension": 0.15, "datalabels": { "display": false } }, { "label": "Opp Pass SR", "data": [ 26.666666666666668, 33.33333333333333, 42.857142857142854, 42.857142857142854, 52.77777777777778, 33.33333333333333, 38.297872340425535, 38.23529411764706, 30.303030303030305, 37.5, 18.181818181818183, 31.57894736842105, 40.74074074074074, 31.914893617021278, 63.1578947368421 ], "borderColor": "#9CA3AF", "backgroundColor": "transparent", "borderWidth": 2, "borderDash": [ 4, 4 ], "pointRadius": 4, "pointStyle": "triangle", "tension": 0.15, "datalabels": { "display": false } }, { "type": "line", "label": "NCAA Avg SR", "data": [ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 ], "borderColor": "#757575", "borderWidth": 1.5, "borderDash": [ 3, 3 ], "pointRadius": 0, "datalabels": { "display": false } } ] }; const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 }, elements: { line: { tension: 0.15, borderWidth: 2.5 }, point: { radius: 4 } }, plugins: { datalabels: { display: false, formatter: function(value, context) { // Use play count data if available (for bar charts) if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex] != null) { return context.dataset.playCountData[context.dataIndex]; } // Fallback for other cases if (typeof value === 'number') { if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem) { return !legendItem.text.includes('NCAA Avg SR'); } } }, tooltip: { enabled: true, mode: 'index', intersect: false } }, scales: { // For vertical bar charts and line charts x: { grid: { display: false }, ticks: { maxRotation: 45, minRotation: 45, font: { size: 11 } } }, y: { max: 100, min: 0, ticks: { callback: function(value) { return value + '%'; } } } } }; const chart = new Chart(canvas, { type: 'line', data: chartData, options: chartOptions }); canvas.chartInstance = chart; } catch (error) { console.error('Error initializing chart:', error); showError('Failed to initialize chart: ' + error.message); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initChart); } else { initChart(); } })();
But … that perhaps that running game flop obscures that the passing game was decidedly average in this game! We even had things cooking a bit late in the first half before a(nother) disappointing drive coming out of halftime. But this passing SR trend line almost never dipped below average, which is notable in a game where the offense only scored 3 points and had zero successful Red Zone plays.
.cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .chart-content { height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767325480707-z11yxdbdy .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767325480707_z11yxdbdy() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767325480707-z11yxdbdy'); const caret = document.getElementById('caret_cfb-chart-1767325480707-z11yxdbdy'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767325480707-z11yxdbdy'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767325480707-z11yxdbdy'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "labels": [ "Q1", "Q2", "Q3", "Q4" ], "datasets": [ { "data": [ 0, 0.0625, 0.18181818181818182, 0.07692307692307693 ], "stack": "Team", "label": "Alabama XR", "backgroundColor": "rgba(101, 0, 20, 0.8)", "datalabels": { "display": false } }, { "data": [ 0.375, 0.375, 0.2727272727272727, 0.38461538461538464 ], "stack": "Team", "label": "Alabama SR", "backgroundColor": "rgba(175, 40, 60, 0.8)", "datalabels": { "display": true } }, { "data": [ 0.05555555555555555, 0.1111111111111111, 0.21428571428571427, 0.1875 ], "stack": "Opponent", "label": "Indiana XR", "backgroundColor": "rgba(102, 0, 0, 0.8)", "datalabels": { "display": false } }, { "data": [ 0.5, 0.6111111111111112, 0.6428571428571429, 0.3125 ], "stack": "Opponent", "label": "Indiana SR", "backgroundColor": "rgba(153, 0, 0, 0.8)", "datalabels": { "display": true } }, { "type": "line", "data": [ 0.42, 0.42, 0.42, 0.42 ], "label": "NCAA Avg SR", "borderColor": "#757575", "borderWidth": 2, "borderDash": [ 3, 3 ], "pointRadius": 0, "datalabels": { "display": false } }, { "type": "line", "data": [ null, null, null, null ], "label": "# Plays", "backgroundColor": "rgba(0, 0, 0, 0)", "borderColor": "rgba(0, 0, 0, 0)", "borderWidth": 0, "pointRadius": 0, "showLine": false, "fill": false, "datalabels": { "display": false } } ], "teamCounts": [ 8, 16, 11, 13 ], "oppCounts": [ 18, 18, 14, 16 ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" } }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'bar' === 'line' ? 'quarter-bars'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'quarter-bars' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'quarter-bars'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('bar' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('quarter-bars' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('quarter-bars'.includes('top-rushers') || 'quarter-bars'.includes('top-passers') || 'quarter-bars'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'quarter-bars' === 'win-probability' ? { display: false } : 'bar' === 'line' ? { position: 'top', align: 'start', labels: 'quarter-bars'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'quarter-bars' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('quarter-bars'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'bar', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767325480707-z11yxdbdy').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
Um, hey we won the 4th quarter? (On efficiency, not in explosivness or, you know, points).
Honestly part of this is just the Hoosiers burning the clock at the end of the game, but I am starving for silver linings over here folks.
.cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .chart-content { height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767325505121-dwiri9r1l .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767325505121_dwiri9r1l() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767325505121-dwiri9r1l'); const caret = document.getElementById('caret_cfb-chart-1767325505121-dwiri9r1l'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767325505121-dwiri9r1l'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767325505121-dwiri9r1l'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "labels": [ "1st Down", "2nd Down", "3rd Down", "4th Down" ], "datasets": [ { "data": [ 0.05, 0.11764705882352941, 0.1, 0 ], "stack": "Team", "label": "Alabama XR", "backgroundColor": "rgba(101, 0, 20, 0.8)", "datalabels": { "display": false } }, { "data": [ 0.4, 0.35294117647058826, 0.3, 0 ], "stack": "Team", "label": "Alabama SR", "backgroundColor": "rgba(175, 40, 60, 0.8)", "datalabels": { "display": true } }, { "data": [ 0.07407407407407407, 0.12, 0.2857142857142857, 0 ], "stack": "Opponent", "label": "Indiana XR", "backgroundColor": "rgba(102, 0, 0, 0.8)", "datalabels": { "display": false } }, { "data": [ 0.4444444444444444, 0.52, 0.6428571428571429, 0 ], "stack": "Opponent", "label": "Indiana SR", "backgroundColor": "rgba(153, 0, 0, 0.8)", "datalabels": { "display": true } }, { "type": "line", "data": [ 0.42, 0.42, 0.42, 0.42 ], "label": "NCAA Avg SR", "borderColor": "#757575", "borderWidth": 2, "borderDash": [ 3, 3 ], "pointRadius": 0, "datalabels": { "display": false } }, { "type": "line", "data": [ null, null, null, null ], "label": "# Plays", "backgroundColor": "rgba(0, 0, 0, 0)", "borderColor": "rgba(0, 0, 0, 0)", "borderWidth": 0, "pointRadius": 0, "showLine": false, "fill": false, "datalabels": { "display": false } } ], "teamCounts": [ 20, 17, 10, 1 ], "oppCounts": [ 27, 25, 14, 0 ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" } }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'bar' === 'line' ? 'down-bars'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'down-bars' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'down-bars'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('bar' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('down-bars' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('down-bars'.includes('top-rushers') || 'down-bars'.includes('top-passers') || 'down-bars'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'down-bars' === 'win-probability' ? { display: false } : 'bar' === 'line' ? { position: 'top', align: 'start', labels: 'down-bars'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'down-bars' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('down-bars'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'bar', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767325505121-dwiri9r1l').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
And speaking of charts that are almost-all-bad … the performance by down. Now, these all look pretty bad, but I want to point out this 3rd down line. Anyone watching the game watched the Tide defense put Indiana in 3rd-and-longs all night … only to have Mendoza pull out some stupendous play for a lot of yards.
Aggravating. And you can’t remove the fact that they pulled that off. But nobody wants to be in 3rd and longs all night; in some ways it feels pretty unlikely that they’d be so successful on basically all of those (and 3rd downs in general). I take some faint solace in that … they’ll all tell you that Indiana utterly dominated Alabama tonight, but bailing yourself out on 3rd and longs all day suggests at least a little more nuance.
.cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .chart-content { height: 325px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .chart-content { padding: 12px 16px 20px !important; height: 280px !important; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767325518411-kykc6i0ul .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767325518411_kykc6i0ul() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767325518411-kykc6i0ul'); const caret = document.getElementById('caret_cfb-chart-1767325518411-kykc6i0ul'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767325518411-kykc6i0ul'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767325518411-kykc6i0ul'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "labels": [ "1st Down", "2nd Down", "3rd Down", "4th Down" ], "datasets": [ { "data": [ 0.05, 0.11764705882352941, 0.1, 0 ], "stack": "Team", "label": "Alabama XR", "backgroundColor": "rgba(101, 0, 20, 0.8)", "datalabels": { "display": false } }, { "data": [ 0.4, 0.35294117647058826, 0.3, 0 ], "stack": "Team", "label": "Alabama SR", "backgroundColor": "rgba(175, 40, 60, 0.8)", "datalabels": { "display": true } }, { "data": [ 0.07407407407407407, 0.12, 0.2857142857142857, 0 ], "stack": "Opponent", "label": "Indiana XR", "backgroundColor": "rgba(102, 0, 0, 0.8)", "datalabels": { "display": false } }, { "data": [ 0.4444444444444444, 0.52, 0.6428571428571429, 0 ], "stack": "Opponent", "label": "Indiana SR", "backgroundColor": "rgba(153, 0, 0, 0.8)", "datalabels": { "display": true } }, { "type": "line", "data": [ 0.42, 0.42, 0.42, 0.42 ], "label": "NCAA Avg SR", "borderColor": "#757575", "borderWidth": 2, "borderDash": [ 3, 3 ], "pointRadius": 0, "datalabels": { "display": false } }, { "type": "line", "data": [ null, null, null, null ], "label": "# Plays", "backgroundColor": "rgba(0, 0, 0, 0)", "borderColor": "rgba(0, 0, 0, 0)", "borderWidth": 0, "pointRadius": 0, "showLine": false, "fill": false, "datalabels": { "display": false } } ], "teamCounts": [ 20, 17, 10, 1 ], "oppCounts": [ 27, 25, 14, 0 ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" } }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'bar' === 'line' ? 'down-bars'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'down-bars' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'down-bars'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('bar' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('down-bars' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('down-bars'.includes('top-rushers') || 'down-bars'.includes('top-passers') || 'down-bars'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'down-bars' === 'win-probability' ? { display: false } : 'bar' === 'line' ? { position: 'top', align: 'start', labels: 'down-bars'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'down-bars' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('down-bars'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'bar', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767325518411-kykc6i0ul').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
Hah, well Alabama continued — and in fact, exaggerated — their trend of letting the short yardage stuff go on defense. Except this time, we were awful from short yardage.
We were also, unusually, bad on long yardage. That’s often where Ty and co. could pull some things off, but in this one it was Mendoza and co. making, yep, 3rd-and-longs work from out there in the 8+ range.
But look at that medium yardage line! Alabama wins! Roll Tide! 🤪
.cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .chart-content.top-passers { height: 280px !important; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .chart-content { padding: 12px 16px 20px !important; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767325540553-ao5vw12fn .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767325540553_ao5vw12fn() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767325540553-ao5vw12fn'); const caret = document.getElementById('caret_cfb-chart-1767325540553-ao5vw12fn'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767325540553-ao5vw12fn'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767325540553-ao5vw12fn'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "labels": [ "T.Simpson", "A.Mack", "D.Hill" ], "datasets": [ { "label": "Explosive", "data": [ 1, 3, 0 ], "backgroundColor": [ "#3c000cCC", "#3c000cCC", "#3c000cCC" ], "borderColor": "#374151", "borderWidth": 1 }, { "label": "Successful", "data": [ 6, 4, 0 ], "backgroundColor": [ "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)" ], "borderColor": "#374151", "borderWidth": 1 }, { "label": "Other catches", "data": [ 5, 4, 1 ], "backgroundColor": [ "rgba(245, 229, 233, 0.8)", "rgba(245, 229, 233, 0.8)", "rgba(245, 229, 233, 0.8)" ], "borderColor": "#374151", "borderWidth": 1 }, { "label": "Incompletes", "data": [ 4, 5, 0 ], "backgroundColor": "#FFFFFF", "borderColor": "#374151", "borderWidth": 1 }, { "label": "Interceptions", "data": [ 0, 0, 0 ], "backgroundColor": "#4B5563", "borderColor": "#374151", "borderWidth": 1 } ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" }, "teamFilter": "Alabama" }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'bar' === 'line' ? 'top-passers'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'top-passers' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'top-passers'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('bar' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('top-passers' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('top-passers'.includes('top-rushers') || 'top-passers'.includes('top-passers') || 'top-passers'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'top-passers' === 'win-probability' ? { display: false } : 'bar' === 'line' ? { position: 'top', align: 'start', labels: 'top-passers'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'top-passers' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('top-passers'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'bar', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767325540553-ao5vw12fn').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
And while this chart isn’t exactly electric, it was cool to see Austin Mack come in and find some success. Sure, it flamed out late after the Hoosiers got used to him, but he threw about as many passes as Ty and at least ended up with 2 more explosives than Ty. (If also the same passing SR).
(No, I’m not showing Mendoza’s line here. Nobody wants that).
.cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; margin: 0; padding: 0; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .chart-container { background: white; border-radius: 12px; border: 1px solid #e5e5e5; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .chart-header { padding: 18px 24px 14px; border-bottom: 1px solid #e5e5e5; background: white; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .chart-title { font-size: 18px; font-weight: 600; color: #171717; margin: 0; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .chart-subtitle { font-size: 11px; font-weight: 400; color: #737373; margin: 4px 0 0 0; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .chart-content { padding: 20px 24px 24px !important; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .chart-content.top-receivers { height: 380px; } @media (max-width: 640px) { .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .chart-content { padding: 12px 16px 20px !important; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .chart-header { padding: 12px 16px 12px !important; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .embed-footer-top { padding: 8px 12px !important; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .data-definitions { padding: 12px !important; } } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .embed-footer { border-top: 1px solid #e5e5e5; font-size: 12px; color: #737373; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .embed-footer-top { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .embed-footer-link { color: #737373; text-decoration: none; font-weight: 500; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .embed-footer-link:hover { color: #525252; text-decoration: underline; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .data-definitions-toggle { background: none; border: none; color: #737373; font-size: 12px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 0; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .data-definitions-toggle:hover { color: #525252; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .caret { transition: transform 0.2s ease; font-size: 10px; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .caret.expanded { transform: rotate(180deg); } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .data-definitions { display: none; padding: 16px; background: #fafafa; border-top: 1px solid #e5e5e5; font-size: 12px; line-height: 1.4; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .data-definitions.expanded { display: block; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .data-definitions ul { margin: 0; padding-left: 0; list-style: none; } .cfb-chart-embed-cfb-chart-1767325551088-1bmysvksy .data-definitions li { margin-bottom: 4px; }
// Toggle data definitions accordion - unique function per embed function toggleDefinitions_cfb_chart_1767325551088_1bmysvksy() { const definitions = document.getElementById('dataDefinitions_cfb-chart-1767325551088-1bmysvksy'); const caret = document.getElementById('caret_cfb-chart-1767325551088-1bmysvksy'); if (definitions.classList.contains('expanded')) { definitions.classList.remove('expanded'); caret.classList.remove('expanded'); } else { definitions.classList.add('expanded'); caret.classList.add('expanded'); } } // Sequential script loading for better reliability (function() { 'use strict'; let retryCount = 0; const maxRetries = 50; // 5 seconds total // Load scripts sequentially function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; script.onerror = function() { console.error('Failed to load script:', url); showError('Failed to load required chart library'); }; document.head.appendChild(script); } function showError(message) { const canvas = document.getElementById('cfb-chart-1767325551088-1bmysvksy'); if (canvas && canvas.parentNode) { canvas.parentNode.innerHTML = '
' + message + '
'; } } function initChart() { retryCount++; // Check if Chart.js is available if (typeof Chart === 'undefined') { if (retryCount >= maxRetries) { showError('Chart library failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if datalabels plugin is available if (typeof ChartDataLabels === 'undefined') { if (retryCount >= maxRetries) { showError('Chart plugin failed to load. Please refresh the page.'); return; } setTimeout(initChart, 100); return; } // Check if canvas element exists const canvas = document.getElementById('cfb-chart-1767325551088-1bmysvksy'); if (!canvas) { console.warn('Canvas element not found yet, retrying...'); setTimeout(initChart, 100); return; } // Prevent multiple chart instances if (canvas.chartInstance) { console.log('Chart already initialized'); return; } try { // Register the datalabels plugin Chart.register(ChartDataLabels); // Embed actual chart data directly const chartData = { "labels": [ "D.Hill", "R.Williams", "J.Cuevas", "G.Bernard", "I.Horton", "J.Miller" ], "datasets": [ { "label": "Explosive catches", "data": [ 0, 1, 1, 2, 0, 0 ], "backgroundColor": [ "#3c000cCC", "#3c000cCC", "#3c000cCC", "#3c000cCC", "#3c000cCC", "#3c000cCC" ], "borderColor": "#374151", "borderWidth": 1 }, { "label": "Successful catches", "data": [ 2, 3, 2, 1, 2, 0 ], "backgroundColor": [ "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)", "rgba(175, 40, 60, 0.8)" ], "borderColor": "#374151", "borderWidth": 1 }, { "label": "Other catches", "data": [ 5, 2, 1, 1, 0, 1 ], "backgroundColor": [ "rgba(245, 229, 233, 0.8)", "rgba(245, 229, 233, 0.8)", "rgba(245, 229, 233, 0.8)", "rgba(245, 229, 233, 0.8)", "rgba(245, 229, 233, 0.8)", "rgba(245, 229, 233, 0.8)" ], "borderColor": "#374151", "borderWidth": 1 } ], "currentParams": { "year": 2025, "week": 1, "seasonType": "postseason", "team": "Alabama", "gameId": "401769072" }, "teamFilter": "Alabama" }; // Chart options (WordPress-safe) const chartOptions = { responsive: true, maintainAspectRatio: false, animation: { duration: 1 // Minimal animation to trigger layout calculation (fixes label positioning) }, elements: 'bar' === 'line' ? 'top-receivers'.includes('play-map') ? { line: { tension: 0, borderWidth: 0 } } : 'top-receivers' === 'win-probability' ? { line: { tension: 0.15, borderWidth: 2.2, fill: false }, point: { pointRadius: 0, pointHoverRadius: 4 } } : { line: { tension: 0.25, borderWidth: 2.2 }, point: { pointRadius: 'top-receivers'.includes('team-lines') ? 0 : undefined } } : {}, plugins: { datalabels: { display: function(context) { // Suppress data labels on line charts if ('bar' === 'line') { return false; } return context.dataset.datalabels && context.dataset.datalabels.display === true; }, formatter: function(value, context) { // Special handling for Overall Team Performance chart if ('top-receivers' === 'overall-team-performance' && context.dataset.label === 'Success Rate (SR)') { // Use the stored play count data if (context.dataset.playCountData && context.dataset.playCountData[context.dataIndex]) { return context.dataset.playCountData[context.dataIndex]; } // Fallback to percentage if play count data not available return Math.round(value * 100) + '%'; } // Handle bar charts with count data (play-type, quarter, down, etc.) if (context.dataset.label && context.dataset.label.includes(' SR') && (chartData.teamCounts || chartData.oppCounts)) { // Find the first team SR dataset in the chart to determine team order const allDatasets = context.chart.data.datasets; const teamSRDataset = allDatasets.find(d => d.label && d.label.includes(' SR') && !d.label.includes('NCAA')); // If this is the first team's SR dataset, use teamCounts if (teamSRDataset && context.dataset.label === teamSRDataset.label && chartData.teamCounts) { return chartData.teamCounts[context.dataIndex] || 0; } // Otherwise, use oppCounts for the second team else if (chartData.oppCounts) { return chartData.oppCounts[context.dataIndex] || 0; } } // For player charts, show value only if > 0 (matches non-embedded behavior) if ('top-receivers'.includes('top-rushers') || 'top-receivers'.includes('top-passers') || 'top-receivers'.includes('top-receivers')) { // Hide data labels for zero or negative values, show actual value for positive values return value > 0 ? value : null; } // For other charts, show values based on type if (typeof value === 'number') { // If value is between 0 and 1, treat as percentage if (value >= 0 && value 0 ? '#26262660' : 'transparent'; }, borderColor: function(context) { const value = context.dataset.data[context.dataIndex]; return value > 0 ? 'rgba(255, 255, 255, 0.2)' : 'transparent'; }, borderRadius: 4, align: 'center', anchor: 'center' }, legend: 'top-receivers' === 'win-probability' ? { display: false } : 'bar' === 'line' ? { position: 'top', align: 'start', labels: 'top-receivers'.includes('play-map') ? { usePointStyle: true, generateLabels: function(chart) { // Call the original generateLabels to get default styling const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter and customize each label const filteredLabels = labels.filter(label => { return !label.text.includes(' { const dataset = chart.data.datasets[label.datasetIndex]; if (dataset && dataset.label) { if (dataset.label.includes('Rush')) { label.pointStyle = 'circle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else if (dataset.label.includes('Pass')) { label.pointStyle = 'triangle'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } else { label.pointStyle = 'rect'; label.pointStyleWidth = 4; label.fillStyle = 'white'; } } }); return filteredLabels; }, boxWidth: 20, padding: 12 } : { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); // Filter out reference areas and ensure white fill const filteredLabels = labels.filter(label => { return !label.text.includes('NCAA Avg SR') && !label.text.includes('50/50') && !label.text.includes('Quarters'); }); // Ensure white fill for all line chart legend boxes filteredLabels.forEach((label) => { label.fillStyle = 'white'; }); return filteredLabels; } } } : { position: 'top', align: 'start', labels: { usePointStyle: false, boxWidth: 12, boxHeight: 12, padding: 12, filter: function(legendItem, chartData) { return !legendItem.text.includes('NCAA Avg SR') && !legendItem.text.includes('Quarters') && !legendItem.text.includes('50/50'); }, generateLabels: function(chart) { const data = chart.data; if (data.datasets.length) { return data.datasets.map((dataset, i) => { // Handle backgroundColor arrays (like in Overall Team Performance chart) let fillColor = dataset.backgroundColor; if (dataset.label === '# Plays') { fillColor = 'white'; } else if (Array.isArray(dataset.backgroundColor)) { // For datasets with backgroundColor arrays, use the first color for legend fillColor = dataset.backgroundColor[0]; } return { text: dataset.label, fillStyle: fillColor, strokeStyle: dataset.label === '# Plays' ? '#666' : dataset.borderColor, lineWidth: dataset.label === '# Plays' ? 1 : dataset.borderWidth, hidden: !chart.isDatasetVisible(i), datasetIndex: i }; }).filter((item, index) => { // Apply the same filter logic as above const dataset = chart.data.datasets[index]; if (!dataset || !dataset.data) return false; if (dataset.label === '# Plays') return true; // Always show # Plays if (dataset.label && (dataset.label.includes('NCAA Avg SR') || dataset.label.includes('Quarters') || dataset.label.includes('50/50'))) return false; return dataset.data.some((value) => value > 0); }); } return []; } } }, tooltip: 'top-receivers' === 'win-probability' ? { mode: 'index', intersect: false, callbacks: { title: function(tooltipItems) { if (tooltipItems && tooltipItems[0]) { return 'Play ' + (tooltipItems[0].dataIndex + 1); } return ''; }, label: function(context) { const selectedTeamWinProb = context.parsed.y; const opponentWinProb = 100 - selectedTeamWinProb; const selectedTeam = context.dataset.selectedTeam || 'Team'; const opponentTeam = context.dataset.opponentTeam || 'Opponent'; return [ selectedTeam + ': ' + selectedTeamWinProb.toFixed(1) + '%', opponentTeam + ': ' + opponentWinProb.toFixed(1) + '%' ]; }, afterLabel: function(context) { if (context.dataset.playTexts && context.dataset.playTexts[context.dataIndex]) { return '\n' + context.dataset.playTexts[context.dataIndex]; } return ''; } } } : { filter: function(tooltipItem) { if ('top-receivers'.includes('play-map')) { return !tooltipItem.dataset.label.includes('< 0') && !tooltipItem.dataset.label.includes('Quarters') && !tooltipItem.dataset.label.includes('Drive'); } return !tooltipItem.dataset.label.includes('NCAA Avg SR') && !tooltipItem.dataset.label.includes('50/50') && !tooltipItem.dataset.label.includes(' ds.label === 'Win Probability'); if (wpDataset && wpDataset.segmentColors) { wpDataset.segment = { borderColor: function(ctx) { // Use p1DataIndex (ending point) so the line inherits the destination color // This makes momentum shifts more visually intuitive const index = ctx.p1DataIndex; if (index !== undefined && wpDataset.segmentColors[index]) { return wpDataset.segmentColors[index]; } return wpDataset.borderColor || '#8B0000'; } }; } } // Initialize the chart const ctx = canvas.getContext('2d'); const chart = new Chart(ctx, { type: 'bar', data: chartData, options: chartOptions }); // Store reference to prevent re-initialization canvas.chartInstance = chart; console.log('CFB Chart initialized successfully'); } catch (error) { console.error('Error initializing CFB chart:', error); // Fallback: show error message in canvas container const container = document.getElementById('cfb-chart-1767325551088-1bmysvksy').parentNode; if (container) { container.innerHTML = '
Chart failed to load. Please refresh the page.
'; } } } // Start loading scripts sequentially function startLoading() { // First, check if scripts are already loaded (multiple embeds on same page) if (typeof Chart !== 'undefined' && typeof ChartDataLabels !== 'undefined') { initChart(); return; } // Load Chart.js first if (typeof Chart === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js', function() { // Then load ChartDataLabels if (typeof ChartDataLabels === 'undefined') { loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } }); } else if (typeof ChartDataLabels === 'undefined') { // Chart.js loaded but not ChartDataLabels loadScript('https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0', function() { initChart(); }); } else { initChart(); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startLoading); } else { startLoading(); } })();
Finally, this chart is not exactly inspiring either, but a few receivers had respectable days.
- Notably, Ryan Williams caught (!) some footballs and put up 4 successful catches (with 1 explosive)
- Josh Cuevas was a low-volume but high-impact hero again
- Germie Bernard pulled in 2 explosives (3 total successful catches) of his own.
- The running backs … caught some passes. they largely did not work. (Too bad Riley couldn’t pull in the one RB screen that was looking really promising).
The rest of the charts from this miserable game are here, by the way.
And that’s all I’ve got. Folks, I’m as mad as the next Gump, but it is paramount to remind ourselves that it’s just football. And, especially, that our Alabama Crimson Tide fanbase is freshly into a post-Saban world — with the transfer portal; with the NIL; with the “I hope he’s a good one” coaching hires — and that things are just gonna be kinda tough for a bit.
Heck, after the Florida State game — I told you it wasn’t that bad; I told you we could still make a season out of 2025 — we should be proud to have even made the Playoff and the SECCG game. But when you make it to those games, you play really good teams; and when you play those teams, sometimes you get spanked. (Just ask Ohio State and Clemson during the 4-team Playoff years, or even NFL teams … even good teams are capable of putting up big wins and big losses).
In the offseason, I’m excited to share more things I’m working on in the land of Graphing the Tide, starting with that work around Team Trends. You’ll hear from me more — especially on the RBR Feed — and by the first kickoff in 2026, we’ll have even more data visualization to look at together.
But, as I saw after every loss, Roll Tide anyway. This season had moments of great frustration, but also moments of great surprise and joy. Thus is football; maybe we’ll win the next one.