{"id":6554,"date":"2025-08-29T11:10:59","date_gmt":"2025-08-29T04:10:59","guid":{"rendered":"https:\/\/sport.mcu.ac.th\/?page_id=6554"},"modified":"2025-08-29T12:02:06","modified_gmt":"2025-08-29T05:02:06","slug":"%e0%b8%a7%e0%b8%87%e0%b8%a5%e0%b9%89%e0%b8%ad%e0%b8%aa%e0%b8%b8%e0%b9%88%e0%b8%a1%e0%b8%95%e0%b8%b2%e0%b8%a3%e0%b8%b2%e0%b8%87%e0%b9%81%e0%b8%9a%e0%b9%88%e0%b8%87%e0%b8%aa%e0%b8%b2%e0%b8%a2%e0%b8%81","status":"publish","type":"page","link":"https:\/\/sport.mcu.ac.th\/?page_id=6554","title":{"rendered":"\u0e27\u0e07\u0e25\u0e49\u0e2d\u0e2a\u0e38\u0e48\u0e21\u0e15\u0e32\u0e23\u0e32\u0e07\u0e41\u0e1a\u0e48\u0e07\u0e2a\u0e32\u0e22\u0e01\u0e35\u0e2c\u0e32"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"th\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>\u0e27\u0e07\u0e25\u0e49\u0e2d\u0e2a\u0e38\u0e48\u0e21\u0e15\u0e32\u0e23\u0e32\u0e07\u0e41\u0e1a\u0e48\u0e07\u0e2a\u0e32\u0e22\u0e01\u0e35\u0e2c\u0e32<\/title>\n    \n    <!-- Tailwind CSS via CDN -->\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    \n    <!-- Google Fonts: Mitr -->\n    <link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n    <link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Mitr:wght@400;600&#038;display=swap\" rel=\"stylesheet\">\n    \n    <!-- Tone.js for Sound Effects -->\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/tone\/14.7.77\/Tone.min.js\"><\/script>\n    \n    <!-- SheetJS (xlsx) for Excel file reading -->\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/xlsx\/0.18.5\/xlsx.full.min.js\"><\/script>\n\n    <!-- Canvas-Confetti for Celebration Effect -->\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/canvas-confetti@1.6.0\/dist\/confetti.browser.min.js\"><\/script>\n\n    <style>\n        body {\n            font-family: 'Mitr', sans-serif;\n            background-color: #FFF0F5; \/* Lavender Blush - a soft pink pastel *\/\n        }\n        .wheel-pointer {\n            width: 0;\n            height: 0;\n            border-left: 20px solid transparent;\n            border-right: 20px solid transparent;\n            border-top: 30px solid #FF69B4; \/* Hot Pink *\/\n            position: absolute;\n            top: -10px;\n            left: 50%;\n            transform: translateX(-50%);\n            z-index: 10;\n            filter: drop-shadow(0 2px 2px rgba(0,0,0,0.2));\n        }\n        .hidden-file-input {\n            width: 0.1px;\n            height: 0.1px;\n            opacity: 0;\n            overflow: hidden;\n            position: absolute;\n            z-index: -1;\n        }\n        canvas {\n            width: 100%;\n            height: 100%;\n        }\n    <\/style>\n<\/head>\n<body class=\"text-gray-700\">\n\n    <div class=\"container mx-auto p-4 md:p-8\">\n        <header class=\"text-center mb-8\">\n            <h1 class=\"text-4xl md:text-5xl font-bold text-pink-500\">\u0e27\u0e07\u0e25\u0e49\u0e2d\u0e2a\u0e38\u0e48\u0e21\u0e15\u0e32\u0e23\u0e32\u0e07\u0e41\u0e1a\u0e48\u0e07\u0e2a\u0e32\u0e22\u0e01\u0e35\u0e2c\u0e32<\/h1>\n            <p class=\"text-lg text-gray-500 mt-2\">\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e2a\u0e32\u0e22\u0e01\u0e32\u0e23\u0e41\u0e02\u0e48\u0e07\u0e02\u0e31\u0e19\u0e41\u0e25\u0e30\u0e17\u0e35\u0e21 \u0e41\u0e25\u0e49\u0e27\u0e21\u0e32\u0e2b\u0e21\u0e38\u0e19\u0e27\u0e07\u0e25\u0e49\u0e2d\u0e41\u0e2b\u0e48\u0e07\u0e42\u0e0a\u0e04\u0e0a\u0e30\u0e15\u0e32\u0e01\u0e31\u0e19!<\/p>\n        <\/header>\n\n        <main class=\"flex flex-col lg:flex-row justify-center items-start gap-8\">\n            <!-- Wheel 1: Groups -->\n            <div class=\"w-full lg:w-1\/2 bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center\">\n                <h2 class=\"text-2xl font-semibold mb-4 text-pink-600\">\u0e27\u0e07\u0e25\u0e49\u0e2d\u0e2a\u0e32\u0e22 \/ \u0e01\u0e25\u0e38\u0e48\u0e21<\/h2>\n                <div class=\"relative w-full max-w-sm aspect-square mb-4\">\n                    <div class=\"wheel-pointer\"><\/div>\n                    <canvas id=\"wheelCanvas1\"><\/canvas>\n                <\/div>\n                <div class=\"w-full mt-6\">\n                    <div class=\"flex gap-2 mb-4\">\n                        <input type=\"text\" id=\"optionInput1\" placeholder=\"\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e2a\u0e32\u0e22 A1, A2, A3, B1, B2, B3,...\" class=\"flex-grow p-3 border-2 border-gray-200 rounded-lg focus:ring-2 focus:ring-pink-400 focus:border-transparent outline-none transition\">\n                        <button id=\"addButton1\" class=\"bg-pink-500 text-white w-12 h-12 rounded-lg text-2xl font-bold hover:bg-pink-600 transition-colors shadow\">+<\/button>\n                    <\/div>\n                    <div class=\"bg-gray-50 p-4 rounded-lg max-h-48 overflow-y-auto\">\n                        <h3 class=\"font-semibold mb-2\">\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e2a\u0e32\u0e22\/\u0e01\u0e25\u0e38\u0e48\u0e21:<\/h3>\n                        <div id=\"optionsList1\"><\/div>\n                    <\/div>\n                     <div class=\"mt-4\">\n                        <input type=\"file\" id=\"fileInput1\" class=\"hidden-file-input\" accept=\".txt,.xlsx\">\n                        <label for=\"fileInput1\" class=\"w-full text-center cursor-pointer bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-lg transition-colors block\">\n                            \u0e19\u0e33\u0e40\u0e02\u0e49\u0e32\u0e44\u0e1f\u0e25\u0e4c\n                        <\/label>\n                    <\/div>\n                <\/div>\n            <\/div>\n\n            <!-- Wheel 2: Teams -->\n            <div class=\"w-full lg:w-1\/2 bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center\">\n                <h2 class=\"text-2xl font-semibold mb-4 text-indigo-600\">\u0e27\u0e07\u0e25\u0e49\u0e2d\u0e17\u0e35\u0e21<\/h2>\n                <div class=\"relative w-full max-w-sm aspect-square mb-4\">\n                    <div class=\"wheel-pointer\" style=\"border-top-color: #4F46E5;\"><\/div>\n                    <canvas id=\"wheelCanvas2\"><\/canvas>\n                <\/div>\n                <div class=\"w-full mt-6\">\n                    <div class=\"flex gap-2 mb-4\">\n                        <input type=\"text\" id=\"optionInput2\" placeholder=\"\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e0a\u0e37\u0e48\u0e2d\u0e17\u0e35\u0e21 (\u0e2b\u0e23\u0e37\u0e2d\u0e0a\u0e37\u0e48\u0e2d\u0e2a\u0e35) \u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e1f\u0e49\u0e32, \u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e19\u0e49\u0e33\u0e40\u0e07\u0e34\u0e19, \u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e21\u0e48\u0e27\u0e07, \u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e40\u0e2b\u0e25\u0e37\u0e2d\u0e07, \u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e40\u0e02\u0e35\u0e22\u0e27, \u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e2a\u0e49\u0e21,...\" class=\"flex-grow p-3 border-2 border-gray-200 rounded-lg focus:ring-2 focus:ring-indigo-400 focus:border-transparent outline-none transition\">\n                        <button id=\"addButton2\" class=\"bg-indigo-500 text-white w-12 h-12 rounded-lg text-2xl font-bold hover:bg-indigo-600 transition-colors shadow\">+<\/button>\n                    <\/div>\n                    <div class=\"bg-gray-50 p-4 rounded-lg max-h-48 overflow-y-auto\">\n                        <h3 class=\"font-semibold mb-2\">\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e17\u0e35\u0e21:<\/h3>\n                        <div id=\"optionsList2\"><\/div>\n                    <\/div>\n                    <div class=\"mt-4\">\n                        <input type=\"file\" id=\"fileInput2\" class=\"hidden-file-input\" accept=\".txt,.xlsx\">\n                        <label for=\"fileInput2\" class=\"w-full text-center cursor-pointer bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-lg transition-colors block\">\n                            \u0e19\u0e33\u0e40\u0e02\u0e49\u0e32\u0e44\u0e1f\u0e25\u0e4c\n                        <\/label>\n                    <\/div>\n                <\/div>\n            <\/div>\n        <\/main>\n\n        <div class=\"text-center my-8\">\n            <button id=\"mainSpinButton\" class=\"bg-gradient-to-r from-green-400 to-blue-500 hover:from-green-500 hover:to-blue-600 text-white font-bold text-3xl py-5 px-12 rounded-full shadow-xl transform hover:scale-105 transition-transform duration-200 disabled:opacity-50 disabled:cursor-not-allowed\">\n                \u0e40\u0e23\u0e34\u0e48\u0e21\u0e08\u0e31\u0e1a\u0e2a\u0e25\u0e32\u0e01\n            <\/button>\n        <\/div>\n\n        <div id=\"resultsContainer\" class=\"w-full max-w-4xl mx-auto bg-white rounded-2xl shadow-lg p-6 mb-8 hidden\">\n            <h2 class=\"text-2xl font-semibold mb-4 text-center text-gray-700\">\u0e1c\u0e25\u0e01\u0e32\u0e23\u0e08\u0e31\u0e1a\u0e2a\u0e25\u0e32\u0e01<\/h2>\n            <div class=\"overflow-x-auto\">\n                <table class=\"w-full text-left min-w-full\">\n                    <thead>\n                        <tr class=\"bg-gray-100 border-b\">\n                            <th class=\"p-3 font-semibold text-gray-600\">\u0e01\u0e25\u0e38\u0e48\u0e21 \/ \u0e2a\u0e32\u0e22<\/th>\n                            <th class=\"p-3 font-semibold text-gray-600\">\u0e17\u0e35\u0e21<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody id=\"resultsBody\">\n                        <!-- Results will be injected here -->\n                    <\/tbody>\n                <\/table>\n            <\/div>\n        <\/div>\n        \n        <footer class=\"text-center mt-8\">\n            <button id=\"resetAllButton\" class=\"bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-6 rounded-lg transition-colors\">\n                \u0e40\u0e23\u0e34\u0e48\u0e21\u0e43\u0e2b\u0e21\u0e48\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14\n            <\/button>\n        <\/footer>\n    <\/div>\n\n    <!-- Result Modal -->\n    <div id=\"resultModal\" class=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden\">\n        <div class=\"bg-white rounded-2xl shadow-2xl p-8 text-center relative transform scale-95 transition-transform duration-300 w-11\/12 max-w-md\">\n            <canvas id=\"confettiCanvas\" class=\"absolute top-0 left-0 w-full h-full pointer-events-none\"><\/canvas>\n            <h2 class=\"text-2xl font-bold mb-4\">\u0e08\u0e31\u0e1a\u0e2a\u0e25\u0e32\u0e01\u0e2a\u0e33\u0e40\u0e23\u0e47\u0e08!<\/h2>\n            <div id=\"resultText\" class=\"text-center mb-8\"><\/div>\n            <button id=\"closeResultModal\" class=\"bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-6 rounded-lg transition-colors\">\u0e1b\u0e34\u0e14<\/button>\n        <\/div>\n    <\/div>\n\n    <!-- Confirm Reset Modal -->\n    <div id=\"confirmModal\" class=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden\">\n        <div class=\"bg-white rounded-2xl shadow-2xl p-8 text-center transform scale-95 transition-transform duration-300 w-11\/12 max-w-sm\">\n            <h2 class=\"text-xl font-bold mb-4\">\u0e22\u0e37\u0e19\u0e22\u0e31\u0e19\u0e01\u0e32\u0e23\u0e25\u0e1a<\/h2>\n            <p class=\"text-gray-600 mb-6\">\u0e04\u0e38\u0e13\u0e41\u0e19\u0e48\u0e43\u0e08\u0e2b\u0e23\u0e37\u0e2d\u0e44\u0e21\u0e48\u0e27\u0e48\u0e32\u0e15\u0e49\u0e2d\u0e07\u0e01\u0e32\u0e23\u0e25\u0e49\u0e32\u0e07\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e41\u0e25\u0e30\u0e1c\u0e25\u0e01\u0e32\u0e23\u0e08\u0e31\u0e1a\u0e2a\u0e25\u0e32\u0e01\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14? \u0e01\u0e32\u0e23\u0e01\u0e23\u0e30\u0e17\u0e33\u0e19\u0e35\u0e49\u0e44\u0e21\u0e48\u0e2a\u0e32\u0e21\u0e32\u0e23\u0e16\u0e22\u0e49\u0e2d\u0e19\u0e01\u0e25\u0e31\u0e1a\u0e44\u0e14\u0e49<\/p>\n            <div class=\"flex justify-center gap-4\">\n                <button id=\"cancelReset\" class=\"bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-6 rounded-lg transition-colors\">\u0e22\u0e01\u0e40\u0e25\u0e34\u0e01<\/button>\n                <button id=\"confirmReset\" class=\"bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-6 rounded-lg transition-colors\">\u0e22\u0e37\u0e19\u0e22\u0e31\u0e19<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <script>\n        document.addEventListener('DOMContentLoaded', () => {\n            const initialTeamData = [\n                { text: '\u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e1f\u0e49\u0e32', color: '#03a9f4' }, { text: '\u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e19\u0e49\u0e33\u0e40\u0e07\u0e34\u0e19', color: '#3f51b5' },\n                { text: '\u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e21\u0e48\u0e27\u0e07', color: '#9c27b0' }, { text: '\u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e40\u0e02\u0e35\u0e22\u0e27', color: '#558b2f' },\n                { text: '\u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e40\u0e2b\u0e25\u0e37\u0e2d\u0e07', color: '#ffeb3b' }, { text: '\u0e42\u0e0b\u0e19\u0e2a\u0e35\u0e2a\u0e49\u0e21', color: '#fb8c00' }\n            ];\n\n            const state = {\n                wheels: [\n                    {\n                        canvas: document.getElementById('wheelCanvas1'),\n                        optionInput: document.getElementById('optionInput1'),\n                        addButton: document.getElementById('addButton1'),\n                        optionsList: document.getElementById('optionsList1'),\n                        fileInput: document.getElementById('fileInput1'),\n                        options: ['\u0e2a\u0e32\u0e22 A1', '\u0e2a\u0e32\u0e22 A2', '\u0e2a\u0e32\u0e22 A3', '\u0e01\u0e25\u0e38\u0e48\u0e21 B1', '\u0e2a\u0e32\u0e22 B2', '\u0e2a\u0e32\u0e22 B3'],\n                        colors: ['#FFC0CB', '#ADD8E6', '#90EE90', '#FFD700', '#FFA07A', '#B0E0E6', '#DDA0DD', '#F0E68C'],\n                        isSpinning: false, rotation: 0, currentAngle: 0,\n                    },\n                    {\n                        canvas: document.getElementById('wheelCanvas2'),\n                        optionInput: document.getElementById('optionInput2'),\n                        addButton: document.getElementById('addButton2'),\n                        optionsList: document.getElementById('optionsList2'),\n                        fileInput: document.getElementById('fileInput2'),\n                        options: JSON.parse(JSON.stringify(initialTeamData)), \/\/ Deep copy\n                        colors: ['#87CEEB', '#3CB371', '#BA55D3', '#FF6347', '#4682B4', '#DB7093', '#6B8E23', '#D2B48C'],\n                        isSpinning: false, rotation: 0, currentAngle: 0,\n                    }\n                ],\n                drawResults: []\n            };\n\n            const mainSpinButton = document.getElementById('mainSpinButton');\n            const resetAllButton = document.getElementById('resetAllButton');\n            const resultModal = document.getElementById('resultModal');\n            const confirmModal = document.getElementById('confirmModal');\n            const resultText = document.getElementById('resultText');\n            const resultsContainer = document.getElementById('resultsContainer');\n            const resultsBody = document.getElementById('resultsBody');\n\n            let soundsReady = false;\n            let tickSynth, winSynth;\n            \n            if (typeof Tone !== 'undefined') {\n                try {\n                    tickSynth = new Tone.MembraneSynth().toDestination();\n                    winSynth = new Tone.PolySynth(Tone.Synth, { oscillator: { type: \"sine\" }, envelope: { attack: 0.005, decay: 0.1, sustain: 0.3, release: 1 } }).toDestination();\n                } catch (e) {\n                    console.warn(\"Tone.js is loaded, but failed to initialize synths. Sounds will be disabled.\", e);\n                    tickSynth = null; winSynth = null;\n                }\n            } else { console.log(\"Tone.js library not found or failed to load. Running in silent mode.\"); }\n            \n            const initAudio = () => {\n                if (tickSynth && !soundsReady) { Tone.start().then(() => { soundsReady = true; }); }\n                document.body.removeEventListener('click', initAudio);\n            };\n            document.body.addEventListener('click', initAudio);\n\n            const isValidCSSColor = (strColor) => {\n                const s = new Option().style;\n                s.color = strColor;\n                return s.color !== '';\n            };\n\n            const resizeAndDrawWheels = () => {\n                state.wheels.forEach((wheel, index) => {\n                    const canvas = wheel.canvas;\n                    const container = canvas.parentElement;\n                    const size = container.clientWidth;\n                    canvas.width = size;\n                    canvas.height = size;\n                    drawWheel(index);\n                });\n            };\n\n            const drawWheel = (wheelIndex) => {\n                const wheel = state.wheels[wheelIndex];\n                const { canvas, options, colors } = wheel;\n                if (!canvas) return;\n                const ctx = canvas.getContext('2d');\n                const numOptions = options.length;\n                const arcSize = numOptions > 0 ? (2 * Math.PI \/ numOptions) : 0;\n                const centerX = canvas.width \/ 2;\n                const centerY = canvas.height \/ 2;\n                const radius = centerX - 10;\n                ctx.clearRect(0, 0, canvas.width, canvas.height);\n                if (numOptions === 0) {\n                    ctx.textAlign = 'center';\n                    ctx.fillStyle = '#999';\n                    ctx.font = `bold ${canvas.width * 0.05}px Mitr`;\n                    ctx.fillText('\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e15\u0e31\u0e27\u0e40\u0e25\u0e37\u0e2d\u0e01...', centerX, centerY);\n                    return;\n                }\n                ctx.save();\n                ctx.translate(centerX, centerY);\n                ctx.rotate(wheel.rotation);\n                ctx.translate(-centerX, -centerY);\n                for (let i = 0; i < numOptions; i++) {\n                    const option = options[i];\n                    const angle = i * arcSize;\n                    const isTeamWheel = typeof option === 'object';\n                    \n                    ctx.beginPath();\n                    ctx.fillStyle = isTeamWheel ? option.color : colors[i % colors.length];\n                    ctx.moveTo(centerX, centerY);\n                    ctx.arc(centerX, centerY, radius, angle, angle + arcSize);\n                    ctx.closePath();\n                    ctx.fill();\n                    ctx.strokeStyle = '#FFFFFF';\n                    ctx.lineWidth = 3;\n                    ctx.stroke();\n                    ctx.save();\n                    ctx.translate(centerX, centerY);\n                    ctx.rotate(angle + arcSize \/ 2);\n                    ctx.textAlign = 'right';\n                    ctx.fillStyle = '#333';\n                    const fontSize = Math.min(18, canvas.width \/ 25);\n                    ctx.font = `bold ${numOptions > 12 ? fontSize * 0.8 : fontSize}px Mitr`;\n                    const textToDraw = isTeamWheel ? option.text : option;\n                    ctx.fillText(textToDraw, radius - 15, fontSize \/ 2);\n                    ctx.restore();\n                }\n                ctx.restore();\n            };\n\n            const updateOptionsList = (wheelIndex) => {\n                const wheel = state.wheels[wheelIndex];\n                wheel.optionsList.innerHTML = '';\n                if (wheel.options.length === 0) {\n                    wheel.optionsList.innerHTML = '<p class=\"text-gray-400 text-center\">\u0e22\u0e31\u0e07\u0e44\u0e21\u0e48\u0e21\u0e35\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23...<\/p>';\n                } else {\n                    wheel.options.forEach((option, index) => {\n                        const isTeamWheel = typeof option === 'object';\n                        const text = isTeamWheel ? option.text : option;\n                        const item = document.createElement('div');\n                        item.className = 'flex justify-between items-center bg-white p-2 rounded-md mb-2 shadow-sm';\n                        item.innerHTML = `<span class=\"truncate\">${text}<\/span><button data-index=\"${index}\" class=\"delete-btn text-red-500 hover:text-red-700 font-bold text-lg w-6 h-6 flex items-center justify-center rounded-full hover:bg-red-100\">&times;<\/button>`;\n                        wheel.optionsList.appendChild(item);\n                    });\n                }\n                wheel.optionsList.querySelectorAll('.delete-btn').forEach(btn => {\n                    btn.addEventListener('click', () => deleteOption(wheelIndex, parseInt(btn.dataset.index)));\n                });\n                updateMainSpinButtonState();\n            };\n\n            const addOption = (wheelIndex) => {\n                const wheel = state.wheels[wheelIndex];\n                const newOptionText = wheel.optionInput.value.trim();\n                if (!newOptionText) return;\n\n                if (wheelIndex === 1) { \/\/ Team wheel with dynamic color\n                    const newColor = isValidCSSColor(newOptionText.toLowerCase()) ? newOptionText.toLowerCase() : wheel.colors[wheel.options.length % wheel.colors.length];\n                    wheel.options.push({ text: newOptionText, color: newColor });\n                } else { \/\/ Group wheel\n                    wheel.options.push(newOptionText);\n                }\n                wheel.optionInput.value = '';\n                updateAndDraw(wheelIndex);\n            };\n\n            const deleteOption = (wheelIndex, optionIndex) => {\n                state.wheels[wheelIndex].options.splice(optionIndex, 1);\n                updateAndDraw(wheelIndex);\n            };\n\n            const handleFile = (e, wheelIndex) => {\n                const file = e.target.files[0];\n                if (!file) return;\n                const reader = new FileReader();\n                const wheel = state.wheels[wheelIndex];\n                \n                const processLines = (lines) => {\n                    const newOptions = lines.filter(line => line.trim() !== '');\n                    if (wheelIndex === 1) { \/\/ Team wheel\n                        const teamObjects = newOptions.map(text => {\n                            const color = isValidCSSColor(text.toLowerCase()) ? text.toLowerCase() : wheel.colors[(wheel.options.length + wheel.options.length) % wheel.colors.length];\n                            return { text, color };\n                        });\n                        wheel.options.push(...teamObjects);\n                    } else { \/\/ Group wheel\n                        wheel.options.push(...newOptions);\n                    }\n                    updateAndDraw(wheelIndex);\n                };\n\n                if (file.name.endsWith('.txt')) {\n                    reader.onload = (event) => processLines(event.target.result.split('\\n'));\n                    reader.readAsText(file);\n                } else if (file.name.endsWith('.xlsx')) {\n                    reader.onload = (event) => {\n                        const data = new Uint8Array(event.target.result);\n                        const workbook = XLSX.read(data, { type: 'array' });\n                        const worksheet = workbook.Sheets[workbook.SheetNames[0]];\n                        const json = XLSX.utils.sheet_to_json(worksheet, { header: 1 });\n                        const lines = json.map(row => row[0]).filter(cell => cell != null);\n                        processLines(lines.map(String));\n                    };\n                    reader.readAsArrayBuffer(file);\n                }\n                e.target.value = '';\n            };\n\n            const spinWheel = (wheelIndex) => {\n                return new Promise(resolve => {\n                    const wheel = state.wheels[wheelIndex];\n                    wheel.isSpinning = true;\n                    const spinDuration = 5000 + Math.random() * 1000;\n                    const spinRotations = 5 + Math.random() * 5;\n                    const totalAngle = spinRotations * 2 * Math.PI;\n                    const randomStopOffset = Math.random() * (2 * Math.PI \/ wheel.options.length);\n                    const finalAngle = totalAngle + randomStopOffset;\n                    let start = null;\n                    let lastTickAngle = wheel.rotation;\n                    const animate = (timestamp) => {\n                        if (!start) start = timestamp;\n                        const progress = timestamp - start;\n                        const t = Math.min(progress \/ spinDuration, 1);\n                        const easedT = 1 - Math.pow(1 - t, 3);\n                        const currentAngle = easedT * finalAngle;\n                        wheel.rotation = wheel.currentAngle + currentAngle;\n                        const arcSize = 2 * Math.PI \/ wheel.options.length;\n                        if (Math.floor(wheel.rotation \/ arcSize) > Math.floor(lastTickAngle \/ arcSize)) {\n                            if (soundsReady && tickSynth) tickSynth.triggerAttackRelease(\"C2\", \"8n\", Tone.now(), 0.1);\n                        }\n                        lastTickAngle = wheel.rotation;\n                        drawWheel(wheelIndex);\n                        if (progress < spinDuration) {\n                            requestAnimationFrame(animate);\n                        } else {\n                            wheel.currentAngle = wheel.rotation % (2 * Math.PI);\n                            const winningAngle = (2 * Math.PI) - (wheel.currentAngle % (2 * Math.PI));\n                            const winnerIndex = Math.floor(winningAngle \/ arcSize);\n                            resolve({ winner: wheel.options[winnerIndex], winnerIndex: winnerIndex });\n                        }\n                    };\n                    requestAnimationFrame(animate);\n                });\n            };\n            \n            const setControlsEnabled = (enabled) => {\n                mainSpinButton.disabled = !enabled;\n                resetAllButton.disabled = !enabled;\n                document.querySelectorAll('input, button[id^=\"add\"], label[for^=\"fileInput\"]').forEach(el => {\n                    el.style.pointerEvents = enabled ? 'auto' : 'none';\n                    if(el.tagName === 'INPUT' || el.tagName === 'BUTTON') {\n                        el.disabled = !enabled;\n                    }\n                });\n                if (enabled) { updateMainSpinButtonState(); }\n            };\n\n            const startDraw = async () => {\n                if (state.wheels[0].isSpinning || state.wheels[1].isSpinning) return;\n                setControlsEnabled(false);\n                const [groupResult, teamResult] = await Promise.all([spinWheel(0), spinWheel(1)]);\n                processDrawResults(groupResult, teamResult);\n            };\n\n            const processDrawResults = (groupResult, teamResult) => {\n                state.drawResults.push({ group: groupResult.winner, team: teamResult.winner.text });\n                updateResultsTable();\n                showResult(groupResult.winner, teamResult.winner.text);\n\n                setTimeout(() => {\n                    \/\/ FIX: Remove both group and team\n                    state.wheels[0].options.splice(groupResult.winnerIndex, 1);\n                    state.wheels[1].options.splice(teamResult.winnerIndex, 1);\n                    \n                    [0, 1].forEach(i => {\n                        state.wheels[i].rotation = 0;\n                        state.wheels[i].currentAngle = 0;\n                        state.wheels[i].isSpinning = false;\n                        updateAndDraw(i);\n                    });\n                    \n                    setControlsEnabled(true);\n                }, 2000);\n            };\n            \n            const showResult = (group, team) => {\n                resultText.innerHTML = `\n                    <p class=\"text-lg text-gray-500\">\u0e01\u0e25\u0e38\u0e48\u0e21 \/ \u0e2a\u0e32\u0e22<\/p>\n                    <p class=\"text-3xl font-bold text-pink-500 mb-4\">${group}<\/p>\n                    <p class=\"text-lg text-gray-500\">\u0e17\u0e35\u0e21<\/p>\n                    <p class=\"text-3xl font-bold text-indigo-500\">${team}<\/p>\n                `;\n                resultModal.classList.remove('hidden');\n                setTimeout(() => resultModal.querySelector('div').classList.remove('scale-95'), 10);\n                if (soundsReady && winSynth) winSynth.triggerAttackRelease([\"C4\", \"E4\", \"G4\"], \"0.5s\");\n                const confettiCanvas = document.getElementById('confettiCanvas');\n                const myConfetti = confetti.create(confettiCanvas, { resize: true, useWorker: true });\n                myConfetti({ particleCount: 150, spread: 180, origin: { y: 0.6 } });\n            };\n\n            const updateResultsTable = () => {\n                if (state.drawResults.length > 0) {\n                    resultsContainer.classList.remove('hidden');\n                } else { resultsContainer.classList.add('hidden'); }\n                resultsBody.innerHTML = '';\n                state.drawResults.forEach(result => {\n                    const row = document.createElement('tr');\n                    row.className = 'border-b hover:bg-gray-50';\n                    row.innerHTML = `<td class=\"p-3\">${result.group}<\/td><td class=\"p-3\">${result.team}<\/td>`;\n                    resultsBody.appendChild(row);\n                });\n            };\n            \n            const resetAll = () => {\n                state.wheels[0].options = ['\u0e01\u0e25\u0e38\u0e48\u0e21 A', '\u0e01\u0e25\u0e38\u0e48\u0e21 B', '\u0e01\u0e25\u0e38\u0e48\u0e21 C', '\u0e01\u0e25\u0e38\u0e48\u0e21 D'];\n                state.wheels[1].options = JSON.parse(JSON.stringify(initialTeamData));\n                state.drawResults = [];\n                \n                state.wheels.forEach((wheel, index) => {\n                    wheel.rotation = 0;\n                    wheel.currentAngle = 0;\n                    updateAndDraw(index);\n                });\n\n                updateResultsTable();\n                setControlsEnabled(true);\n            };\n            \n            const updateAndDraw = (wheelIndex) => {\n                updateOptionsList(wheelIndex);\n                drawWheel(wheelIndex);\n            };\n\n            const updateMainSpinButtonState = () => {\n                mainSpinButton.disabled = state.wheels[0].options.length < 1 || state.wheels[1].options.length < 1;\n            };\n\n            \/\/ --- EVENT LISTENERS ---\n            state.wheels.forEach((wheel, index) => {\n                wheel.addButton.addEventListener('click', () => addOption(index));\n                wheel.optionInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') addOption(index); });\n                wheel.fileInput.addEventListener('change', (e) => handleFile(e, index));\n            });\n\n            mainSpinButton.addEventListener('click', startDraw);\n\n            resetAllButton.addEventListener('click', () => {\n                confirmModal.classList.remove('hidden');\n                setTimeout(() => confirmModal.querySelector('div').classList.remove('scale-95'), 10);\n            });\n            document.getElementById('closeResultModal').addEventListener('click', () => {\n                resultModal.querySelector('div').classList.add('scale-95');\n                setTimeout(() => resultModal.classList.add('hidden'), 300);\n            });\n            document.getElementById('cancelReset').addEventListener('click', () => {\n                confirmModal.querySelector('div').classList.add('scale-95');\n                setTimeout(() => confirmModal.classList.add('hidden'), 300);\n            });\n            document.getElementById('confirmReset').addEventListener('click', () => {\n                resetAll();\n                confirmModal.querySelector('div').classList.add('scale-95');\n                setTimeout(() => confirmModal.classList.add('hidden'), 300);\n            });\n            \n            resizeAndDrawWheels();\n            window.addEventListener('resize', resizeAndDrawWheels);\n            state.wheels.forEach((_, index) => updateAndDraw(index));\n        });\n    <\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>\u0e27\u0e07\u0e25\u0e49\u0e2d\u0e2a\u0e38\u0e48\u0e21\u0e15\u0e32\u0e23\u0e32\u0e07\u0e41\u0e1a\u0e48\u0e07\u0e2a\u0e32\u0e22\u0e01\u0e35\u0e2c\u0e32 \u0e27\u0e07\u0e25\u0e49\u0e2d\u0e2a\u0e38\u0e48\u0e21\u0e15\u0e32\u0e23\u0e32\u0e07\u0e41\u0e1a\u0e48\u0e07\u0e2a\u0e32\u0e22\u0e01\u0e35\u0e2c\u0e32 \u0e40\u0e1e\u0e34 [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_seopress_robots_primary_cat":"","_seopress_titles_title":"","_seopress_titles_desc":"","_seopress_robots_index":"","footnotes":""},"_links":{"self":[{"href":"https:\/\/sport.mcu.ac.th\/index.php?rest_route=\/wp\/v2\/pages\/6554"}],"collection":[{"href":"https:\/\/sport.mcu.ac.th\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/sport.mcu.ac.th\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/sport.mcu.ac.th\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sport.mcu.ac.th\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6554"}],"version-history":[{"count":5,"href":"https:\/\/sport.mcu.ac.th\/index.php?rest_route=\/wp\/v2\/pages\/6554\/revisions"}],"predecessor-version":[{"id":6562,"href":"https:\/\/sport.mcu.ac.th\/index.php?rest_route=\/wp\/v2\/pages\/6554\/revisions\/6562"}],"wp:attachment":[{"href":"https:\/\/sport.mcu.ac.th\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6554"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}