|
<!DOCTYPE html> |
|
<html lang="zh-CN"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>阳光点名转盘</title> |
|
<style> |
|
:root { |
|
--primary-color: #FF9E45; |
|
--secondary-color: #FFB347; |
|
--accent-color: #FF6B6B; |
|
--light-color: #FFF8E6; |
|
--text-color: #3D3D3D; |
|
--shadow-color: rgba(255, 158, 69, 0.3); |
|
} |
|
|
|
* { |
|
margin: 0; |
|
padding: 0; |
|
box-sizing: border-box; |
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|
} |
|
|
|
body { |
|
background: linear-gradient(135deg, var(--light-color) 0%, #FFE8CC 100%); |
|
color: var(--text-color); |
|
min-height: 100vh; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
padding: 2rem; |
|
} |
|
|
|
.container { |
|
max-width: 1200px; |
|
width: 100%; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
gap: 2rem; |
|
} |
|
|
|
header { |
|
text-align: center; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
h1 { |
|
font-size: 2.5rem; |
|
color: var(--primary-color); |
|
text-shadow: 2px 2px 4px var(--shadow-color); |
|
margin-bottom: 0.5rem; |
|
} |
|
|
|
.subtitle { |
|
font-size: 1.2rem; |
|
color: var(--accent-color); |
|
font-weight: 300; |
|
} |
|
|
|
.setup-panel { |
|
background-color: white; |
|
padding: 2rem; |
|
border-radius: 1rem; |
|
box-shadow: 0 10px 30px var(--shadow-color); |
|
width: 100%; |
|
max-width: 500px; |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.setup-panel.minimized { |
|
padding: 1rem; |
|
max-width: 300px; |
|
cursor: pointer; |
|
} |
|
|
|
.setup-panel.minimized .form-group { |
|
display: none; |
|
} |
|
|
|
.setup-panel.minimized .panel-title:after { |
|
content: " (点击展开)"; |
|
font-size: 0.8rem; |
|
color: var(--accent-color); |
|
} |
|
|
|
.panel-title { |
|
text-align: center; |
|
margin-bottom: 1.5rem; |
|
color: var(--primary-color); |
|
} |
|
|
|
.form-group { |
|
margin-bottom: 1.5rem; |
|
} |
|
|
|
label { |
|
display: block; |
|
margin-bottom: 0.5rem; |
|
font-weight: 500; |
|
} |
|
|
|
input, select { |
|
width: 100%; |
|
padding: 0.8rem; |
|
border: 2px solid #FFD8B1; |
|
border-radius: 0.5rem; |
|
font-size: 1rem; |
|
background-color: var(--light-color); |
|
transition: all 0.3s; |
|
} |
|
|
|
input:focus, select:focus { |
|
outline: none; |
|
border-color: var(--primary-color); |
|
box-shadow: 0 0 0 3px var(--shadow-color); |
|
} |
|
|
|
.btn { |
|
background-color: var(--primary-color); |
|
color: white; |
|
border: none; |
|
padding: 0.8rem 1.5rem; |
|
border-radius: 0.5rem; |
|
font-size: 1rem; |
|
font-weight: 600; |
|
cursor: pointer; |
|
transition: all 0.3s; |
|
box-shadow: 0 4px 10px var(--shadow-color); |
|
} |
|
|
|
.btn:hover { |
|
background-color: var(--accent-color); |
|
transform: translateY(-2px); |
|
box-shadow: 0 6px 15px var(--shadow-color); |
|
} |
|
|
|
.btn-secondary { |
|
background-color: var(--light-color); |
|
color: var(--primary-color); |
|
border: 2px solid var(--primary-color); |
|
} |
|
|
|
.btn-secondary:hover { |
|
background-color: var(--primary-color); |
|
color: white; |
|
} |
|
|
|
.actions { |
|
display: flex; |
|
justify-content: center; |
|
gap: 1rem; |
|
} |
|
|
|
.wheel-container { |
|
position: relative; |
|
width: 100%; |
|
max-width: 600px; |
|
aspect-ratio: 1; |
|
margin: 2rem 0; |
|
display: none; |
|
} |
|
|
|
.wheel { |
|
width: 100%; |
|
height: 100%; |
|
position: relative; |
|
border-radius: 50%; |
|
overflow: hidden; |
|
box-shadow: 0 0 30px var(--shadow-color), 0 0 60px rgba(255, 214, 102, 0.6); |
|
transition: box-shadow 0.3s; |
|
} |
|
|
|
.wheel-inner { |
|
width: 100%; |
|
height: 100%; |
|
border-radius: 50%; |
|
position: relative; |
|
transition: transform 5s cubic-bezier(0.1, 0.05, 0.1, 1.0); |
|
} |
|
|
|
.segment { |
|
position: absolute; |
|
width: 50%; |
|
height: 50%; |
|
transform-origin: bottom right; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
overflow: hidden; |
|
} |
|
|
|
.segment-content { |
|
position: absolute; |
|
left: 30px; |
|
width: 80px; |
|
text-align: center; |
|
transform: rotate(90deg); |
|
transform-origin: left; |
|
font-weight: bold; |
|
font-size: 0.9rem; |
|
color: rgba(255, 255, 255, 0.9); |
|
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.5); |
|
overflow: hidden; |
|
text-overflow: ellipsis; |
|
white-space: nowrap; |
|
} |
|
|
|
.wheel-pointer { |
|
position: absolute; |
|
top: -20px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
width: 40px; |
|
height: 60px; |
|
background-color: var(--accent-color); |
|
clip-path: polygon(50% 0%, 0% 100%, 100% 100%); |
|
z-index: 10; |
|
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.2)); |
|
} |
|
|
|
.wheel-center { |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 15%; |
|
height: 15%; |
|
background: radial-gradient(circle, var(--light-color) 0%, var(--primary-color) 100%); |
|
border-radius: 50%; |
|
z-index: 5; |
|
box-shadow: 0 0 15px var(--shadow-color); |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
color: white; |
|
font-weight: bold; |
|
font-size: 1.2rem; |
|
cursor: pointer; |
|
} |
|
|
|
.wheel-center:hover { |
|
box-shadow: 0 0 20px var(--accent-color); |
|
} |
|
|
|
.wheel-center:after { |
|
content: ""; |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 70%; |
|
height: 70%; |
|
background-color: var(--accent-color); |
|
border-radius: 50%; |
|
z-index: -1; |
|
} |
|
|
|
.result-display { |
|
background-color: white; |
|
padding: 2rem; |
|
border-radius: 1rem; |
|
box-shadow: 0 10px 30px var(--shadow-color); |
|
text-align: center; |
|
max-width: 500px; |
|
width: 100%; |
|
display: none; |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.result-display h2 { |
|
color: var(--primary-color); |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.result-number { |
|
font-size: 5rem; |
|
font-weight: bold; |
|
color: var(--accent-color); |
|
margin: 1rem 0; |
|
position: relative; |
|
transition: all 0.3s; |
|
} |
|
|
|
.result-text { |
|
font-size: 1.2rem; |
|
margin-bottom: 1.5rem; |
|
} |
|
|
|
.shine { |
|
position: absolute; |
|
top: 0; |
|
left: -100%; |
|
width: 50%; |
|
height: 100%; |
|
background: linear-gradient( |
|
90deg, |
|
rgba(255, 255, 255, 0) 0%, |
|
rgba(255, 255, 255, 0.8) 50%, |
|
rgba(255, 255, 255, 0) 100% |
|
); |
|
z-index: 10; |
|
animation: shine 2s infinite; |
|
opacity: 0; |
|
pointer-events: none; |
|
} |
|
|
|
.confetti { |
|
position: absolute; |
|
width: 10px; |
|
height: 10px; |
|
background-color: var(--primary-color); |
|
opacity: 0; |
|
pointer-events: none; |
|
} |
|
|
|
@keyframes shine { |
|
0% { |
|
left: -100%; |
|
opacity: 0; |
|
} |
|
10% { |
|
opacity: 1; |
|
} |
|
50% { |
|
left: 100%; |
|
opacity: 1; |
|
} |
|
51% { |
|
opacity: 0; |
|
} |
|
100% { |
|
opacity: 0; |
|
} |
|
} |
|
|
|
.spinning .wheel { |
|
box-shadow: 0 0 50px var(--accent-color), 0 0 100px rgba(255, 214, 102, 0.8); |
|
} |
|
|
|
@media (max-width: 768px) { |
|
h1 { |
|
font-size: 2rem; |
|
} |
|
|
|
.container { |
|
gap: 1rem; |
|
} |
|
|
|
.setup-panel, .result-display { |
|
padding: 1.5rem; |
|
} |
|
|
|
.result-number { |
|
font-size: 3.5rem; |
|
} |
|
} |
|
|
|
.mode-description { |
|
display: none; |
|
margin-top: 0.5rem; |
|
font-size: 0.85rem; |
|
color: var(--accent-color); |
|
font-style: italic; |
|
} |
|
|
|
.special-effects { |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
pointer-events: none; |
|
z-index: 20; |
|
} |
|
|
|
.flicker { |
|
animation: flicker 0.2s infinite; |
|
} |
|
|
|
@keyframes flicker { |
|
0% { opacity: 1; } |
|
50% { opacity: 0.7; } |
|
100% { opacity: 1; } |
|
} |
|
|
|
.shake { |
|
animation: shake 0.1s infinite; |
|
} |
|
|
|
@keyframes shake { |
|
0% { transform: translateX(0); } |
|
25% { transform: translateX(-5px); } |
|
50% { transform: translateX(0); } |
|
75% { transform: translateX(5px); } |
|
100% { transform: translateX(0); } |
|
} |
|
|
|
.jump { |
|
animation: jump 0.5s; |
|
} |
|
|
|
@keyframes jump { |
|
0% { transform: scale(1); } |
|
50% { transform: scale(1.2); } |
|
100% { transform: scale(1); } |
|
} |
|
|
|
.help-bubble { |
|
position: fixed; |
|
bottom: 20px; |
|
right: 20px; |
|
background-color: var(--primary-color); |
|
color: white; |
|
width: 50px; |
|
height: 50px; |
|
border-radius: 50%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
font-size: 1.5rem; |
|
cursor: pointer; |
|
box-shadow: 0 3px 10px var(--shadow-color); |
|
transition: all 0.3s; |
|
} |
|
|
|
.help-bubble:hover { |
|
background-color: var(--accent-color); |
|
transform: scale(1.1); |
|
} |
|
|
|
.help-content { |
|
position: fixed; |
|
bottom: 80px; |
|
right: 20px; |
|
background-color: white; |
|
padding: 1.5rem; |
|
border-radius: 1rem; |
|
width: 300px; |
|
box-shadow: 0 10px 30px var(--shadow-color); |
|
display: none; |
|
z-index: 100; |
|
} |
|
|
|
.help-content h3 { |
|
color: var(--primary-color); |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.help-content p { |
|
margin-bottom: 0.8rem; |
|
font-size: 0.9rem; |
|
} |
|
|
|
.close-help { |
|
position: absolute; |
|
top: 10px; |
|
right: 10px; |
|
font-size: 1.2rem; |
|
cursor: pointer; |
|
color: var(--accent-color); |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="container"> |
|
<header> |
|
<h1>阳光点名转盘</h1> |
|
<p class="subtitle">让点名充满乐趣和惊喜!</p> |
|
</header> |
|
|
|
<div class="setup-panel"> |
|
<h2 class="panel-title">设置</h2> |
|
<div class="form-group"> |
|
<label for="class-size">班级人数:</label> |
|
<input type="number" id="class-size" min="1" max="100" value="30"> |
|
</div> |
|
|
|
<div class="form-group"> |
|
<label for="start-number">起始编号 (默认从1开始):</label> |
|
<input type="number" id="start-number" min="0" value="1"> |
|
</div> |
|
|
|
<div class="form-group"> |
|
<label for="picker-mode">选择模式:</label> |
|
<select id="picker-mode"> |
|
<option value="normal">正常模式</option> |
|
<option value="fake-out">假动作模式</option> |
|
<option value="oscillate">摇摆不定模式</option> |
|
<option value="mystery">神秘模式</option> |
|
<option value="double">双重选择模式</option> |
|
</select> |
|
<div id="mode-normal" class="mode-description">普通的转盘选择,公平公正。</div> |
|
<div id="mode-fake-out" class="mode-description">即将停止时,转盘会突然改变方向!</div> |
|
<div id="mode-oscillate" class="mode-description">在两个结果之间反复摇摆,到底会是谁呢?</div> |
|
<div id="mode-mystery" class="mode-description">结果会短暂显示然后突然变化,充满惊喜!</div> |
|
<div id="mode-double" class="mode-description">同时选出两个幸运儿!</div> |
|
</div> |
|
|
|
<div class="actions"> |
|
<button id="start-btn" class="btn">开始点名</button> |
|
<button id="reset-btn" class="btn btn-secondary">重置</button> |
|
</div> |
|
</div> |
|
|
|
<div class="wheel-container"> |
|
<div class="wheel-pointer"></div> |
|
<div class="wheel"> |
|
<div class="wheel-inner" id="wheel-inner"></div> |
|
</div> |
|
<div class="wheel-center" id="spin-btn">转!</div> |
|
</div> |
|
|
|
<div class="result-display"> |
|
<div class="shine"></div> |
|
<h2>点名结果</h2> |
|
<div class="result-number" id="result-number">?</div> |
|
<p class="result-text" id="result-text">请点击转盘开始</p> |
|
<button id="spin-again-btn" class="btn">再来一次</button> |
|
</div> |
|
</div> |
|
|
|
<div class="help-bubble">?</div> |
|
<div class="help-content"> |
|
<span class="close-help">×</span> |
|
<h3>使用帮助</h3> |
|
<p><strong>正常模式:</strong> 普通的点名选择,公平公正。</p> |
|
<p><strong>假动作模式:</strong> 转盘减速后会有一次假动作,然后才会显示最终结果。</p> |
|
<p><strong>摇摆不定模式:</strong> 在两个选项之间来回摇摆,增加悬念感。</p> |
|
<p><strong>神秘模式:</strong> 先显示一个结果,然后突然改变!谁也猜不到最终会是谁。</p> |
|
<p><strong>双重选择模式:</strong> 同时选出两名同学,适合小组活动。</p> |
|
</div> |
|
|
|
<script> |
|
|
|
const setupPanel = document.querySelector('.setup-panel'); |
|
const classSizeInput = document.getElementById('class-size'); |
|
const startNumberInput = document.getElementById('start-number'); |
|
const pickerModeSelect = document.getElementById('picker-mode'); |
|
const startBtn = document.getElementById('start-btn'); |
|
const resetBtn = document.getElementById('reset-btn'); |
|
const wheelContainer = document.querySelector('.wheel-container'); |
|
const wheelInner = document.getElementById('wheel-inner'); |
|
const spinBtn = document.getElementById('spin-btn'); |
|
const resultDisplay = document.querySelector('.result-display'); |
|
const resultNumber = document.getElementById('result-number'); |
|
const resultText = document.getElementById('result-text'); |
|
const spinAgainBtn = document.getElementById('spin-again-btn'); |
|
const helpBubble = document.querySelector('.help-bubble'); |
|
const helpContent = document.querySelector('.help-content'); |
|
const closeHelp = document.querySelector('.close-help'); |
|
|
|
|
|
const modeDescriptions = { |
|
normal: document.getElementById('mode-normal'), |
|
'fake-out': document.getElementById('mode-fake-out'), |
|
oscillate: document.getElementById('mode-oscillate'), |
|
mystery: document.getElementById('mode-mystery'), |
|
double: document.getElementById('mode-double') |
|
}; |
|
|
|
|
|
let classSize = 30; |
|
let startNumber = 1; |
|
let mode = 'normal'; |
|
let isSpinning = false; |
|
let segments = []; |
|
let selectedSegment = null; |
|
let secondSelectedSegment = null; |
|
|
|
|
|
const colors = [ |
|
'#FF9E45', '#FFB347', '#FF8C42', '#FFC154', |
|
'#FF6B6B', '#FF9671', '#FFA25B', '#FFD56B', |
|
'#FFBB69', '#FFD166', '#FFC857', '#E9C46A', |
|
'#F4A261', '#FF7F50', '#FF8966', '#FFBA7C' |
|
]; |
|
|
|
|
|
function init() { |
|
|
|
startBtn.addEventListener('click', setupWheel); |
|
resetBtn.addEventListener('click', reset); |
|
spinBtn.addEventListener('click', spin); |
|
spinAgainBtn.addEventListener('click', () => { |
|
resultDisplay.style.display = 'none'; |
|
wheelContainer.style.display = 'block'; |
|
}); |
|
|
|
pickerModeSelect.addEventListener('change', updateModeDescription); |
|
|
|
helpBubble.addEventListener('click', () => { |
|
helpContent.style.display = 'block'; |
|
}); |
|
|
|
closeHelp.addEventListener('click', () => { |
|
helpContent.style.display = 'none'; |
|
}); |
|
|
|
|
|
updateModeDescription(); |
|
} |
|
|
|
function updateModeDescription() { |
|
const selectedMode = pickerModeSelect.value; |
|
|
|
|
|
Object.values(modeDescriptions).forEach(desc => { |
|
desc.style.display = 'none'; |
|
}); |
|
|
|
|
|
const descElement = document.getElementById(`mode-${selectedMode}`); |
|
if (descElement) { |
|
descElement.style.display = 'block'; |
|
} |
|
} |
|
|
|
function setupWheel() { |
|
classSize = parseInt(classSizeInput.value) || 30; |
|
startNumber = parseInt(startNumberInput.value) || 1; |
|
mode = pickerModeSelect.value; |
|
|
|
if (classSize < 1) { |
|
alert('班级人数必须大于0'); |
|
return; |
|
} |
|
|
|
|
|
createWheel(); |
|
|
|
|
|
setupPanel.classList.add('minimized'); |
|
wheelContainer.style.display = 'block'; |
|
resultDisplay.style.display = 'none'; |
|
|
|
|
|
setupPanel.addEventListener('click', function() { |
|
if (this.classList.contains('minimized')) { |
|
this.classList.remove('minimized'); |
|
} |
|
}); |
|
} |
|
|
|
function createWheel() { |
|
|
|
wheelInner.innerHTML = ''; |
|
segments = []; |
|
|
|
|
|
const segmentAngle = 360 / classSize; |
|
|
|
for (let i = 0; i < classSize; i++) { |
|
const segmentElement = document.createElement('div'); |
|
segmentElement.className = 'segment'; |
|
|
|
|
|
const rotation = i * segmentAngle; |
|
segmentElement.style.transform = `rotate(${rotation}deg)`; |
|
segmentElement.style.backgroundColor = colors[i % colors.length]; |
|
|
|
|
|
const contentElement = document.createElement('div'); |
|
contentElement.className = 'segment-content'; |
|
const studentNumber = startNumber + i; |
|
contentElement.textContent = studentNumber; |
|
|
|
segmentElement.appendChild(contentElement); |
|
wheelInner.appendChild(segmentElement); |
|
|
|
|
|
segments.push({ |
|
element: segmentElement, |
|
rotation, |
|
value: studentNumber |
|
}); |
|
} |
|
} |
|
|
|
function spin() { |
|
if (isSpinning) return; |
|
|
|
isSpinning = true; |
|
wheelContainer.classList.add('spinning'); |
|
|
|
|
|
const minRotation = 1800; |
|
const maxRotation = 3600; |
|
|
|
|
|
const segmentAngle = 360 / classSize; |
|
const randomOffset = Math.floor(Math.random() * classSize); |
|
const finalSegmentIndex = randomOffset; |
|
|
|
|
|
let totalRotation = minRotation + (maxRotation - minRotation) * Math.random(); |
|
|
|
|
|
totalRotation += (finalSegmentIndex * segmentAngle); |
|
|
|
|
|
wheelInner.style.transform = `rotate(${-totalRotation}deg)`; |
|
|
|
|
|
selectedSegment = segments[finalSegmentIndex]; |
|
|
|
|
|
if (mode === 'double') { |
|
let secondIndex = (finalSegmentIndex + Math.floor(classSize / 2)) % classSize; |
|
secondSelectedSegment = segments[secondIndex]; |
|
} |
|
|
|
|
|
setTimeout(() => { |
|
processResult(); |
|
}, 5000); |
|
} |
|
|
|
function processResult() { |
|
isSpinning = false; |
|
wheelContainer.classList.remove('spinning'); |
|
|
|
let finalResult = selectedSegment.value; |
|
let secondResult = secondSelectedSegment ? secondSelectedSegment.value : null; |
|
|
|
switch (mode) { |
|
case 'fake-out': |
|
playFakeOutEffect(finalResult); |
|
break; |
|
|
|
case 'oscillate': |
|
playOscillateEffect(finalResult); |
|
break; |
|
|
|
case 'mystery': |
|
playMysteryEffect(finalResult); |
|
break; |
|
|
|
case 'double': |
|
showDoubleResult(finalResult, secondResult); |
|
break; |
|
|
|
default: |
|
showResult(finalResult); |
|
break; |
|
} |
|
} |
|
|
|
function showResult(result) { |
|
wheelContainer.style.display = 'none'; |
|
resultDisplay.style.display = 'block'; |
|
|
|
resultNumber.textContent = result; |
|
resultText.textContent = `恭喜 ${result} 号同学被选中!`; |
|
|
|
|
|
const shine = document.querySelector('.shine'); |
|
shine.style.opacity = '1'; |
|
shine.style.animation = 'shine 2s 1'; |
|
|
|
|
|
setTimeout(() => { |
|
shine.style.opacity = '0'; |
|
shine.style.animation = 'none'; |
|
}, 2000); |
|
|
|
|
|
createConfetti(); |
|
} |
|
|
|
function showDoubleResult(result1, result2) { |
|
wheelContainer.style.display = 'none'; |
|
resultDisplay.style.display = 'block'; |
|
|
|
resultNumber.textContent = `${result1} & ${result2}`; |
|
resultText.textContent = `恭喜 ${result1} 号和 ${result2} 号同学被选中!`; |
|
|
|
|
|
const shine = document.querySelector('.shine'); |
|
shine.style.opacity = '1'; |
|
shine.style.animation = 'shine 2s 1'; |
|
|
|
|
|
setTimeout(() => { |
|
shine.style.opacity = '0'; |
|
shine.style.animation = 'none'; |
|
}, 2000); |
|
|
|
|
|
createConfetti(); |
|
} |
|
|
|
function playFakeOutEffect(finalResult) { |
|
|
|
const fakeResult = ((finalResult - startNumber + Math.floor(classSize / 2)) % classSize) + startNumber; |
|
|
|
wheelContainer.style.display = 'none'; |
|
resultDisplay.style.display = 'block'; |
|
|
|
resultNumber.textContent = fakeResult; |
|
resultText.textContent = `恭喜 ${fakeResult} 号同学被选中!`; |
|
|
|
|
|
setTimeout(() => { |
|
resultNumber.classList.add('shake'); |
|
resultText.textContent = "等等,发生了什么..."; |
|
|
|
|
|
setTimeout(() => { |
|
resultNumber.classList.remove('shake'); |
|
resultNumber.classList.add('jump'); |
|
resultNumber.textContent = finalResult; |
|
resultText.textContent = `真正被选中的是 ${finalResult} 号同学!`; |
|
|
|
|
|
const shine = document.querySelector('.shine'); |
|
shine.style.opacity = '1'; |
|
shine.style.animation = 'shine 2s 1'; |
|
|
|
|
|
setTimeout(() => { |
|
resultNumber.classList.remove('jump'); |
|
shine.style.opacity = '0'; |
|
shine.style.animation = 'none'; |
|
}, 2000); |
|
|
|
|
|
createConfetti(); |
|
}, 1000); |
|
}, 1500); |
|
} |
|
|
|
function playOscillateEffect(finalResult) { |
|
|
|
const altResult = ((finalResult - startNumber + Math.floor(classSize / 2)) % classSize) + startNumber; |
|
|
|
wheelContainer.style.display = 'none'; |
|
resultDisplay.style.display = 'block'; |
|
|
|
let count = 0; |
|
const maxOscillations = 6; |
|
const oscillationInterval = setInterval(() => { |
|
count++; |
|
resultNumber.textContent = count % 2 === 0 ? finalResult : altResult; |
|
resultText.textContent = "究竟会是谁呢..."; |
|
|
|
if (count >= maxOscillations) { |
|
clearInterval(oscillationInterval); |
|
|
|
resultNumber.classList.add('jump'); |
|
resultNumber.textContent = finalResult; |
|
resultText.textContent = `恭喜 ${finalResult} 号同学被选中!`; |
|
|
|
|
|
const shine = document.querySelector('.shine'); |
|
shine.style.opacity = '1'; |
|
shine.style.animation = 'shine 2s 1'; |
|
|
|
|
|
setTimeout(() => { |
|
resultNumber.classList.remove('jump'); |
|
shine.style.opacity = '0'; |
|
shine.style.animation = 'none'; |
|
}, 2000); |
|
|
|
|
|
createConfetti(); |
|
} |
|
}, 300); |
|
} |
|
|
|
function playMysteryEffect(finalResult) { |
|
|
|
const mysterySteps = 3; |
|
const stepDelay = 600; |
|
|
|
wheelContainer.style.display = 'none'; |
|
resultDisplay.style.display = 'block'; |
|
|
|
let step = 0; |
|
resultText.textContent = "神秘数字即将揭晓..."; |
|
|
|
|
|
resultNumber.classList.add('flicker'); |
|
|
|
const mysteryInterval = setInterval(() => { |
|
step++; |
|
|
|
if (step < mysterySteps) { |
|
|
|
const randomNumber = Math.floor(Math.random() * classSize) + startNumber; |
|
resultNumber.textContent = randomNumber; |
|
} else { |
|
|
|
clearInterval(mysteryInterval); |
|
resultNumber.classList.remove('flicker'); |
|
resultNumber.classList.add('jump'); |
|
resultNumber.textContent = finalResult; |
|
resultText.textContent = `恭喜 ${finalResult} 号同学被选中!`; |
|
|
|
|
|
const shine = document.querySelector('.shine'); |
|
shine.style.opacity = '1'; |
|
shine.style.animation = 'shine 2s 1'; |
|
|
|
|
|
setTimeout(() => { |
|
resultNumber.classList.remove('jump'); |
|
shine.style.opacity = '0'; |
|
shine.style.animation = 'none'; |
|
}, 2000); |
|
|
|
|
|
createConfetti(); |
|
} |
|
}, stepDelay); |
|
} |
|
|
|
function createConfetti() { |
|
const specialEffects = document.createElement('div'); |
|
specialEffects.className = 'special-effects'; |
|
resultDisplay.appendChild(specialEffects); |
|
|
|
|
|
for (let i = 0; i < 50; i++) { |
|
const confetti = document.createElement('div'); |
|
confetti.className = 'confetti'; |
|
|
|
|
|
const left = Math.random() * 100 + '%'; |
|
const top = -20 + 'px'; |
|
|
|
|
|
const size = Math.random() * 8 + 5; |
|
|
|
|
|
const color = colors[Math.floor(Math.random() * colors.length)]; |
|
|
|
|
|
const shapes = ['circle', 'square', 'triangle']; |
|
const shape = shapes[Math.floor(Math.random() * shapes.length)]; |
|
|
|
|
|
confetti.style.left = left; |
|
confetti.style.top = top; |
|
confetti.style.width = size + 'px'; |
|
confetti.style.height = size + 'px'; |
|
confetti.style.backgroundColor = color; |
|
|
|
if (shape === 'circle') { |
|
confetti.style.borderRadius = '50%'; |
|
} else if (shape === 'triangle') { |
|
confetti.style.clipPath = 'polygon(50% 0%, 0% 100%, 100% 100%)'; |
|
} |
|
|
|
|
|
specialEffects.appendChild(confetti); |
|
|
|
|
|
const duration = Math.random() * 3 + 2; |
|
const delay = Math.random() * 1.5; |
|
|
|
confetti.style.opacity = '1'; |
|
confetti.style.animation = `fall ${duration}s ease-in ${delay}s forwards`; |
|
|
|
|
|
if (!document.querySelector('#confetti-animation')) { |
|
const styleSheet = document.createElement('style'); |
|
styleSheet.id = 'confetti-animation'; |
|
styleSheet.textContent = ` |
|
@keyframes fall { |
|
0% { |
|
transform: translateY(0) rotate(0deg); |
|
opacity: 1; |
|
} |
|
100% { |
|
transform: translateY(${resultDisplay.clientHeight}px) rotate(360deg); |
|
opacity: 0; |
|
} |
|
} |
|
`; |
|
document.head.appendChild(styleSheet); |
|
} |
|
} |
|
|
|
|
|
setTimeout(() => { |
|
if (specialEffects && specialEffects.parentNode) { |
|
specialEffects.parentNode.removeChild(specialEffects); |
|
} |
|
}, 5000); |
|
} |
|
|
|
function reset() { |
|
|
|
setupPanel.classList.remove('minimized'); |
|
wheelContainer.style.display = 'none'; |
|
resultDisplay.style.display = 'none'; |
|
|
|
|
|
wheelInner.style.transform = 'rotate(0deg)'; |
|
|
|
|
|
isSpinning = false; |
|
selectedSegment = null; |
|
secondSelectedSegment = null; |
|
} |
|
|
|
|
|
init(); |
|
</script> |
|
</body> |
|
</html> |