mistpe commited on
Commit
50c1b92
·
verified ·
1 Parent(s): fe21207

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +354 -523
index.html CHANGED
@@ -28,7 +28,7 @@
28
  display: flex;
29
  flex-direction: column;
30
  align-items: center;
31
- padding: 2rem;
32
  }
33
 
34
  .container {
@@ -37,12 +37,12 @@
37
  display: flex;
38
  flex-direction: column;
39
  align-items: center;
40
- gap: 2rem;
41
  }
42
 
43
  header {
44
  text-align: center;
45
- margin-bottom: 1rem;
46
  }
47
 
48
  h1 {
@@ -58,40 +58,75 @@
58
  font-weight: 300;
59
  }
60
 
 
 
 
 
 
 
 
 
 
61
  .setup-panel {
62
  background-color: white;
63
- padding: 2rem;
64
  border-radius: 1rem;
65
  box-shadow: 0 10px 30px var(--shadow-color);
66
  width: 100%;
67
- max-width: 500px;
68
  transition: all 0.3s ease;
 
69
  }
70
 
71
- .setup-panel.minimized {
72
  padding: 1rem;
73
- max-width: 300px;
74
- cursor: pointer;
75
  }
76
 
77
- .setup-panel.minimized .form-group {
78
  display: none;
79
  }
80
 
81
- .setup-panel.minimized .panel-title:after {
82
- content: " (点击展开)";
83
- font-size: 0.8rem;
84
- color: var(--accent-color);
85
  }
86
 
87
- .panel-title {
88
- text-align: center;
 
 
89
  margin-bottom: 1.5rem;
 
 
 
 
90
  color: var(--primary-color);
 
91
  }
92
 
93
- .form-group {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  margin-bottom: 1.5rem;
 
 
 
 
 
 
95
  }
96
 
97
  label {
@@ -135,30 +170,19 @@
135
  box-shadow: 0 6px 15px var(--shadow-color);
136
  }
137
 
138
- .btn-secondary {
139
- background-color: var(--light-color);
140
- color: var(--primary-color);
141
- border: 2px solid var(--primary-color);
142
- }
143
-
144
- .btn-secondary:hover {
145
- background-color: var(--primary-color);
146
- color: white;
147
- }
148
-
149
  .actions {
150
  display: flex;
151
  justify-content: center;
152
  gap: 1rem;
 
153
  }
154
 
155
  .wheel-container {
156
  position: relative;
157
  width: 100%;
158
- max-width: 600px;
159
  aspect-ratio: 1;
160
- margin: 2rem 0;
161
- display: none;
162
  }
163
 
