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>

2025.02.02 - [분류 전체보기] - 복권 가중치 번호 추첨기

728x90
반응형