๐ฐ ๋๋ค ์ ์ฌ ๋ฉ๋ด ๋ฃฐ๋ - ์ค๋ ๋ญ ๋จน์ง? ๊ณ ๋ฏผ ๋!
lunch-menu-roulette
๋ฌธ์ ์ค๋ช
๐ฝ๏ธ ํ๋ก์ ํธ ๊ฐ์
์ ์ฌ ๋ฉ๋ด ์ ํ ๊ณ ๋ฏผ์ ํด๊ฒฐํด์ฃผ๋ ์ธํฐ๋ํฐ๋ธ ๋ฃฐ๋ ํ์ด์ง์ ๋๋ค. ์ฌ์ฉ์๊ฐ ๋ฉ๋ด ํ๋ณด๋ฅผ ์ถ๊ฐํ๊ณ , ๋ฃฐ๋ ์ ๋๋ ค ๋๋ค์ผ๋ก ์ค๋์ ์ ์ฌ ๋ฉ๋ด๋ฅผ ๊ฒฐ์ ํฉ๋๋ค. ์ ๋๋ฉ์ด์ ๊ณผ ์ฌ์ด๋ ํจ๊ณผ๋ก ์ฌ๋ฏธ๋ฅผ ๋ํ์ต๋๋ค.
โจ ํ์ ๊ธฐ๋ฅ
- ๋ฉ๋ด ์ ๋ ฅ ํผ - ์ฌ์ฉ์๊ฐ ์ ์ฌ ๋ฉ๋ด ํ๋ณด๋ฅผ ์์ ๋กญ๊ฒ ์ถ๊ฐ (์: ๊น์น์ฐ๊ฐ, ํ์คํ, ํ๋ฒ๊ฑฐ)
- ๋ฉ๋ด ๋ชฉ๋ก ๊ด๋ฆฌ - ์ถ๊ฐ๋ ๋ฉ๋ด๋ฅผ ๋ฆฌ์คํธ๋ก ํ์, ๊ฐ๋ณ ์ญ์ ๊ฐ๋ฅ
- ๋ฃฐ๋ ์ ๋๋ฉ์ด์ - ์ํ ๋ฃฐ๋ ์ด ํ์ ํ๋ฉฐ ๋๋ค ๋ฉ๋ด ์ ํ
- ๊ฒฐ๊ณผ ํ์ - ์ ํ๋ ๋ฉ๋ด๋ฅผ ํฌ๊ฒ ๊ฐ์กฐํ์ฌ ํ์ (์ถํ ์ดํํธ ํฌํจ)
- ๋คํฌ๋ชจ๋ ์๋ ๋์ - modern shell์ ๋์์ธ ํ ํฐ ํ์ฉ
- ๋ก์ปฌ ์คํ ๋ฆฌ์ง ์ ์ฅ - ์ ๋ ฅํ ๋ฉ๋ด ๋ชฉ๋ก์ ๋ธ๋ผ์ฐ์ ์ ์ ์ฅํ์ฌ ์๋ก๊ณ ์นจ ํ์๋ ์ ์ง
๐ ์ ํ ์ถ๊ฐ ๊ธฐ๋ฅ (๋ณด๋์ค)
- ๋ฃฐ๋ ํ์ ์ ํจ๊ณผ์ ์ฌ์ (Web Audio API)
- ๋ฉ๋ด๋ณ ๊ฐ์ค์น ์ค์ (์์ฃผ ๋จน๊ณ ์ถ์ ๋ฉ๋ด๋ ๋น์ฒจ ํ๋ฅ ๋์ด๊ธฐ)
- ์ต๊ทผ ๋น์ฒจ ๋ฉ๋ด ํ์คํ ๋ฆฌ ํ์ (์ค๋/์ด์ /๊ทธ์ ๊ป ๋ญ ๋จน์๋์ง)
- ๋ฉ๋ด ์นดํ ๊ณ ๋ฆฌ ํํฐ (ํ์/์ค์/์ผ์/์์)
- ๋ฃฐ๋ ํ ๋ง ๋ณ๊ฒฝ (์์ ์คํด ์ ํ)
๐ฏ ํ์ต ๋ชฉํ
- g5se์ ํด๋ ๊ธฐ๋ฐ ์๋ ๋ผ์ฐํ ์ฒดํ
- modern shell์ ํ์ฉํ ์ผ๊ด๋ ์ฌ์ดํธ ๋์์ธ ์ ์ฉ
- ์์ JavaScript๋ก Canvas ์ ๋๋ฉ์ด์ ๊ตฌํ
- localStorage API๋ฅผ ํ์ฉํ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋ฐ์ดํฐ ์ ์ฅ
- CSS ๋ณ์(๋์์ธ ํ ํฐ)๋ฅผ ํ์ฉํ ๋คํฌ๋ชจ๋ ๋์
๐ก ๊ตฌํ ํ
- ๋ฃฐ๋ ๊ทธ๋ฆฌ๊ธฐ๋ HTML5 Canvas API ์ฌ์ฉ
- ๋ฉ๋ด ๋ชฉ๋ก์ JSON ํํ๋ก localStorage์ ์ ์ฅ
- ํ์ ์ ๋๋ฉ์ด์
์
requestAnimationFrame์ผ๋ก ๋ถ๋๋ฝ๊ฒ ์ฒ๋ฆฌ - ๋น์ฒจ ํจ๊ณผ๋ CSS animation + JavaScript ์กฐํฉ
์ ์ฝ ์กฐ๊ฑด
- โข g5se ๊ธฐ๋ฐ ์์ PHP ํ๋ก์ ํธ (Laravel/Composer/npm ์ฌ์ฉ ๊ธ์ง)
- โข app/modules/lunch-menu-roulette/index.php ๋จ์ผ ํ์ด์ง๋ก ๊ตฌํ
- โข modern shell (_head.inc.php + m-shell + _nav.inc.php + m-container + _footer.inc.php) ํ์ ์ ์ฉ
- โข ๋์์ธ ํ ํฐ (--m-surface, --m-text, --m-shadow ๋ฑ) ์ฌ์ฉํ์ฌ ๋คํฌ๋ชจ๋ ์๋ ๋์
- โข ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ ๊ธ์ง (localStorage๋ก ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ์ ์ฅ)
- โข ์ธ๋ถ CDN ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ๊ธ์ง (์์ HTML/CSS/JS)
- โข Canvas API๋ก ๋ฃฐ๋ UI ์ง์ ๊ตฌํ
- โข ์ฌ์ฉ์ ์ ๋ ฅ์ htmlspecialchars()๋ก ์ด์ค์ผ์ดํ
ํ๋กฌํํธ ๋ ์ํผ
์๋ ํ๋กฌํํธ๋ฅผ ์์๋๋ก AI์๊ฒ ๋ณด๋ด๋ฉด ๋ฉ๋๋ค. ๋ณต์ฌ ๋ฒํผ์ ๋๋ฌ ๋ฐ๋ก ์ฌ์ฉํ์ธ์.
g5se๊ฐ ์ค์น๋ ๋๋ ํฐ๋ฆฌ(๋ฃจํธ์ `index.php`ยท`app/`์ด ์๋ ๊ณณ)์์ ์์
์ ์์ํฉ๋๋ค. (g5se ์ค์น๋ https://github.com/gnuboard/g5se ์ฐธ๊ณ )
## Step 1: ๊ธฐ๋ณธ ํ์ด์ง ๊ตฌ์กฐ ์์ฑ
`app/modules/lunch-menu-roulette/index.php` ํ์ผ์ ์์ฑํ๊ณ modern shell ๊ณจ๊ฒฉ์ ์ ์ฉํฉ๋๋ค.
```php
<?php
include_once('./_common.php');
require_once(G5_THEME_PATH.'/modern/_head.inc.php');
include_once('./head.sub.php');
?>
<style>
.roulette-container {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.page-header {
margin-bottom: 32px;
}
.page-header h1 {
font-size: 2rem;
font-weight: 700;
color: var(--m-text);
margin-bottom: 8px;
}
.page-header p {
color: var(--m-text-muted);
font-size: 1rem;
}
.menu-input-section {
background: var(--m-surface);
padding: 24px;
border-radius: var(--m-radius-lg);
box-shadow: var(--m-shadow);
margin-bottom: 32px;
}
.menu-form {
display: flex;
gap: 12px;
margin-bottom: 16px;
}
.menu-form input {
flex: 1;
padding: 12px 16px;
border: 1px solid var(--m-border, #e5e7eb);
border-radius: 8px;
font-size: 1rem;
background: var(--m-surface);
color: var(--m-text);
}
.menu-form input:focus {
outline: none;
border-color: #3b82f6;
}
.menu-form button {
padding: 12px 24px;
background: #3b82f6;
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}
.menu-form button:hover {
background: #2563eb;
}
.menu-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
min-height: 40px;
}
.menu-item {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: #f3f4f6;
border-radius: 20px;
font-size: 0.9rem;
color: #374151;
}
[data-theme="dark"] .menu-item {
background: #374151;
color: #e5e7eb;
}
.menu-item button {
background: none;
border: none;
color: #ef4444;
cursor: pointer;
font-size: 1.1rem;
padding: 0;
line-height: 1;
}
.canvas-section {
background: var(--m-surface);
padding: 32px;
border-radius: var(--m-radius-lg);
box-shadow: var(--m-shadow);
margin-bottom: 24px;
}
#rouletteCanvas {
max-width: 100%;
border-radius: 50%;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
}
.spin-button {
margin-top: 24px;
padding: 16px 48px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 12px;
font-size: 1.2rem;
font-weight: 700;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.spin-button:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
}
.spin-button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.result-section {
background: var(--m-surface);
padding: 24px;
border-radius: var(--m-radius-lg);
box-shadow: var(--m-shadow);
min-height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.result-content {
text-align: center;
}
.result-emoji {
font-size: 3rem;
margin-bottom: 12px;
}
.result-text {
font-size: 1.5rem;
font-weight: 700;
color: var(--m-text);
}
.result-menu {
font-size: 2rem;
font-weight: 900;
color: #667eea;
margin-top: 8px;
}
.empty-state {
color: var(--m-text-muted);
font-size: 0.95rem;
}
</style>
<div class="m-shell">
<?php require G5_THEME_PATH.'/modern/_nav.inc.php'; ?>
<main class="m-container" style="padding: 32px 20px 48px;">
<div class="roulette-container">
<div class="page-header">
<h1>๐ฐ ๋๋ค ์ ์ฌ ๋ฉ๋ด ๋ฃฐ๋ </h1>
<p>์ค๋ ๋ญ ๋จน์ง? ๊ณ ๋ฏผ์ ๊ทธ๋ง, ๋ฃฐ๋ ์ด ๊ฒฐ์ ํด๋๋ ค์!</p>
</div>
<div class="menu-input-section">
<form class="menu-form" id="menuForm">
<input
type="text"
id="menuInput"
placeholder="๋ฉ๋ด ์ด๋ฆ ์
๋ ฅ (์: ๊น์น์ฐ๊ฐ, ํ์คํ)"
maxlength="20"
required
>
<button type="submit">์ถ๊ฐ</button>
</form>
<div class="menu-list" id="menuList">
<span class="empty-state">์์ง ์ถ๊ฐ๋ ๋ฉ๋ด๊ฐ ์์ด์. ์์์ ๋ฉ๋ด๋ฅผ ์ถ๊ฐํด๋ณด์ธ์!</span>
</div>
</div>
<div class="canvas-section">
<canvas id="rouletteCanvas" width="400" height="400"></canvas>
<div>
<button class="spin-button" id="spinButton" disabled>๋ฃฐ๋ ๋๋ฆฌ๊ธฐ ๐ฒ</button>
</div>
</div>
<div class="result-section" id="resultSection" style="display: none;">
<div class="result-content">
<div class="result-emoji">๐</div>
<div class="result-text">์ค๋์ ์ ์ฌ ๋ฉ๋ด๋</div>
<div class="result-menu" id="resultMenu"></div>
</div>
</div>
</div>
</main>
<?php require G5_THEME_PATH.'/modern/_footer.inc.php'; ?>
</div>
<?php include_once('./tail.sub.php'); ?>
```
์ด ๋จ๊ณ์์๋ ํ์ด์ง์ HTML ๊ตฌ์กฐ์ CSS ์คํ์ผ๋ง ์์ฑํฉ๋๋ค. ๋ค์ ๋จ๊ณ์์ JavaScript ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์์ ์
๋๋ค.
๊ธฐ๋ ๊ฒฐ๊ณผ: ๋ธ๋ผ์ฐ์ ์์ `/lunch-menu-roulette` ์ ์ ์ modern shell์ด ์ ์ฉ๋ ํ์ด์ง๊ฐ ํ์๋ฉ๋๋ค. ๋ฉ๋ด ์ ๋ ฅ ํผ, ๋น ์บ๋ฒ์ค ์์ญ, ๋นํ์ฑํ๋ ๋ฃฐ๋ ๋ฒํผ์ด ๋ณด์ด๋ฉฐ, ๋คํฌ๋ชจ๋ ํ ๊ธ ์ ์์์ด ์๋์ผ๋ก ๋ณ๊ฒฝ๋ฉ๋๋ค. ์์ง ๊ธฐ๋ฅ์ ๋์ํ์ง ์์ต๋๋ค.
## Step 2: ๋ฉ๋ด ๊ด๋ฆฌ ๊ธฐ๋ฅ ๊ตฌํ (JavaScript)
`app/modules/lunch-menu-roulette/index.php` ํ์ผ์ `<?php include_once('./tail.sub.php'); ?>` ๋ฐ๋ก ์์ ๋ค์ JavaScript ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค:
```html
<script>
// ์ ์ญ ๋ณ์
let menuList = [];
const STORAGE_KEY = 'lunch_menu_roulette_items';
// ํ์ด์ง ๋ก๋ ์ localStorage์์ ๋ฉ๋ด ๋ถ๋ฌ์ค๊ธฐ
window.addEventListener('DOMContentLoaded', () => {
loadMenuFromStorage();
renderMenuList();
updateSpinButton();
});
// localStorage์์ ๋ฉ๋ด ๋ก๋
function loadMenuFromStorage() {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
try {
menuList = JSON.parse(saved);
} catch (e) {
console.error('๋ฉ๋ด ๋ก๋ ์คํจ:', e);
menuList = [];
}
}
}
// localStorage์ ๋ฉ๋ด ์ ์ฅ
function saveMenuToStorage() {
localStorage.setItem(STORAGE_KEY, JSON.stringify(menuList));
}
// ๋ฉ๋ด ์ถ๊ฐ
document.getElementById('menuForm').addEventListener('submit', (e) => {
e.preventDefault();
const input = document.getElementById('menuInput');
const menuName = input.value.trim();
if (!menuName) return;
// ์ค๋ณต ์ฒดํฌ
if (menuList.includes(menuName)) {
alert('์ด๋ฏธ ์ถ๊ฐ๋ ๋ฉ๋ด์
๋๋ค!');
return;
}
menuList.push(menuName);
saveMenuToStorage();
renderMenuList();
updateSpinButton();
input.value = '';
input.focus();
});
// ๋ฉ๋ด ์ญ์
function removeMenu(index) {
menuList.splice(index, 1);
saveMenuToStorage();
renderMenuList();
updateSpinButton();
}
// ๋ฉ๋ด ๋ฆฌ์คํธ ๋ ๋๋ง
function renderMenuList() {
const container = document.getElementById('menuList');
if (menuList.length === 0) {
container.innerHTML = '<span class="empty-state">์์ง ์ถ๊ฐ๋ ๋ฉ๋ด๊ฐ ์์ด์. ์์์ ๋ฉ๋ด๋ฅผ ์ถ๊ฐํด๋ณด์ธ์!</span>';
return;
}
container.innerHTML = menuList.map((menu, index) => `
<div class="menu-item">
<span>${escapeHtml(menu)}</span>
<button onclick="removeMenu(${index})" title="์ญ์ ">ร</button>
</div>
`).join('');
}
// ๋ฃฐ๋ ๋ฒํผ ํ์ฑํ/๋นํ์ฑํ
function updateSpinButton() {
const button = document.getElementById('spinButton');
button.disabled = menuList.length < 2;
if (menuList.length < 2) {
button.textContent = '์ต์ 2๊ฐ ์ด์์ ๋ฉ๋ด๋ฅผ ์ถ๊ฐํ์ธ์';
} else {
button.textContent = '๋ฃฐ๋ ๋๋ฆฌ๊ธฐ ๐ฒ';
}
}
// XSS ๋ฐฉ์ง์ฉ HTML ์ด์ค์ผ์ดํ
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
</script>
```
์ด ๋จ๊ณ์์๋ ๋ฉ๋ด ์ถ๊ฐ/์ญ์ /์ ์ฅ/๋ถ๋ฌ์ค๊ธฐ ๊ธฐ๋ฅ์ ์์ฑํฉ๋๋ค.
๊ธฐ๋ ๊ฒฐ๊ณผ: ๋ฉ๋ด ์ ๋ ฅ ํผ์์ ๋ฉ๋ด๋ฅผ ์ถ๊ฐํ๋ฉด ์๋ ๋ฆฌ์คํธ์ ํ์๋๊ณ , ๊ฐ ๋ฉ๋ด ์ ร๋ฒํผ์ผ๋ก ์ญ์ ํ ์ ์์ต๋๋ค. ๋ฉ๋ด๊ฐ 2๊ฐ ์ด์์ด๋ฉด ๋ฃฐ๋ ๋ฒํผ์ด ํ์ฑํ๋ฉ๋๋ค. ํ์ด์ง๋ฅผ ์๋ก๊ณ ์นจํด๋ ์ถ๊ฐํ ๋ฉ๋ด๊ฐ ์ ์ง๋ฉ๋๋ค.
## Step 3: ๋ฃฐ๋ Canvas ๊ทธ๋ฆฌ๊ธฐ ๋ฐ ํ์ ์ ๋๋ฉ์ด์
`app/modules/lunch-menu-roulette/index.php`์ `<script>` ํ๊ทธ ๋ด๋ถ ๋งจ ์๋์ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค:
```javascript
// Canvas ๊ด๋ จ ๋ณ์
const canvas = document.getElementById('rouletteCanvas');
const ctx = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 180;
let currentRotation = 0;
let isSpinning = false;
// ๋ฃฐ๋ ์์ ํ๋ ํธ
const colors = [
'#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A',
'#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E2',
'#F8B500', '#52B788', '#E07A5F', '#81B29A'
];
// ๋ฃฐ๋ ๊ทธ๋ฆฌ๊ธฐ
function drawRoulette() {
if (menuList.length === 0) {
// ๋ฉ๋ด๊ฐ ์์ ๋ ๊ธฐ๋ณธ ์
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
ctx.fillStyle = '#f3f4f6';
ctx.fill();
ctx.strokeStyle = '#d1d5db';
ctx.lineWidth = 3;
ctx.stroke();
ctx.fillStyle = '#9ca3af';
ctx.font = '16px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('๋ฉ๋ด๋ฅผ ์ถ๊ฐํด์ฃผ์ธ์', centerX, centerY);
return;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate(currentRotation);
const sliceAngle = (2 * Math.PI) / menuList.length;
// ๊ฐ ์กฐ๊ฐ ๊ทธ๋ฆฌ๊ธฐ
menuList.forEach((menu, index) => {
const startAngle = index * sliceAngle;
const endAngle = startAngle + sliceAngle;
// ์กฐ๊ฐ ์์น
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.arc(0, 0, radius, startAngle, endAngle);
ctx.closePath();
ctx.fillStyle = colors[index % colors.length];
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 3;
ctx.stroke();
// ํ
์คํธ
ctx.save();
ctx.rotate(startAngle + sliceAngle / 2);
ctx.textAlign = 'center';
ctx.fillStyle = '#fff';
ctx.font = 'bold 16px sans-serif';
ctx.fillText(menu, radius * 0.6, 5);
ctx.restore();
});
ctx.restore();
// ์ค์ ์ (์ฅ์)
ctx.beginPath();
ctx.arc(centerX, centerY, 20, 0, 2 * Math.PI);
ctx.fillStyle = '#fff';
ctx.fill();
ctx.strokeStyle = '#333';
ctx.lineWidth = 2;
ctx.stroke();
// ์๋จ ํฌ์ธํฐ (๊ณ ์ )
ctx.beginPath();
ctx.moveTo(centerX, 30);
ctx.lineTo(centerX - 15, 60);
ctx.lineTo(centerX + 15, 60);
ctx.closePath();
ctx.fillStyle = '#ef4444';
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 2;
ctx.stroke();
}
// ๋ฃฐ๋ ํ์ ์ ๋๋ฉ์ด์
function spinRoulette() {
if (isSpinning || menuList.length < 2) return;
isSpinning = true;
document.getElementById('spinButton').disabled = true;
document.getElementById('resultSection').style.display = 'none';
// ๋๋ค ํ์ ๊ฐ๋ (์ต์ 5๋ฐํด + ๋๋ค)
const minSpins = 5;
const extraRotation = Math.random() * 2 * Math.PI;
const targetRotation = currentRotation + (minSpins * 2 * Math.PI) + extraRotation;
const duration = 3000; // 3์ด
const startTime = Date.now();
const startRotation = currentRotation;
function animate() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
// easeOut ํจ๊ณผ
const easeProgress = 1 - Math.pow(1 - progress, 3);
currentRotation = startRotation + (targetRotation - startRotation) * easeProgress;
drawRoulette();
if (progress < 1) {
requestAnimationFrame(animate);
} else {
// ํ์ ์๋ฃ
currentRotation = targetRotation % (2 * Math.PI);
isSpinning = false;
document.getElementById('spinButton').disabled = false;
showResult();
}
}
animate();
}
// ๊ฒฐ๊ณผ ํ์
function showResult() {
// ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ๋ฉ๋ด ๊ณ์ฐ (์๋จ ๊ธฐ์ค)
const sliceAngle = (2 * Math.PI) / menuList.length;
const normalizedRotation = (2 * Math.PI - (currentRotation % (2 * Math.PI))) % (2 * Math.PI);
const selectedIndex = Math.floor(normalizedRotation / sliceAngle) % menuList.length;
const selectedMenu = menuList[selectedIndex];
document.getElementById('resultMenu').textContent = selectedMenu;
document.getElementById('resultSection').style.display = 'flex';
// ๊ฒฐ๊ณผ ์น์
์คํฌ๋กค
setTimeout(() => {
document.getElementById('resultSection').scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}, 100);
}
// ๋ฃฐ๋ ๋ฒํผ ์ด๋ฒคํธ
document.getElementById('spinButton').addEventListener('click', spinRoulette);
// ์ด๊ธฐ ๋ฃฐ๋ ๊ทธ๋ฆฌ๊ธฐ
drawRoulette();
// ๋ฉ๋ด ๋ณ๊ฒฝ ์ ๋ฃฐ๋ ๋ค์ ๊ทธ๋ฆฌ๊ธฐ
const originalRenderMenuList = renderMenuList;
renderMenuList = function() {
originalRenderMenuList();
currentRotation = 0; // ๋ฉ๋ด ๋ณ๊ฒฝ ์ ํ์ ์ด๊ธฐํ
drawRoulette();
};
</script>
```
์ด ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ฉด ๋ฃฐ๋ ์ ๋ชจ๋ ๊ธฐ๋ฅ์ด ์์ฑ๋ฉ๋๋ค.
๊ธฐ๋ ๊ฒฐ๊ณผ: ๋ฉ๋ด๋ฅผ 2๊ฐ ์ด์ ์ถ๊ฐํ๊ณ '๋ฃฐ๋ ๋๋ฆฌ๊ธฐ' ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์บ๋ฒ์ค์ ๊ทธ๋ ค์ง ๋ฃฐ๋ ์ด 3์ด๊ฐ ํ์ ํฉ๋๋ค. ํ์ ์ด ๋ฉ์ถ๋ฉด ์๋จ ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ๋ฉ๋ด๊ฐ ๊ฒฐ๊ณผ๋ก ํ์๋ฉ๋๋ค. ๋ฉ๋ด๋ฅผ ์ถ๊ฐ/์ญ์ ํ๋ฉด ๋ฃฐ๋ ์ด ์๋์ผ๋ก ๋ค์ ๊ทธ๋ ค์ง๋๋ค. ๋คํฌ๋ชจ๋์์๋ ์ ์ ์๋ํฉ๋๋ค.
์ ์ถ๋ ์ํ (0)
๋ก๊ทธ์ธ ํ ์ ์ถ์์ง ์ ์ถ๋ ์ํ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋์ ์๊ฐ ๋์ด๋ณด์ธ์!