164
  .wheel {
@@ -258,15 +282,22 @@
258
 
259
  .result-display {
260
  background-color: white;
261
- padding: 2rem;
262
  border-radius: 1rem;
263
  box-shadow: 0 10px 30px var(--shadow-color);
264
  text-align: center;
265
- max-width: 500px;
266
  width: 100%;
 
267
  display: none;
268
- position: relative;
 
 
 
269
  overflow: hidden;
 
 
 
 
270
  }
271
 
272
  .result-display h2 {
@@ -275,17 +306,18 @@
275
  }
276
 
277
  .result-number {
278
- font-size: 5rem;
279
  font-weight: bold;
280
  color: var(--accent-color);
281
- margin: 1rem 0;
282
  position: relative;
283
  transition: all 0.3s;
 
284
  }
285
 
286
  .result-text {
287
- font-size: 1.2rem;
288
- margin-bottom: 1.5rem;
289
  }
290
 
291
  .shine {
@@ -339,24 +371,6 @@
339
  box-shadow: 0 0 50px var(--accent-color), 0 0 100px rgba(255, 214, 102, 0.8);
340
  }
341
 
342
- @media (max-width: 768px) {
343
- h1 {
344
- font-size: 2rem;
345
- }
346
-
347
- .container {
348
- gap: 1rem;
349
- }
350
-
351
- .setup-panel, .result-display {
352
- padding: 1.5rem;
353
- }
354
-
355
- .result-number {
356
- font-size: 3.5rem;
357
- }
358
- }
359
-
360
  .mode-description {
361
  display: none;
362
  margin-top: 0.5rem;
@@ -395,12 +409,6 @@
395
  100% { transform: scale(1); }
396
  }
397
 
398
- @keyframes spotlight {
399
- 0% { box-shadow: 0 0 10px var(--shadow-color); }
400
- 50% { box-shadow: 0 0 60px var(--accent-color), 0 0 120px rgba(129, 199, 132, 0.8); }
401
- 100% { box-shadow: 0 0 10px var(--shadow-color); }
402
- }
403
-
404
  @keyframes heartbeat {
405
  0% { transform: scale(1); }
406
  15% { transform: scale(1.15); }
@@ -410,23 +418,16 @@
410
  100% { transform: scale(1); }
411
  }
412
 
413
- /* Spotlight effect */
414
- .spotlight-container {
415
- position: absolute;
416
- top: 0;
417
- left: 0;
418
- width: 100%;
419
- height: 100%;
420
- overflow: hidden;
421
- pointer-events: none;
422
- z-index: 5;
423
- background: radial-gradient(
424
- circle at center,
425
- rgba(255, 255, 255, 0) 30%,
426
- rgba(0, 0, 0, 0.7) 100%
427
- );
428
- opacity: 0;
429
- transition: opacity 0.5s;
430
  }
431
 
432
  .help-bubble {
@@ -483,6 +484,51 @@
483
  cursor: pointer;
484
  color: var(--accent-color);
485
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
  </style>
487
  </head>
488
  <body>
@@ -492,82 +538,81 @@
492
  <p class="subtitle">掌控命运,抉择未来!</p>
493
  </header>
494
 
495
- <div class="setup-panel">
496
- <h2 class="panel-title">设置</h2>
497
- <div class="form-group">
498
- <label for="class-size">班级人数:</label>
499
- <input type="number" id="class-size" min="1" max="100" value="30">
500
- </div>
501
-
502
- <div class="form-group">
503
- <label for="start-number">起始编号 (默认从1开始):</label>
504
- <input type="number" id="start-number" min="0" value="1">
505
- </div>
506
-
507
- <div class="form-group">
508
- <label for="animation-speed">动画速度:</label>
509
- <select id="animation-speed">
510
- <option value="slow">慢速 (更多悬念)</option>
511
- <option value="normal" selected>正常</option>
512
- <option value="fast">快速</option>
513
- <option value="insane">超快 (刺激模式)</option>
514
- </select>
515
- </div>
516
-
517
- <div class="form-group">
518
- <label for="sound-effects">音效:</label>
519
- <select id="sound-effects">
520
- <option value="off">关闭</option>
521
- <option value="basic" selected>基础音效</option>
522
- <option value="dramatic">戏剧性音效</option>
523
- <option value="suspense">悬疑���效</option>
524
- </select>
525
- </div>
526
-
527
- <div class="form-group">
528
- <label for="picker-mode">选择模式:</label>
529
- <select id="picker-mode">
530
- <option value="normal">正常模式</option>
531
- <option value="fake-out">假动作模式</option>
532
- <option value="oscillate">摇摆不定模式</option>
533
- <option value="mystery">神秘模式</option>
534
- <option value="double">双重选择模式</option>
535
- <option value="countdown">倒计时模式</option>
536
- <option value="elimination">淘汰赛模式</option>
537
- <option value="spotlight">聚光灯模式</option>
538
- <option value="heartbeat">心跳紧张模式</option>
539
- </select>
540
- <div id="mode-normal" class="mode-description">普通的转盘选择,公平公正。</div>
541
- <div id="mode-fake-out" class="mode-description">即将停止时转盘突然改变方向!</div>
542
- <div id="mode-oscillate" class="mode-description">在两个结果之间反复摇摆,到底是谁呢?</div>
543
- <div id="mode-mystery" class="mode-description">结果会短暂显示然后突然变化,充满惊喜!</div>
544
- <div id="mode-double" class="mode-description">选出两个幸运儿!</div>
545
- <div id="mode-countdown" class="mode-description">紧张的倒计时音效增加悬念感!</div>
546
- <div id="mode-elimination" class="mode-description">一轮轮淘汰,最后只留下一个幸运儿!</div>
547
- <div id="mode-spotlight" class="mode-description">灯光聚焦效果,犹如舞台中央的明星!</div>
548
- <div id="mode-heartbeat" class="mode-description">伴随心跳声,感受命运的紧张抉择!</div>
 
 
 
 
549
  </div>
550
 
551
- <div class="actions">
552
- <button id="start-btn" class="btn">开始点名</button>
553
- <button id="reset-btn" class="btn btn-secondary">重置</button>
554
- </div>
555
- </div>
556
-
557
- <div class="wheel-container">
558
- <div class="wheel-pointer"></div>
559
- <div class="wheel">
560
- <div class="wheel-inner" id="wheel-inner"></div>
 
 
 
 
561
  </div>
562
- <div class="wheel-center" id="spin-btn">转!</div>
563
- </div>
564
-
565
- <div class="result-display">
566
- <div class="shine"></div>
567
- <h2>点名结果</h2>
568
- <div class="result-number" id="result-number">?</div>
569
- <p class="result-text" id="result-text">请点击转盘开始</p>
570
- <button id="spin-again-btn" class="btn">再来一次</button>
571
  </div>
572
  </div>
573
 
@@ -580,22 +625,19 @@
580
  <p><strong>摇摆不定模式:</strong> 在两个选项之间来回摇摆,增加悬念感。</p>
581
  <p><strong>神秘模式:</strong> 先显示一个结果,然后突然改变!谁也猜不到最终会是谁。</p>
582
  <p><strong>双重选择模式:</strong> 同时选出两名同学,适合小组活动。</p>
583
- <p><strong>倒计时模式:</strong> 伴随紧张的倒计时音效和动画,增加刺激感。</p>
584
- <p><strong>淘汰赛模式:</strong> 连续多轮抽取逐步淘汰,最终决出命运之选。</p>
585
- <p><strong>聚光灯模式:</strong> 模拟真实大型抽奖活动,灯光聚焦效果。</p>
586
- <p><strong>心跳紧张模式:</strong> 伴随心跳声音效,让结果更加扣人心弦。</p>
587
- <p><strong>提示:</strong> 尝试不同的音效和动画速度组合,获得最佳体验!</p>
588
  </div>
589
 
590
  <script>
591
  // DOM Elements
592
  const setupPanel = document.querySelector('.setup-panel');
 
593
  const classSizeInput = document.getElementById('class-size');
594
  const startNumberInput = document.getElementById('start-number');
595
  const pickerModeSelect = document.getElementById('picker-mode');
596
  const animationSpeedSelect = document.getElementById('animation-speed');
597
- const soundEffectsSelect = document.getElementById('sound-effects');
598
- const startBtn = document.getElementById('start-btn');
599
  const resetBtn = document.getElementById('reset-btn');
600
  const wheelContainer = document.querySelector('.wheel-container');
601
  const wheelInner = document.getElementById('wheel-inner');
@@ -616,64 +658,33 @@
616
  mystery: document.getElementById('mode-mystery'),
617
  double: document.getElementById('mode-double'),
618
  countdown: document.getElementById('mode-countdown'),
619
- elimination: document.getElementById('mode-elimination'),
620
- spotlight: document.getElementById('mode-spotlight'),
621
  heartbeat: document.getElementById('mode-heartbeat')
622
  };
623
 
 
 
 
 
 
 
 
 
624
  // Variables
625
  let classSize = 30;
626
  let startNumber = 1;
627
  let mode = 'normal';
628
  let animationSpeed = 'normal';
629
- let soundEffects = 'basic';
630
  let isSpinning = false;
631
  let segments = [];
632
  let selectedSegment = null;
633
  let secondSelectedSegment = null;
634
- let eliminationCandidates = [];
635
- let eliminationRound = 0;
636
-
637
- // Sound effects
638
- const sounds = {
639
- spin: new Audio('data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4Ljc2LjEwMAAAAAAAAAAAAAAA/+M4wAAAAAAAAAAAAEluZm8AAAAPAAAAAwAAAbAAkJCQkJCQkJCQkJCQkJCQkJCQwMDAwMDAwMDAwMDAwMDAwMDA4ODg4ODg4ODg4ODg4ODg4ODg4P////////////////////////////////////////////////////////////////8AAAAATGF2YzU4LjEzAAAAAAAAAAAAAAAAJAXAAAAAAAAAAbC3hL2QAAAAAAD/+9DEAAAJtPl39BEAJgpN7j84wAGMKUpWlP19W1v1f3a1apSktaUkxpJgYGAYGDEYO5eHyXh9wfP+H4fwfD6AZ8Pw+gGfnygY+MDDDDDDDDDDDDDDDD4fg+gGfh8/8Pn/+H0Az5+UMfP/+oBooyZVLj6iYqhplXOKiomz1kVdVUksYnF3KszMrUxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'),
640
- result: new Audio('data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4Ljc2LjEwMAAAAAAAAAAAAAAA/+M4wAAAAAAAAAAAAEluZm8AAAAPAAAAAwAAAXnAyMjIyMjIyMjIyMjIyMjIyMjI5OTk5OTk5OTk5OTk5OTk5OTk5P39/f39/f39/f39/f39/f39/f///////////////////////////////////////////////////////////////////////////////////////////////////////////8AAAAATGF2YzU4LjEzAAAAAAAAAAAAAAAAJAaUAAAAAAAAeblBaHYAAAAAAP/7sMQAAAfA53P5hgAKGUruPzjAASEQQQNhjHHdPnPz797ve0vbdM7vPPPGBBBQoUhISEhIAAAIQhAVOP4WOeeOJwIBANDuK+Xn8fH06Ic7etFbiMVhYAgIBgYGBwfB8Hw+H0A0NDQ0NDQ0Af/////////+qqqqoAAAAAVVVVQAAAxiMQ5nJTnOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5znOc5zmIxEZ//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////MTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV'),
641
- countdown: new Audio('data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4Ljc2LjEwMAAAAAAAAAAAAAAA/+M4wAAAAAAAAAAAAEluZm8AAAAPAAAABAAAAeAAMDAwMDAwMDAwMDAwVVVVVVVVVVVVVVVVVaqqqqqqqqqqqqqqqqqq1dXV1dXV1dXV1dXV1dXw8PDw8PDw8PDw8PDw8P////////////////////////////////8AAAAATGF2YzU4LjEzAAAAAAAAAAAAAAAAJAZgAAAAAAAAei6yB8AAAAAAA//7kMQAAAs0x2/4YYABRCOqOzDACpdGMYxtBpqqtSv1KUyRRZVlzKdBkCgIBAIJiQUGijgQDBSMFwAGAAYAGPR++D4PnAEHwfJAUeBAQEBEREQIQhCNDHw+fB8HwfJAR8Pn5IIEBAQEBAQEBAT5ICAj4fTHw+f///+SCAgI+DgICPjggICbICAgICAn////5IICBMkBAT/+SCAgICAgJ////kggICAgQEyQEBAQECYICAgI+Hz////5IICAn////+SCAgIDRMNDQ0NDQ0TDQ0NDQ0NDa0mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpMQU1FMy4xMDBV'),
642
- heartbeat: new Audio('data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4Ljc2LjEwMAAAAAAAAAAAAAAA/+M4wAAAAAAAAAAAAEluZm8AAAAPAAAAAwAAAbAAkJCQkJCQkJCQkJCQkJCQkJCQwMDAwMDAwMDAwMDAwMDAwMDA4ODg4ODg4ODg4ODg4ODg4ODg4P////////////////////////////////////////////////////////////////8AAAAATGF2YzU4LjEzAAAAAAAAAAAAAAAAJAXAAAAAAAAAAbC3hL2QAAAAAAD/+xDEAAAHRId9+GGAARIrKn8wwAGqqqpN9aqqkqqpN9VNIiNu7Zmg2JMICJVAwEAgELhcGAYBgMGQwZfL+XyQEBAQEeD5/y/kgICPB8/5ICAgI8Hc/kgICAj4fP8kBAQEwQEB4PggICPB3/P+SAgICPh8/8kBAQEBASD4PggICPB3P5ICAgI+D4ICAj4fD5IIPggICPB8/8kBAQEBAQEfB9/kgICAkH/JBB8Hz/kgg+CAkH/P/JBB8EHwQf/JAQEggICPg+/yQQEBMEBAR8Hz/kggICYIPgg+CD4IP+SCAgI+D5/yQEBAT/B8Hc/6oAAAAAAAAA'),
643
- dramatic: new Audio('data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4Ljc2LjEwMAAAAAAAAAAAAAAA/+M4wAAAAAAAAAAAAEluZm8AAAAPAAAAAwAAAbAAzMzMzMzMzMzMzMzMzMzMzMzM/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/P///////////////////////////////////////////////////////////////////////////////////8AAAAATGF2YzU4LjEzAAAAAAAAAAAAAAAAJAZgAAAAAAAAAbD6L30gAAAAAAD/+7DEAAAKYOFy+cmAASikabj8qAA2lVVmtOmdzHHtK7mONOmcyczMqgoWFJwcLCwpIhYWFk4OFixQsLD/wULCwJFFCwsOaSIWFA4WFhQFFFFjGMWFhQWFhQWFhQUDGMb/BQWHNkUUUUdJowULDssUUWMWKKOkgcLDuyKKOklFqEVwsO72MWKKOkldJI/iqPaRX+yP/oRVH/ysKDu9lYf/ZVHaFUe0iv9JIO72VR7SKo8dJI6Qij2hlQdhFUeOkkdIRVHtDKg7SK//2MWKPYGKPaGVR/9lYUFh/aFC/8Ozs7O/8rOzv/DKg7uw7OzsOzo7Ozs6Ozs7Ozr///zs7Ozs6Os6Ozs7Olh2dDKo7Ozs6Ozs6OsOzs6Ozs7Ozs6Ozs6OsOzo7Ojr///w7Ojs7Ow6Ojr/w7Ozs7OsOw7Ozs6Ow7Ozs6Ow7Ozs6Ozs7DsOzs7OjsOzs7Ojr//8Ozs7Ols7OztbOzs6Ozs7O1s7OztbOzs6Ozs7O1s7OztbOzs6O1s7OztbOzs7WztbOztbOzs7O1s7OztbOzs7O1s7OzpbOzs7WztbOzs7Wzs7O1s7OztbOzs7O1s7OztbOzs7O1s7OzpbOzs7WztbOztbOzs7O1s7OzpbOzs7WztbOzs7Wzs7O1s7OztbOzs7O1s7O1s7OztbOzs7O1s7OztbOzs7WzqzWztbOztbOzs6WzpbOzs6szs6szs6szs6szs6szs6szs6s1s6szs6szs6szs6szs6szs6s1s6szs6szs6szs6szs6szs6s1s6szs6szs6szs6szs6szs6s1s6szs6szs6szs6szs6szs6s1s6szs6szs6szs6szs6szs6s1s7OzpbOzs7WztbOzs6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsqs1s6Wzsq')
644
- };
645
-
646
- // Play a sound from the sound library
647
- function playSound(soundName) {
648
- // Only play if sound effects are enabled
649
- if (soundEffects === 'off') return;
650
-
651
- // Stop any currently playing sounds
652
- sounds.spin.pause();
653
- sounds.spin.currentTime = 0;
654
- sounds.result.pause();
655
- sounds.result.currentTime = 0;
656
- sounds.countdown.pause();
657
- sounds.countdown.currentTime = 0;
658
- sounds.heartbeat.pause();
659
- sounds.heartbeat.currentTime = 0;
660
- sounds.dramatic.pause();
661
- sounds.dramatic.currentTime = 0;
662
-
663
- // Play the requested sound
664
- if (sounds[soundName]) {
665
- sounds[soundName].play().catch(e => {
666
- console.log("Sound could not be played: " + e);
667
- });
668
- }
669
- }
670
 
671
  function updateModeDescription() {
672
  const selectedMode = pickerModeSelect.value;
673
 
674
  // Hide all descriptions
675
  Object.values(modeDescriptions).forEach(desc => {
676
- desc.style.display = 'none';
677
  });
678
 
679
  // Show selected description
@@ -683,56 +694,11 @@
683
  }
684
  }
