AI, Coding
복권 가중치 번호 추첨기(개선)
Dasol
2025. 2. 6. 11:09
복권 가중치 번호 추첨기에서 처음 데이터를 불러올 때 속도가 느려서 제대로 진행되고 있는지를 파악하기 힘들었다.
그래서 다음과 같은 개선을 진행하였다.
1. 값을 불러오는 중에는 로딩 스피너(로딩 중일 때 빙글빙글 돌아가는 표시)를 추가
2. querySelector 호출로 특정 요소를 찾아서 값을 불러오던 작업(DOM 탐색)을 삭제하고 querySelectorAll에서 인덱스로 접근
3. document.createElement 작업(DOM업데이트)을 1번으로 최소화
See the Pen Untitled by sol Da (@sol-Da) on CodePen.
아래는 혹시나 전체 코드 참고용으로 남긴다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>복권 번호 추출기</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
background-color: #f4f4f9;
margin: 0;
padding: 0;
}
h1 {
color: #333;
}
.container {
margin-top: 50px;
}
button {
padding: 10px 20px;
font-size: 16px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin: 5px;
}
button:hover {
background-color: #0056b3;
}
.result {
margin-top: 30px;
display: flex;
justify-content: center;
gap: 10px;
}
.circle {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 18px;
font-weight: bold;
}
.yellow { background-color: #f7dc6f; }
.blue { background-color: #87cefa; }
.red { background-color: #ff6347; }
.gray { background-color: #a9a9a9; }
.green { background-color: #98fb98; }
/* 로딩 스피너 */
.loading-spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
border-left-color: #007bff;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 20px auto;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* 표 스타일 */
table {
margin: 20px auto;
border-collapse: collapse;
width: 80%;
max-width: 600px;
text-align: center;
background-color: white;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
th, td {
padding: 10px;
border: 1px solid #ddd;
}
th {
background-color: #f7f7f7;
}
td.number-cell {
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<h1>복권 번호 추출기</h1>
<button onclick="generateOrFetchData()">번호 생성하기</button>
<div id="loading" class="loading-spinner" style="display: none;"></div>
<div class="result" id="result"></div>
<!-- 최신 데이터 정보 -->
<div id="latest-data-info" style="margin-top: 20px; font-size: 16px; color: #555;"></div>
<!-- 정렬 버튼 -->
<div style="margin-top: 20px;">
<button onclick="sortTableByNumber()">번호순 정렬</button>
<button onclick="sortTableByCount()">당첨횟수순 정렬</button>
</div>
<!-- 받아온 데이터를 표시할 테이블 -->
<h2>받아온 데이터</h2>
<table id="data-table">
<thead>
<tr>
<th>번호</th>
<th>당첨횟수</th>
</tr>
</thead>
<tbody>
<!-- 데이터가 여기에 동적으로 추가됩니다 -->
</tbody>
</table>
</div>
<script>
let numbersData = []; // 데이터 저장 변수
let latestDataRange = ''; // 최신 데이터 범위 저장 변수
async function fetchLatestData() {
const loadingSpinner = document.getElementById('loading');
try {
loadingSpinner.style.display = 'block'; // 로딩 스피너 표시
// 프록시 서비스 변경 (allorigins.win 사용)
const proxyUrl = 'https://api.allorigins.win/get?url=';
const targetUrl = encodeURIComponent('https://www.dhlottery.co.kr/gameResult.do?method=statByNumber');
const response = await fetch(proxyUrl + targetUrl);
if (!response.ok) {
throw new Error(`네트워크 오류: ${response.status} ${response.statusText}`);
}
const data = await response.json();
// HTML 파싱
const parser = new DOMParser();
const doc = parser.parseFromString(data.contents, 'text/html');
// "번호순" 테이블 선택
const table = doc.querySelector('table.tbl_data.tbl_data_col'); // 클래스명만 사용
if (!table) {
throw new Error('테이블을 찾을 수 없습니다.');
}
// 데이터 추출 로직 최적화
const rows = Array.from(table.querySelectorAll('tbody tr')); // tbody 내의 행만 선택
numbersData = rows.map(row => {
const cols = row.querySelectorAll('td');
// 더 빠른 접근을 위해 직접 인덱스로 접근
const number = parseInt(cols[0].textContent.trim(), 10); // 번호
const graph = parseFloat(cols[1].textContent.trim().replace('%', '')); // 그래프 값(퍼센트)
const count = parseInt(cols[2].textContent.trim(), 10); // 당첨횟수
return { number, graph, count };
});
// 기본 정렬: 번호순
numbersData.sort((a, b) => a.number - b.number);
// 최신 데이터 범위 설정
const selectBox = doc.querySelector('select#edDrwNo'); // 드롭다운 메뉴 선택
if (selectBox) {
const options = Array.from(selectBox.querySelectorAll('option'));
const latestOption = options[0].value; // 가장 최신 회차 번호
latestDataRange = `1~${latestOption}회`;
} else {
latestDataRange = '범위 정보를 불러올 수 없습니다.';
}
// 데이터를 표로 출력
updateDataTable(numbersData);
// 최신 데이터 정보 업데이트
document.getElementById('latest-data-info').textContent = `최신 데이터: ${latestDataRange}`;
alert('최신 데이터를 성공적으로 불러왔습니다!');
} catch (error) {
console.error('데이터를 불러오는 중 오류가 발생했습니다:', error);
alert('데이터를 불러오는 데 실패했습니다. 잠시 후 다시 시도해주세요.');
} finally {
loadingSpinner.style.display = 'none'; // 로딩 스피너 숨김
}
}
function updateDataTable(data) {
const tableBody = document.querySelector('#data-table tbody');
tableBody.innerHTML = ''; // 이전 데이터 초기화
// DOM 조작 최적화를 위해 문자열로 HTML 생성 후 한 번에 삽입
const rowsHTML = data.map(item => `
<tr>
<td class="number-cell ${getColorClass(item.number)}">${item.number}</td>
<td>${item.count}</td>
</tr>
`).join('');
tableBody.innerHTML = rowsHTML;
}
function getColorClass(number) {
if (number >= 1 && number <= 10) return 'yellow';
if (number >= 11 && number <= 20) return 'blue';
if (number >= 21 && number <= 30) return 'red';
if (number >= 31 && number <= 40) return 'gray';
if (number >= 41 && number <= 45) return 'green';
return '';
}
function sortTableByNumber() {
// 번호순으로 정렬
numbersData.sort((a, b) => a.number - b.number);
updateDataTable(numbersData);
}
function sortTableByCount() {
// 당첨횟수순으로 정렬 (내림차순)
numbersData.sort((a, b) => b.count - a.count);
updateDataTable(numbersData);
}
function generateWeightedLotteryNumbers() {
if (numbersData.length === 0) {
alert('먼저 최신 정보를 받아와야 합니다.');
return;
}
const numbers = [];
const totalWeight = numbersData.reduce((sum, num) => sum + num.graph, 0);
while (numbers.length < 6) {
const random = Math.random() * totalWeight;
let cumulativeWeight = 0;
for (const num of numbersData) {
cumulativeWeight += num.graph;
if (random <= cumulativeWeight && !numbers.includes(num.number)) {
numbers.push(num.number);
break;
}
}
}
numbers.sort((a, b) => a - b);
const resultDiv = document.getElementById('result');
resultDiv.innerHTML = ''; // Clear previous results
numbers.forEach(number => {
const circle = document.createElement('div');
circle.classList.add('circle', getColorClass(number));
circle.textContent = number;
resultDiv.appendChild(circle);
});
}
async function generateOrFetchData() {
if (numbersData.length === 0) {
// 데이터가 없으면 최신 데이터를 가져옴
await fetchLatestData();
}
// 번호 생성
generateWeightedLotteryNumbers();
}
</script>
</body>
</html>
728x90
반응형