685
 
686
- function setupWheel() {
687
- classSize = parseInt(classSizeInput.value) || 30;
688
- startNumber = parseInt(startNumberInput.value) || 1;
689
- mode = pickerModeSelect.value;
690
- animationSpeed = animationSpeedSelect.value;
691
- soundEffects = soundEffectsSelect.value;
692
-
693
- if (classSize < 1) {
694
- alert('班级人数必须大于0');
695
- return;
696
- }
697
-
698
- // For elimination mode, prepare the candidates
699
- if (mode === 'elimination') {
700
- eliminationCandidates = [];
701
- for (let i = 0; i < classSize; i++) {
702
- eliminationCandidates.push(startNumber + i);
703
- }
704
- eliminationRound = 0;
705
- }
706
-
707
- // Create wheel segments
708
- createWheel();
709
-
710
- // Show wheel, hide setup
711
- setupPanel.classList.add('minimized');
712
- wheelContainer.style.display = 'block';
713
- resultDisplay.style.display = 'none';
714
-
715
- // Make setup panel expandable when minimized
716
- setupPanel.addEventListener('click', function() {
717
- if (this.classList.contains('minimized')) {
718
- this.classList.remove('minimized');
719
- }
720
- });
721
- }
722
-
723
  function createWheel() {
724
  // Clear previous wheel
725
  wheelInner.innerHTML = '';
726
  segments = [];
727
 
728
- // Colors for the wheel segments (soft green palette)
729
- const colors = [
730
- '#4CAF50', '#66BB6A', '#81C784', '#A5D6A7',
731
- '#C8E6C9', '#7CB342', '#8BC34A', '#9CCC65',
732
- '#AED581', '#C5E1A5', '#DCEDC8', '#43A047',
733
- '#388E3C', '#2E7D32', '#689F38', '#558B2F'
734
- ];
735
-
736
  // Create segments
737
  const segmentAngle = 360 / classSize;
738
 
@@ -763,6 +729,24 @@
763
  }
764
  }
765
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
766
  function spin() {
767
  if (isSpinning) return;
768
 
@@ -814,25 +798,6 @@
814
  secondSelectedSegment = segments[secondIndex];
815
  }
816
 
817
- // Play sound effects if enabled
818
- if (soundEffects !== 'off') {
819
- playSound('spin');
820
-
821
- if (mode === 'countdown') {
822
- // Start countdown sound after a delay
823
- setTimeout(() => {
824
- playSound('countdown');
825
- }, spinDuration - 3000); // Start 3 seconds before end
826
- }
827
-
828
- if (mode === 'heartbeat') {
829
- // Start heartbeat sound after a delay
830
- setTimeout(() => {
831
- playSound('heartbeat');
832
- }, spinDuration - 3000); // Start 3 seconds before end
833
- }
834
- }
835
-
836
  // Process result after spinning animation
837
  setTimeout(() => {
838
  processResult();
@@ -846,16 +811,6 @@
846
  let finalResult = selectedSegment.value;
847
  let secondResult = secondSelectedSegment ? secondSelectedSegment.value : null;
848
 
849
- // Play result sound if enabled
850
- if (soundEffects !== 'off') {
851
- // Different sounds for different modes
852
- if (mode === 'dramatic' && soundEffects === 'dramatic') {
853
- playSound('dramatic');
854
- } else {
855
- playSound('result');
856
- }
857
- }
858
-
859
  switch (mode) {
860
  case 'fake-out':
861
  playFakeOutEffect(finalResult);
@@ -877,14 +832,6 @@
877
  playCountdownEffect(finalResult);
878
  break;
879
 
880
- case 'elimination':
881
- playEliminationEffect(finalResult);
882
- break;
883
-
884
- case 'spotlight':
885
- playSpotlightEffect(finalResult);
886
- break;
887
-
888
  case 'heartbeat':
889
  playHeartbeatEffect(finalResult);
890
  break;
@@ -896,40 +843,51 @@
896
  }
897
 
898
  function showResult(result) {
899
- wheelContainer.style.display = 'none';
900
- resultDisplay.style.display = 'block';
901
 
902
  resultNumber.textContent = result;
903
  resultText.textContent = `恭喜 ${result} 号同学被选中!`;
904
 
905
- // Add shine effect
 
 
 
 
 
 
 
906
  const shine = document.querySelector('.shine');
907
  shine.style.opacity = '1';
908
  shine.style.animation = 'shine 2s 1';
909
 
910
- // Reset animation after it completes
911
  setTimeout(() => {
912
  shine.style.opacity = '0';
913
  shine.style.animation = 'none';
914
  }, 2000);
915
 
916
- // Add confetti effect
917
  createConfetti();
918
  }
919
-
920
  function showDoubleResult(result1, result2) {
921
- wheelContainer.style.display = 'none';
922
- resultDisplay.style.display = 'block';
923
 
924
  resultNumber.textContent = `${result1} & ${result2}`;
925
  resultText.textContent = `恭喜 ${result1} 号和 ${result2} 号同学被选中!`;
926
 
 
 
 
 
 
 
 
927
  // Add shine effect
928
  const shine = document.querySelector('.shine');
929
  shine.style.opacity = '1';
930
  shine.style.animation = 'shine 2s 1';
931
 
932
- // Reset animation after it completes
933
  setTimeout(() => {
934
  shine.style.opacity = '0';
935
  shine.style.animation = 'none';
@@ -938,29 +896,42 @@
938
  // Add confetti effect
939
  createConfetti();
940
  }
941
-
942
  function playFakeOutEffect(finalResult) {
943
  // First show a fake result
944
  const fakeResult = ((finalResult - startNumber + Math.floor(classSize / 2)) % classSize) + startNumber;
945
 
946
- wheelContainer.style.display = 'none';
947
- resultDisplay.style.display = 'block';
948
 
949
  resultNumber.textContent = fakeResult;
950
  resultText.textContent = `恭喜 ${fakeResult} 号同学被选中!`;
951
 
 
 
 
 
 
 
 
952
  // After a short delay, apply shake effect and change to actual result
953
  setTimeout(() => {
954
- resultNumber.classList.add('shake');
955
  resultText.textContent = "等等,发生了什么...";
956
 
957
  // After shake effect, reveal true result
958
  setTimeout(() => {
959
- resultNumber.classList.remove('shake');
960
- resultNumber.classList.add('jump');
 
961
  resultNumber.textContent = finalResult;
962
  resultText.textContent = `真正被选中的是 ${finalResult} 号同学!`;
963
 
 
 
 
 
 
 
 
964
  // Add shine effect
965
  const shine = document.querySelector('.shine');
966
  shine.style.opacity = '1';
@@ -968,7 +939,7 @@
968
 
969
  // Reset animations
970
  setTimeout(() => {
971
- resultNumber.classList.remove('jump');
972
  shine.style.opacity = '0';
973
  shine.style.animation = 'none';
974
  }, 2000);
@@ -978,25 +949,34 @@
978
  }, 1000);
979
  }, 1500);
980
  }
981
-
982
  function playOscillateEffect(finalResult) {
983
  // Create alternative result
984
  const altResult = ((finalResult - startNumber + Math.floor(classSize / 2)) % classSize) + startNumber;
985
 
986
- wheelContainer.style.display = 'none';
987
- resultDisplay.style.display = 'block';
 
 
988
 
989
  let count = 0;
990
  const maxOscillations = 6;
991
  const oscillationInterval = setInterval(() => {
992
  count++;
993
- resultNumber.textContent = count % 2 === 0 ? finalResult : altResult;
 
994
  resultText.textContent = "究竟会是谁呢...";
995
 
 
 
 
 
 
 
 
996
  if (count >= maxOscillations) {
997
  clearInterval(oscillationInterval);
998
  // Final result with visual effect
999
- resultNumber.classList.add('jump');
1000
  resultNumber.textContent = finalResult;
1001
  resultText.textContent = `恭喜 ${finalResult} 号同学被选中!`;
1002
 
@@ -1007,7 +987,7 @@
1007
 
1008
  // Reset animations
1009
  setTimeout(() => {
1010
- resultNumber.classList.remove('jump');
1011
  shine.style.opacity = '0';
1012
  shine.style.animation = 'none';
1013
  }, 2000);
@@ -1017,20 +997,19 @@
1017
  }
1018
  }, 300);
1019
  }
1020
-
1021
  function playMysteryEffect(finalResult) {
1022
  // Generate a series of random results ending with the actual one
1023
  const mysterySteps = 3;
1024
  const stepDelay = 600;
1025
 
1026
- wheelContainer.style.display = 'none';
1027
- resultDisplay.style.display = 'block';
1028
 
1029
  let step = 0;
1030
  resultText.textContent = "神秘数字即将揭晓...";
1031
 
1032
  // Add flicker effect to create suspense
1033
- resultNumber.classList.add('flicker');
 
1034
 
1035
  const mysteryInterval = setInterval(() => {
1036
  step++;
@@ -1039,14 +1018,29 @@
1039
  // Show random number
1040
  const randomNumber = Math.floor(Math.random() * classSize) + startNumber;
1041
  resultNumber.textContent = randomNumber;
 
 
 
 
 
 
 
1042
  } else {
1043
  // Last step - show real result
1044
  clearInterval(mysteryInterval);
1045
- resultNumber.classList.remove('flicker');
1046
- resultNumber.classList.add('jump');
 
1047
  resultNumber.textContent = finalResult;
1048
  resultText.textContent = `恭喜 ${finalResult} 号同学被选中!`;
1049
 
 
 
 
 
 
 
 
1050
  // Add shine effect
1051
  const shine = document.querySelector('.shine');
1052
  shine.style.opacity = '1';
@@ -1054,7 +1048,7 @@
1054
 
1055
  // Reset animations
1056
  setTimeout(() => {
1057
- resultNumber.classList.remove('jump');
1058
  shine.style.opacity = '0';
1059
  shine.style.animation = 'none';
1060
  }, 2000);
@@ -1064,32 +1058,38 @@
1064
  }
1065
  }, stepDelay);
1066
  }
1067
-
1068
  function playCountdownEffect(finalResult) {
1069
- wheelContainer.style.display = 'none';
1070
- resultDisplay.style.display = 'block';
1071
 
1072
  resultNumber.textContent = "3";
 
1073
  resultText.textContent = "倒计时开始...";
1074
 
1075
  // Countdown animation
1076
  setTimeout(() => {
 
1077
  resultNumber.textContent = "2";
1078
- resultNumber.classList.add('jump');
1079
- setTimeout(() => resultNumber.classList.remove('jump'), 300);
1080
  }, 1000);
1081
 
1082
  setTimeout(() => {
 
1083
  resultNumber.textContent = "1";
1084
- resultNumber.classList.add('jump');
1085
- setTimeout(() => resultNumber.classList.remove('jump'), 300);
1086
  }, 2000);
1087
 
1088
  setTimeout(() => {
1089
- resultNumber.classList.add('jump');
1090
  resultNumber.textContent = finalResult;
1091
  resultText.textContent = `恭喜 ${finalResult} 号同学被选中!`;
1092
 
 
 
 
 
 
 
 
1093
  // Add shine effect
1094
  const shine = document.querySelector('.shine');
1095
  shine.style.opacity = '1';
@@ -1097,7 +1097,7 @@
1097
 
1098
  // Reset animations
1099
  setTimeout(() => {
1100
- resultNumber.classList.remove('jump');
1101
  shine.style.opacity = '0';
1102
  shine.style.animation = 'none';
1103
  }, 2000);
@@ -1106,185 +1106,11 @@
1106
  createConfetti();
1107
  }, 3000);
1108
  }
1109
-
1110
- function playEliminationEffect(finalResult) {
1111
- eliminationRound++;
1112
-
1113
- // If this is the first round, start with all candidates
1114
- if (eliminationRound === 1) {
1115
- wheelContainer.style.display = 'none';
1116
- resultDisplay.style.display = 'block';
1117
-
1118
- // Show how many candidates remain
1119
- if (eliminationCandidates.length > 1) {
1120
- resultNumber.textContent = eliminationCandidates.length;
1121
- resultText.textContent = `第${eliminationRound}轮: 还剩${eliminationCandidates.length}名候选者`;
1122
-
1123
- // Remove the selected candidate
1124
- const index = eliminationCandidates.indexOf(finalResult);
1125
- if (index > -1) {
1126
- eliminationCandidates.splice(index, 1);
1127
- }
1128
-
1129
- // Provide option to continue elimination or select winner
1130
- spinAgainBtn.textContent = "继续淘汰";
1131
- const selectWinnerBtn = document.createElement('button');
1132
- selectWinnerBtn.textContent = "选出获胜者";
1133
- selectWinnerBtn.className = "btn btn-secondary";
1134
- selectWinnerBtn.style.marginLeft = "10px";
1135
-
1136
- // Add button to DOM if not already there
1137
- if (!document.getElementById('select-winner-btn')) {
1138
- selectWinnerBtn.id = 'select-winner-btn';
1139
- spinAgainBtn.parentNode.appendChild(selectWinnerBtn);
1140
-
1141
- // Add event listener
1142
- selectWinnerBtn.addEventListener('click', function() {
1143
- // Choose random winner from remaining candidates
1144
- const winnerIndex = Math.floor(Math.random() * eliminationCandidates.length);
1145
- const winner = eliminationCandidates[winnerIndex];
1146
-
1147
- // Display winner
1148
- resultNumber.textContent = winner;
1149
- resultText.textContent = `最终获胜者是 ${winner} 号同学!`;
1150
-
1151
- // Remove this button
1152
- this.remove();
1153
- spinAgainBtn.textContent = "再来一次";
1154
-
1155
- // Add confetti
1156
- createConfetti();
1157
-
1158
- // Reset elimination mode
1159
- eliminationRound = 0;
1160
- eliminationCandidates = [];
1161
- });
1162
- }
1163
- } else if (eliminationCandidates.length === 1) {
1164
- // Only one candidate left - they're the winner
1165
- resultNumber.textContent = eliminationCandidates[0];
1166
- resultText.textContent = `最终获胜者是 ${eliminationCandidates[0]} 号同学!`;
1167
- spinAgainBtn.textContent = "再来一次";
1168
-
1169
- // Remove select winner button if it exists
1170
- const selectWinnerBtn = document.getElementById('select-winner-btn');
1171
- if (selectWinnerBtn) {
1172
- selectWinnerBtn.remove();
1173
- }
1174
-
1175
- // Add confetti
1176
- createConfetti();
1177
-
1178
- // Reset elimination mode
1179
- eliminationRound = 0;
1180
- eliminationCandidates = [];
1181
- }
1182
- } else {
1183
- // Subsequent rounds
1184
- // Remove the newly selected candidate
1185
- const index = eliminationCandidates.indexOf(finalResult);
1186
- if (index > -1) {
1187
- eliminationCandidates.splice(index, 1);
1188
- }
1189
-
1190
- // Show how many candidates remain
1191
- resultNumber.textContent = eliminationCandidates.length;
1192
-
1193
- if (eliminationCandidates.length > 1) {
1194
- resultText.textContent = `第${eliminationRound}轮: 还剩${eliminationCandidates.length}名候选者`;
1195
- } else if (eliminationCandidates.length === 1) {
1196
- // Only one candidate left - they're the winner
1197
- resultNumber.textContent = eliminationCandidates[0];
1198
- resultText.textContent = `最终获胜者是 ${eliminationCandidates[0]} 号同学!`;
1199
- spinAgainBtn.textContent = "再来一次";
1200
-
1201
- // Remove select winner button if it exists
1202
- const selectWinnerBtn = document.getElementById('select-winner-btn');
1203
- if (selectWinnerBtn) {
1204
- selectWinnerBtn.remove();
1205
- }
1206
-
1207
- // Add confetti
1208
- createConfetti();
1209
-
1210
- // Reset elimination mode
1211
- eliminationRound = 0;
1212
- eliminationCandidates = [];
1213
- } else {
1214
- // No candidates left (shouldn't happen normally)
1215
- resultText.textContent = `所有候选者都已淘汰!`;
1216
- spinAgainBtn.textContent = "再来一次";
1217
-
1218
- // Remove select winner button if it exists
1219
- const selectWinnerBtn = document.getElementById('select-winner-btn');
1220
- if (selectWinnerBtn) {
1221
- selectWinnerBtn.remove();
1222
- }
1223
-
1224
- // Reset elimination mode
1225
- eliminationRound = 0;
1226
- eliminationCandidates = [];
1227
- }
1228
- }
1229
- }
1230
-
1231
- function playSpotlightEffect(finalResult) {
1232
- wheelContainer.style.display = 'none';
1233
- resultDisplay.style.display = 'block';
1234
-
1235
- // Create spotlight container if it doesn't exist
1236
- let spotlightContainer = document.querySelector('.spotlight-container');
1237
- if (!spotlightContainer) {
1238
- spotlightContainer = document.createElement('div');
1239
- spotlightContainer.className = 'spotlight-container';
1240
- resultDisplay.appendChild(spotlightContainer);
1241
- }
1242
-
1243
- // Show the spotlight
1244
- spotlightContainer.style.opacity = '1';
1245
-
1246
- // First show blank result
1247
- resultNumber.textContent = "?";
1248
- resultText.textContent = "聚光灯将选择...";
1249
-
1250
- // Add drumroll effect with increasing intensity
1251
- let drumrollInterval;
1252
- let intensity = 0;
1253
- const maxIntensity = 10;
1254
-
1255
- drumrollInterval = setInterval(() => {
1256
- intensity++;
1257
- resultNumber.style.opacity = 0.5 + (intensity / maxIntensity * 0.5);
1258
-
1259
- if (intensity >= maxIntensity) {
1260
- clearInterval(drumrollInterval);
1261
-
1262
- // Show the result with dramatic effect
1263
- resultNumber.classList.add('jump');
1264
- resultNumber.textContent = finalResult;
1265
- resultText.textContent = `恭喜 ${finalResult} 号同学被选中!`;
1266
-
1267
- // Apply spotlight pulse animation
1268
- resultDisplay.style.animation = 'spotlight 2s';
1269
-
1270
- // Create confetti
1271
- createConfetti();
1272
-
1273
- // Gradually fade out spotlight
1274
- setTimeout(() => {
1275
- spotlightContainer.style.opacity = '0';
1276
- resultNumber.classList.remove('jump');
1277
- resultDisplay.style.animation = 'none';
1278
- }, 3000);
1279
- }
1280
- }, 300);
1281
- }
1282
-
1283
  function playHeartbeatEffect(finalResult) {
1284
- wheelContainer.style.display = 'none';
1285
- resultDisplay.style.display = 'block';
1286
 
1287
  resultNumber.textContent = "?";
 
1288
  resultText.textContent = "命运正在抉择...";
1289
 
1290
  // Add heartbeat animation to result number
@@ -1293,10 +1119,18 @@
1293
  // After a few heartbeats, reveal the result
1294
  setTimeout(() => {
1295
  resultNumber.style.animation = 'none';
1296
- resultNumber.classList.add('jump');
 
1297
  resultNumber.textContent = finalResult;
1298
  resultText.textContent = `命运选择了 ${finalResult} 号同学!`;
1299
 
 
 
 
 
 
 
 
1300
  // Add shine effect
1301
  const shine = document.querySelector('.shine');
1302
  shine.style.opacity = '1';
@@ -1304,7 +1138,7 @@
1304
 
1305
  // Reset animations
1306
  setTimeout(() => {
1307
- resultNumber.classList.remove('jump');
1308
  shine.style.opacity = '0';
1309
  shine.style.animation = 'none';
1310
  }, 2000);
@@ -1313,8 +1147,14 @@
1313
  createConfetti();
1314
  }, 4000);
1315
  }
1316
-
1317
  function createConfetti() {
 
 
 
 
 
 
 
1318
  const specialEffects = document.createElement('div');
1319
  specialEffects.className = 'special-effects';
1320
  resultDisplay.appendChild(specialEffects);
@@ -1344,7 +1184,10 @@
1344
  confetti.style.width = size + 'px';
1345
  confetti.style.height = size + 'px';
1346
  confetti.style.backgroundColor = color;
 
 
1347
 
 
1348
  if (shape === 'circle') {
1349
  confetti.style.borderRadius = '50%';
1350
  } else if (shape === 'triangle') {
@@ -1358,27 +1201,7 @@
1358
  const duration = Math.random() * 3 + 2;
1359
  const delay = Math.random() * 1.5;
1360
 
1361
- confetti.style.opacity = '1';
1362
  confetti.style.animation = `fall ${duration}s ease-in ${delay}s forwards`;
1363
-
1364
- // Add keyframe animation for falling confetti
1365
- if (!document.querySelector('#confetti-animation')) {
1366
- const styleSheet = document.createElement('style');
1367
- styleSheet.id = 'confetti-animation';
1368
- styleSheet.textContent = `
1369
- @keyframes fall {
1370
- 0% {
1371
- transform: translateY(0) rotate(0deg);
1372
- opacity: 1;
1373
- }
1374
- 100% {
1375
- transform: translateY(${resultDisplay.clientHeight}px) rotate(360deg);
1376
- opacity: 0;
1377
- }
1378
- }
1379
- `;
1380
- document.head.appendChild(styleSheet);
1381
- }
1382
  }
1383
 
1384
  // Remove confetti after animation
@@ -1391,8 +1214,7 @@
1391
 
1392
  function reset() {
1393
  // Reset to setup panel
1394
- setupPanel.classList.remove('minimized');
1395
- wheelContainer.style.display = 'none';
1396
  resultDisplay.style.display = 'none';
1397
 
1398
  // Reset wheel rotation
@@ -1402,17 +1224,26 @@
1402
  isSpinning = false;
1403
  selectedSegment = null;
1404
  secondSelectedSegment = null;
 
 
 
1405
  }
1406
 
1407
  // Initialize the app
1408
  function init() {
 
 
 
1409
  // Setup event listeners
1410
- startBtn.addEventListener('click', setupWheel);
 
 
 
 
1411
  resetBtn.addEventListener('click', reset);
1412
  spinBtn.addEventListener('click', spin);
1413
  spinAgainBtn.addEventListener('click', () => {
1414
  resultDisplay.style.display = 'none';
1415
- wheelContainer.style.display = 'block';
1416
  });
1417
 
1418
  pickerModeSelect.addEventListener('change', updateModeDescription);
@@ -1429,8 +1260,8 @@
1429
  updateModeDescription();
1430
  }
1431
 
1432
- // Initialize the app
1433
- init();
1434
  </script>
1435
  </body>
1436
  </html>
 
28
  display: flex;
29
  flex-direction: column;
30
  align-items: center;
31
+ padding: 1rem;
32
  }
33
 
34
  .container {
 
37
  display: flex;
38
  flex-direction: column;
39
  align-items: center;
40
+ gap: 1.5rem;
41
  }
42
 
43
  header {
44
  text-align: center;
45
+ margin-bottom: 0.5rem;
46
  }
47
 
48
  h1 {
 
58
  font-weight: 300;
59
  }
60
 
61
+ /* Layout for desktop */
62
+ .main-content {
63
+ display: flex;
64
+ width: 100%;
65
+ flex-direction: row;
66
+ gap: 2rem;
67
+ align-items: flex-start;
68
+ }
69
+
70
  .setup-panel {
71
  background-color: white;
72
+ padding: 1.5rem;
73
  border-radius: 1rem;
74
  box-shadow: 0 10px 30px var(--shadow-color);
75
  width: 100%;
76
+ max-width: 400px;
77
  transition: all 0.3s ease;
78
+ flex-shrink: 0;
79
  }
80
 
81
+ .setup-panel.collapsed {
82
  padding: 1rem;
83
+ max-width: 400px;
 
84
  }
85
 
86
+ .setup-panel.collapsed .form-content {
87
  display: none;
88
  }
89
 
90
+ .setup-panel.collapsed .panel-title {
91
+ margin-bottom: 0;
 
 
92
  }
93
 
94
+ .panel-header {
95
+ display: flex;
96
+ justify-content: space-between;
97
+ align-items: center;
98
  margin-bottom: 1.5rem;
99
+ cursor: pointer;
100
+ }
101
+
102
+ .panel-title {
103
  color: var(--primary-color);
104
+ margin: 0;
105
  }
106
 
107
+ .toggle-panel {
108
+ background: none;
109
+ border: none;
110
+ font-size: 1.5rem;
111
+ color: var(--accent-color);
112
+ cursor: pointer;
113
+ transition: transform 0.3s;
114
+ }
115
+
116
+ .setup-panel.collapsed .toggle-panel {
117
+ transform: rotate(180deg);
118
+ }
119
+
120
+ .form-row {
121
+ display: flex;
122
+ gap: 1rem;
123
  margin-bottom: 1.5rem;
124
+ flex-wrap: wrap;
125
+ }
126
+
127
+ .form-group {
128
+ flex: 1;
129
+ min-width: 150px;
130
  }
131
 
132
  label {
 
170
  box-shadow: 0 6px 15px var(--shadow-color);
171
  }
172
 
 
 
 
 
 
 
 
 
 
 
 
173
  .actions {
174
  display: flex;
175
  justify-content: center;
176
  gap: 1rem;
177
+ flex-wrap: wrap;
178
  }
179
 
180
  .wheel-container {
181
  position: relative;
182
  width: 100%;
183
+ max-width: 500px;
184
  aspect-ratio: 1;
185
+ margin: 0 auto;
 
186
  }
187
 
188
  .wheel {
 
282
 
283
  .result-display {
284
  background-color: white;
285
+ padding: 1.5rem; /* 减小内边距 */
286
  border-radius: 1rem;
287
  box-shadow: 0 10px 30px var(--shadow-color);
288
  text-align: center;
 
289
  width: 100%;
290
+ height: 100%;
291
  display: none;
292
+ position: absolute;
293
+ top: 0;
294
+ left: 0;
295
+ z-index: 10;
296
  overflow: hidden;
297
+ display: flex; /* 使用flex布局 */
298
+ flex-direction: column;
299
+ justify-content: center; /* 垂直居中 */
300
+ align-items: center; /* 水平居中 */
301
  }
302
 
303
  .result-display h2 {
 
306
  }
307
 
308
  .result-number {
309
+ font-size: min(15vw, 8rem); /* 自适应字体大小 */
310
  font-weight: bold;
311
  color: var(--accent-color);
312
+ margin: 0.5rem 0; /* 减小上下边距 */
313
  position: relative;
314
  transition: all 0.3s;
315
+ line-height: 1; /* 设置行高为1,减少垂直空间 */
316
  }
317
 
318
  .result-text {
319
+ font-size: max(1rem, min(3vw, 1.4rem)); /* 自适应字体大小 */
320
+ margin-bottom: 1.2rem;
321
  }
322
 
323
  .shine {
 
371
  box-shadow: 0 0 50px var(--accent-color), 0 0 100px rgba(255, 214, 102, 0.8);
372
  }
373
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  .mode-description {
375
  display: none;
376
  margin-top: 0.5rem;
 
409
  100% { transform: scale(1); }
410
  }
411
 
 
 
 
 
 
 
412
  @keyframes heartbeat {
413
  0% { transform: scale(1); }
414
  15% { transform: scale(1.15); }
 
418
  100% { transform: scale(1); }
419
  }
420
 
421
+ /* Fall animation for confetti */
422
+ @keyframes fall {
423
+ 0% {
424
+ transform: translateY(0) rotate(0deg);
425
+ opacity: 1;
426
+ }
427
+ 100% {
428
+ transform: translateY(400px) rotate(360deg);
429
+ opacity: 0;
430
+ }
 
 
 
 
 
 
 
431
  }
432
 
433
  .help-bubble {
 
484
  cursor: pointer;
485
  color: var(--accent-color);
486
  }
487
+
488
+ /* Media queries for responsive design */
489
+ @media (max-width: 992px) {
490
+ .main-content {
491
+ flex-direction: column;
492
+ align-items: center;
493
+ }
494
+
495
+ .setup-panel {
496
+ max-width: 100%;
497
+ order: 1;
498
+ }
499
+
500
+ .wheel-container {
501
+ order: 0;
502
+ margin-bottom: 1.5rem;
503
+ }
504
+ }
505
+
506
+ @media (max-width: 768px) {
507
+ h1 {
508
+ font-size: 2rem;
509
+ }
510
+
511
+ .container {
512
+ gap: 1rem;
513
+ }
514
+
515
+ .setup-panel, .result-display {
516
+ padding: 1.5rem;
517
+ }
518
+
519
+ .result-number {
520
+ font-size: 3.5rem;
521
+ }
522
+
523
+ .form-row {
524
+ flex-direction: column;
525
+ gap: 1rem;
526
+ }
527
+
528
+ .form-group {
529
+ min-width: 100%;
530
+ }
531
+ }
532
  </style>
533
  </head>
534
  <body>
 
538
  <p class="subtitle">掌控命运,抉择未来!</p>
539
  </header>
540
 
541
+ <div class="main-content">
542
+ <div class="setup-panel">
543
+ <div class="panel-header">
544
+ <h2 class="panel-title">设置</h2>
545
+ <button class="toggle-panel">▲</button>
546
+ </div>
547
+
548
+ <div class="form-content">
549
+ <div class="form-row">
550
+ <div class="form-group">
551
+ <label for="class-size">班级人数:</label>
552
+ <input type="number" id="class-size" min="1" max="100" value="30">
553
+ </div>
554
+
555
+ <div class="form-group">
556
+ <label for="start-number">起始编号:</label>
557
+ <input type="number" id="start-number" min="0" value="1">
558
+ </div>
559
+ </div>
560
+
561
+ <div class="form-row">
562
+ <div class="form-group">
563
+ <label for="animation-speed">动画速度:</label>
564
+ <select id="animation-speed">
565
+ <option value="slow">慢速 (更多悬念)</option>
566
+ <option value="normal" selected>正常</option>
567
+ <option value="fast">快速</option>
568
+ <option value="insane">超快 (刺激模式)</option>
569
+ </select>
570
+ </div>
571
+ </div>
572
+
573
+ <div class="form-row">
574
+ <div class="form-group">
575
+ <label for="picker-mode">选择模式:</label>
576
+ <select id="picker-mode">
577
+ <option value="normal">正常模式</option>
578
+ <option value="fake-out">假动作模式</option>
579
+ <option value="oscillate">摇摆不定模式</option>
580
+ <option value="mystery">神秘模式</option>
581
+ <option value="double">双重选择模式</option>
582
+ <option value="countdown">倒计时模式</option>
583
+ <option value="heartbeat">心跳紧张模式</option>
584
+ </select>
585
+ <div id="mode-normal" class="mode-description">普通的转盘选择,公平公正。</div>
586
+ <div id="mode-fake-out" class="mode-description">即将停止时,转盘会突然改变方向!</div>
587
+ <div id="mode-oscillate" class="mode-description">在两个结果之间反复摇摆到底是谁呢?</div>
588
+ <div id="mode-mystery" class="mode-description">结果会短暂显示然后突然变化,充满惊喜!</div>
589
+ <div id="mode-double" class="mode-description">同时选出两个幸运儿!</div>
590
+ <div id="mode-countdown" class="mode-description">紧张的倒计,增加悬念感!</div>
591
+ <div id="mode-heartbeat" class="mode-description">伴随心跳,感受命运的紧张抉择!</div>
592
+ </div>
593
+ </div>
594
+
595
+ <div class="actions">
596
+ <button id="reset-btn" class="btn">保存修改/重新开始</button>
597
+ </div>
598
+ </div>
599
  </div>
600
 
601
+ <div class="wheel-container">
602
+ <div class="wheel-pointer"></div>
603
+ <div class="wheel">
604
+ <div class="wheel-inner" id="wheel-inner"></div>
605
+ </div>
606
+ <div class="wheel-center" id="spin-btn">转!</div>
607
+
608
+ <div class="result-display">
609
+ <div class="shine"></div>
610
+ <h2>点名结果</h2>
611
+ <div class="result-number" id="result-number">?</div>
612
+ <p class="result-text" id="result-text">请点击转盘开始</p>
613
+ <button id="spin-again-btn" class="btn">再来一次</button>
614
+ </div>
615
  </div>
 
 
 
 
 
 
 
 
 
616
  </div>
617
  </div>
618
 
 
625
  <p><strong>摇摆不定模式:</strong> 在两个选项之间来回摇摆,增加悬念感。</p>
626
  <p><strong>神秘模式:</strong> 先显示一个结果,然后突然改变!谁也猜不到最终会是谁。</p>
627
  <p><strong>双重选择模式:</strong> 同时选出两名同学,适合小组活动。</p>
628
+ <p><strong>倒计时模式:</strong> 伴随紧张的倒计时动画,增加刺激感。</p>
629
+ <p><strong>心跳紧张模式:</strong> 伴随心跳动画让结果更加扣人心弦。</p>
630
+ <p><strong>提示:</strong> 尝试不同的画速度获得最佳体验!</p>
 
 
631
  </div>
632
 
633
  <script>
634
  // DOM Elements
635
  const setupPanel = document.querySelector('.setup-panel');
636
+ const togglePanelBtn = document.querySelector('.toggle-panel');
637
  const classSizeInput = document.getElementById('class-size');
638
  const startNumberInput = document.getElementById('start-number');
639
  const pickerModeSelect = document.getElementById('picker-mode');
640
  const animationSpeedSelect = document.getElementById('animation-speed');
 
 
641
  const resetBtn = document.getElementById('reset-btn');
642
  const wheelContainer = document.querySelector('.wheel-container');
643
  const wheelInner = document.getElementById('wheel-inner');
 
658
  mystery: document.getElementById('mode-mystery'),
659
  double: document.getElementById('mode-double'),
660
  countdown: document.getElementById('mode-countdown'),
 
 
661
  heartbeat: document.getElementById('mode-heartbeat')
662
  };
663
 
664
+ // Colors for the wheel segments (soft green palette)
665
+ const colors = [
666
+ '#4CAF50', '#66BB6A', '#81C784', '#A5D6A7',
667
+ '#C8E6C9', '#7CB342', '#8BC34A', '#9CCC65',
668
+ '#AED581', '#C5E1A5', '#DCEDC8', '#43A047',
669
+ '#388E3C', '#2E7D32', '#689F38', '#558B2F'
670
+ ];
671
+
672
  // Variables
673
  let classSize = 30;
674
  let startNumber = 1;
675
  let mode = 'normal';
676
  let animationSpeed = 'normal';
 
677
  let isSpinning = false;
678
  let segments = [];
679
  let selectedSegment = null;
680
  let secondSelectedSegment = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
681
 
682
  function updateModeDescription() {
683
  const selectedMode = pickerModeSelect.value;
684
 
685
  // Hide all descriptions
686
  Object.values(modeDescriptions).forEach(desc => {
687
+ if (desc) desc.style.display = 'none';
688
  });
689
 
690
  // Show selected description
 
694
  }
695
  }
696
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
697
  function createWheel() {
698
  // Clear previous wheel
699
  wheelInner.innerHTML = '';
700
  segments = [];
701
 
 
 
 
 
 
 
 
 
702
  // Create segments
703
  const segmentAngle = 360 / classSize;
704
 
 
729
  }
730
  }
731
 
732
+ function setupWheel() {
733
+ classSize = parseInt(classSizeInput.value) || 30;
734
+ startNumber = parseInt(startNumberInput.value) || 1;
735
+ mode = pickerModeSelect.value;
736
+ animationSpeed = animationSpeedSelect.value;
737
+
738
+ if (classSize < 1) {
739
+ alert('班级人数必须大于0');
740
+ return;
741
+ }
742
+
743
+ // Create wheel segments
744
+ createWheel();
745
+
746
+ // Show wheel, hide result display if it's shown
747
+ resultDisplay.style.display = 'none';
748
+ }
749
+
750
  function spin() {
751
  if (isSpinning) return;
752
 
 
798
  secondSelectedSegment = segments[secondIndex];
799
  }
800
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
801
  // Process result after spinning animation
802
  setTimeout(() => {
803
  processResult();
 
811
  let finalResult = selectedSegment.value;
812
  let secondResult = secondSelectedSegment ? secondSelectedSegment.value : null;
813
 
 
 
 
 
 
 
 
 
 
 
814
  switch (mode) {
815
  case 'fake-out':
816
  playFakeOutEffect(finalResult);
 
832
  playCountdownEffect(finalResult);
833
  break;
834
 
 
 
 
 
 
 
 
 
835
  case 'heartbeat':
836
  playHeartbeatEffect(finalResult);
837
  break;
 
843
  }
844
 
845
  function showResult(result) {
846
+ resultDisplay.style.display = 'flex'; // 使用flex布局显示
 
847
 
848
  resultNumber.textContent = result;
849
  resultText.textContent = `恭喜 ${result} 号同学被选中!`;
850
 
851
+ // 根据结果数字的长度动态调整字体大小
852
+ if (result.toString().length > 2) {
853
+ resultNumber.style.fontSize = `min(12vw, 6rem)`;
854
+ } else {
855
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
856
+ }
857
+
858
+ // 添加闪光效果
859
  const shine = document.querySelector('.shine');
860
  shine.style.opacity = '1';
861
  shine.style.animation = 'shine 2s 1';
862
 
863
+ // 重置动画
864
  setTimeout(() => {
865
  shine.style.opacity = '0';
866
  shine.style.animation = 'none';
867
  }, 2000);
868
 
869
+ // 添加纸屑效果
870
  createConfetti();
871
  }
 
872
  function showDoubleResult(result1, result2) {
873
+ resultDisplay.style.display = 'flex'; // Use flex layout
 
874
 
875
  resultNumber.textContent = `${result1} & ${result2}`;
876
  resultText.textContent = `恭喜 ${result1} 号和 ${result2} 号同学被选中!`;
877
 
878
+ // Adjust font size based on content length
879
+ if (result1.toString().length + result2.toString().length > 4) {
880
+ resultNumber.style.fontSize = `min(10vw, 5rem)`;
881
+ } else {
882
+ resultNumber.style.fontSize = `min(12vw, 6rem)`;
883
+ }
884
+
885
  // Add shine effect
886
  const shine = document.querySelector('.shine');
887
  shine.style.opacity = '1';
888
  shine.style.animation = 'shine 2s 1';
889
 
890
+ // Reset animations
891
  setTimeout(() => {
892
  shine.style.opacity = '0';
893
  shine.style.animation = 'none';
 
896
  // Add confetti effect
897
  createConfetti();
898
  }
 
899
  function playFakeOutEffect(finalResult) {
900
  // First show a fake result
901
  const fakeResult = ((finalResult - startNumber + Math.floor(classSize / 2)) % classSize) + startNumber;
902
 
903
+ resultDisplay.style.display = 'flex';
 
904
 
905
  resultNumber.textContent = fakeResult;
906
  resultText.textContent = `恭喜 ${fakeResult} 号同学被选中!`;
907
 
908
+ // Adjust font size based on number length
909
+ if (fakeResult.toString().length > 2) {
910
+ resultNumber.style.fontSize = `min(12vw, 6rem)`;
911
+ } else {
912
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
913
+ }
914
+
915
  // After a short delay, apply shake effect and change to actual result
916
  setTimeout(() => {
917
+ resultNumber.style.animation = 'shake 0.5s';
918
  resultText.textContent = "等等,发生了什么...";
919
 
920
  // After shake effect, reveal true result
921
  setTimeout(() => {
922
+ resultNumber.style.animation = 'none';
923
+ resultNumber.offsetHeight; // Trigger reflow to restart animation
924
+ resultNumber.style.animation = 'jump 0.5s';
925
  resultNumber.textContent = finalResult;
926
  resultText.textContent = `真正被选中的是 ${finalResult} 号同学!`;
927
 
928
+ // Adjust font size for final result
929
+ if (finalResult.toString().length > 2) {
930
+ resultNumber.style.fontSize = `min(12vw, 6rem)`;
931
+ } else {
932
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
933
+ }
934
+
935
  // Add shine effect
936
  const shine = document.querySelector('.shine');
937
  shine.style.opacity = '1';
 
939
 
940
  // Reset animations
941
  setTimeout(() => {
942
+ resultNumber.style.animation = 'none';
943
  shine.style.opacity = '0';
944
  shine.style.animation = 'none';
945
  }, 2000);
 
949
  }, 1000);
950
  }, 1500);
951
  }
 
952
  function playOscillateEffect(finalResult) {
953
  // Create alternative result
954
  const altResult = ((finalResult - startNumber + Math.floor(classSize / 2)) % classSize) + startNumber;
955
 
956
+ resultDisplay.style.display = 'flex';
957
+
958
+ // Initial font size setting
959
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
960
 
961
  let count = 0;
962
  const maxOscillations = 6;
963
  const oscillationInterval = setInterval(() => {
964
  count++;
965
+ const currentResult = count % 2 === 0 ? finalResult : altResult;
966
+ resultNumber.textContent = currentResult;
967
  resultText.textContent = "究竟会是谁呢...";
968
 
969
+ // Adjust font size based on displayed number
970
+ if (currentResult.toString().length > 2) {
971
+ resultNumber.style.fontSize = `min(12vw, 6rem)`;
972
+ } else {
973
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
974
+ }
975
+
976
  if (count >= maxOscillations) {
977
  clearInterval(oscillationInterval);
978
  // Final result with visual effect
979
+ resultNumber.style.animation = 'jump 0.5s';
980
  resultNumber.textContent = finalResult;
981
  resultText.textContent = `恭喜 ${finalResult} 号同学被选中!`;
982
 
 
987
 
988
  // Reset animations
989
  setTimeout(() => {
990
+ resultNumber.style.animation = 'none';
991
  shine.style.opacity = '0';
992
  shine.style.animation = 'none';
993
  }, 2000);
 
997
  }
998
  }, 300);
999
  }
 
1000
  function playMysteryEffect(finalResult) {
1001
  // Generate a series of random results ending with the actual one
1002
  const mysterySteps = 3;
1003
  const stepDelay = 600;
1004
 
1005
+ resultDisplay.style.display = 'flex';
 
1006
 
1007
  let step = 0;
1008
  resultText.textContent = "神秘数字即将揭晓...";
1009
 
1010
  // Add flicker effect to create suspense
1011
+ resultNumber.style.animation = 'flicker 0.5s infinite';
1012
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
1013
 
1014
  const mysteryInterval = setInterval(() => {
1015
  step++;
 
1018
  // Show random number
1019
  const randomNumber = Math.floor(Math.random() * classSize) + startNumber;
1020
  resultNumber.textContent = randomNumber;
1021
+
1022
+ // Adjust font size based on random number
1023
+ if (randomNumber.toString().length > 2) {
1024
+ resultNumber.style.fontSize = `min(12vw, 6rem)`;
1025
+ } else {
1026
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
1027
+ }
1028
  } else {
1029
  // Last step - show real result
1030
  clearInterval(mysteryInterval);
1031
+ resultNumber.style.animation = 'none';
1032
+ resultNumber.offsetHeight; // Trigger reflow to restart animation
1033
+ resultNumber.style.animation = 'jump 0.5s';
1034
  resultNumber.textContent = finalResult;
1035
  resultText.textContent = `恭喜 ${finalResult} 号同学被选中!`;
1036
 
1037
+ // Adjust font size for final result
1038
+ if (finalResult.toString().length > 2) {
1039
+ resultNumber.style.fontSize = `min(12vw, 6rem)`;
1040
+ } else {
1041
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
1042
+ }
1043
+
1044
  // Add shine effect
1045
  const shine = document.querySelector('.shine');
1046
  shine.style.opacity = '1';
 
1048
 
1049
  // Reset animations
1050
  setTimeout(() => {
1051
+ resultNumber.style.animation = 'none';
1052
  shine.style.opacity = '0';
1053
  shine.style.animation = 'none';
1054
  }, 2000);
 
1058
  }
1059
  }, stepDelay);
1060
  }
 
1061
  function playCountdownEffect(finalResult) {
1062
+ resultDisplay.style.display = 'flex';
 
1063
 
1064
  resultNumber.textContent = "3";
1065
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
1066
  resultText.textContent = "倒计时开始...";
1067
 
1068
  // Countdown animation
1069
  setTimeout(() => {
1070
+ resultNumber.style.animation = 'jump 0.5s';
1071
  resultNumber.textContent = "2";
1072
+ setTimeout(() => { resultNumber.style.animation = 'none'; }, 500);
 
1073
  }, 1000);
1074
 
1075
  setTimeout(() => {
1076
+ resultNumber.style.animation = 'jump 0.5s';
1077
  resultNumber.textContent = "1";
1078
+ setTimeout(() => { resultNumber.style.animation = 'none'; }, 500);
 
1079
  }, 2000);
1080
 
1081
  setTimeout(() => {
1082
+ resultNumber.style.animation = 'jump 0.5s';
1083
  resultNumber.textContent = finalResult;
1084
  resultText.textContent = `恭喜 ${finalResult} 号同学被选中!`;
1085
 
1086
+ // Adjust font size for final result
1087
+ if (finalResult.toString().length > 2) {
1088
+ resultNumber.style.fontSize = `min(12vw, 6rem)`;
1089
+ } else {
1090
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
1091
+ }
1092
+
1093
  // Add shine effect
1094
  const shine = document.querySelector('.shine');
1095
  shine.style.opacity = '1';
 
1097
 
1098
  // Reset animations
1099
  setTimeout(() => {
1100
+ resultNumber.style.animation = 'none';
1101
  shine.style.opacity = '0';
1102
  shine.style.animation = 'none';
1103
  }, 2000);
 
1106
  createConfetti();
1107
  }, 3000);
1108
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1109
  function playHeartbeatEffect(finalResult) {
1110
+ resultDisplay.style.display = 'flex';
 
1111
 
1112
  resultNumber.textContent = "?";
1113
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
1114
  resultText.textContent = "命运正在抉择...";
1115
 
1116
  // Add heartbeat animation to result number
 
1119
  // After a few heartbeats, reveal the result
1120
  setTimeout(() => {
1121
  resultNumber.style.animation = 'none';
1122
+ resultNumber.offsetHeight; // Trigger reflow to restart animation
1123
+ resultNumber.style.animation = 'jump 0.5s';
1124
  resultNumber.textContent = finalResult;
1125
  resultText.textContent = `命运选择了 ${finalResult} 号同学!`;
1126
 
1127
+ // Adjust font size for final result
1128
+ if (finalResult.toString().length > 2) {
1129
+ resultNumber.style.fontSize = `min(12vw, 6rem)`;
1130
+ } else {
1131
+ resultNumber.style.fontSize = `min(15vw, 8rem)`;
1132
+ }
1133
+
1134
  // Add shine effect
1135
  const shine = document.querySelector('.shine');
1136
  shine.style.opacity = '1';
 
1138
 
1139
  // Reset animations
1140
  setTimeout(() => {
1141
+ resultNumber.style.animation = 'none';
1142
  shine.style.opacity = '0';
1143
  shine.style.animation = 'none';
1144
  }, 2000);
 
1147
  createConfetti();
1148
  }, 4000);
1149
  }
 
1150
  function createConfetti() {
1151
+ // Clear any existing confetti
1152
+ const existingEffects = document.querySelector('.special-effects');
1153
+ if (existingEffects) {
1154
+ existingEffects.remove();
1155
+ }
1156
+
1157
+ // Create container for confetti
1158
  const specialEffects = document.createElement('div');
1159
  specialEffects.className = 'special-effects';
1160
  resultDisplay.appendChild(specialEffects);
 
1184
  confetti.style.width = size + 'px';
1185
  confetti.style.height = size + 'px';
1186
  confetti.style.backgroundColor = color;
1187
+ confetti.style.opacity = '1';
1188
+ confetti.style.position = 'absolute';
1189
 
1190
+ // Set shape
1191
  if (shape === 'circle') {
1192
  confetti.style.borderRadius = '50%';
1193
  } else if (shape === 'triangle') {
 
1201
  const duration = Math.random() * 3 + 2;
1202
  const delay = Math.random() * 1.5;
1203
 
 
1204
  confetti.style.animation = `fall ${duration}s ease-in ${delay}s forwards`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1205
  }
1206
 
1207
  // Remove confetti after animation
 
1214
 
1215
  function reset() {
1216
  // Reset to setup panel
1217
+ setupPanel.classList.remove('collapsed');
 
1218
  resultDisplay.style.display = 'none';
1219
 
1220
  // Reset wheel rotation
 
1224
  isSpinning = false;
1225
  selectedSegment = null;
1226
  secondSelectedSegment = null;
1227
+
1228
+ // Recreate wheel with current settings
1229
+ setupWheel();
1230
  }
1231
 
1232
  // Initialize the app
1233
  function init() {
1234
+ // Create the wheel for the first time
1235
+ setupWheel();
1236
+
1237
  // Setup event listeners
1238
+ togglePanelBtn.addEventListener('click', () => {
1239
+ setupPanel.classList.toggle('collapsed');
1240
+ togglePanelBtn.textContent = setupPanel.classList.contains('collapsed') ? '▼' : '▲';
1241
+ });
1242
+
1243
  resetBtn.addEventListener('click', reset);
1244
  spinBtn.addEventListener('click', spin);
1245
  spinAgainBtn.addEventListener('click', () => {
1246
  resultDisplay.style.display = 'none';
 
1247
  });
1248
 
1249
  pickerModeSelect.addEventListener('change', updateModeDescription);
 
1260
  updateModeDescription();
1261
  }
1262
 
1263
+ // Initialize the app when the document is loaded
1264
+ document.addEventListener('DOMContentLoaded', init);
1265
  </script>
1266
  </body>
1267
  </html>