웹 미니 프로젝트 - 날씨 API 기능 구현

Zyoon·2025년 4월 8일

미니프로젝트

목록 보기
1/35
post-thumbnail

💡공공데이터 날씨 API 이용


메인페이지 기능구현


🗨️ 현재 위치값으로 날씨정보 가져와서 보여주기

  • 현재 위치값 가져오기

    // 브라우저에서 현재 위치값 가져오는 API
    navigator.geolocation.getCurrentPosition(success, error);
    
    function success(position) {
    	// 실제 포지션 값 (위도, 경도)
    	const lat = position.coords.latitude;
    	const lon = position.coords.longitude;
    	
    	// 기상청 API에 적용할 수 있게 가공
    	const result = dfs_xy_conv(lat, lon); // 기상청 공식 함수
    	nx = result.nx;
    	ny = result.ny;
    
    	console.log("현재 격자 좌표:", nx, ny); // 좌표 찍어보기
    	
    	getWeather(nx, ny) //현재 날씨 구하는 함수 실행
    }
    • 브라우저 내장 함수를 사용하여 구함

    • 브라우저 실행 시 위치값 권한 요청. 요청 거절시 데이터 미출력


  • 현재 시간을 구해서 데이터 알맞게 가공

    • 현재 날짜 및 시간 구하는 로직 실행

    • AM 2시를 기준으로 3시간 간격마다 날씨를 제공하기에, 그 시간에 맞게 가공

    • 해당 시간이 아닐시 에러

      //현재 날짜를 양식에 맞게 조절 (yyyymmdd)
      const base_date = new Date().toISOString().slice(0, 10).replace(/-/g, '');
      
      //현재 시간기준으로 양식에 맞는 시간 구함
      const base_time = getBaseTime();
      
      //날짜 가공 함수
      function getBaseTime() {
      		//현재 시간
          const now = new Date();
          const hour = now.getHours();
      
      		// 기상청 지원 base 시간 정리
          const times = [2, 5, 8, 11, 14, 17, 20, 23]; 
          let baseHour = 23; // 기본값 (가장 늦은 시간)
      
      		// bases 시간 기준으로 규격에 맞는 시간만 구함
          for (let i = 0; i < times.length; i++) {
              if (hour < times[i]) {
                  baseHour = times[i - 1] ?? 23; // 제일 이른 시간 전이면 23시 (전날)
                  break;
              }
          }
      
      		//해당 시간을 양식에 맞게 정리 (0200 ~ 2300)
          return String(baseHour).padStart(2, '0') + '00';
      }

  • 시간과 좌표 기준으로 날씨 정보 구함

    • 공공데이터포탈 API 키 필요

    • 해당 키를 사용하여 Json 형식으로 된 url 접근 가능

    • 현재 기온은 숫자로, 현재 날씨 상태는 아이콘 형식으로(FontAwesome 사용) 변환하여 사용

       // 날씨 정도 가져오는 함수
          function getWeather(nx, ny) {
      
            // 오늘 날짜와 적절한 base_time 계산
            const base_date = new Date().toISOString().slice(0, 10).replace(/-/g, '');
            const base_time = getBaseTime(); //3시간 단위 (0500, 0800 ...)
      
            // 날씨 API 에서 인코딩된 키 사용
            const serviceKey = "[발급받은 Key]";
            
            // 좌표와 시간, 날짜, key 사용하여 url 생성
            const url = `https://apis.data.go.kr/1360000/
      	      VilageFcstInfoService_2.0/
      	      getVilageFcst?serviceKey=${serviceKey}&pageNo=1&
      	      numOfRows=1000&dataType=JSON&base_date=${base_date}&
      	      base_time=${base_time}&nx=${nx}&ny=${ny}`;
      			
      			//url 사용하여 json 파일로 된 데이터에서 필요한 부분 생성
            fetch(url)
              .then(response => {
                if (!response.ok) {
                  throw new Error("네트워크 응답에 문제가 있습니다.");
                }
                return response.json();
              })
              .then(data => {
                const items = data.response.body.items.item;
      
                // 예보 시간 기준으로 정렬 (선택 사항)
                const forecast = {};
      
      					// TMP는 온도, SKY는 상태(맑음,흐림), PTY는 기상(눈,비)
                items.forEach(item => {
                  const time = item.fcstTime;
                  if (!forecast[time]) forecast[time] = {};
      
                  if (item.category === "TMP") {
                    forecast[time].temp = item.fcstValue;
                  } else if (item.category === "SKY") {
                    forecast[time].sky = item.fcstValue;
                  } else if (item.category === "PTY") {
                    forecast[time].pty = item.fcstValue;
                  }
                });
      
                // 상태 매핑 (FontAwesome 아이콘 사용)
                const skyMap = {
                  "1": "fas fa-sun", // 맑음
                  "3": "fas fa-cloud-sun", // 흐림
                  "4": "fa-solid fa-smog" // 구름
                };
                const ptyMap = {
                  "0": "없음",
                  "1": "fa-solid fa-umbrella", // 비
                  "2": "fa-solid fa-cloud-meatball", // 비/눈
                  "3": "fa-solid fa-snowflake", // 눈
                  "4": "fa-solid fa-cloud-showers-heavy", // 소나기
                  "5": "fa-solid fa-cloud-rain", // 비
                  "6": "fa-solid fa-cloud-meatball", // 함박눈
                  "7": "fa-solid fa-cloud-meatball" // 함박눈
                };
      
                // 시간 정보
                const forecastTimes = Object.keys(forecast);
      
                // 전체 예보 시간 중 첫 번째 항목만 선택
                if (forecastTimes.length > 0) {
                  const selectedTime = forecastTimes[0];
                  const tmp = forecast[selectedTime].temp;
      
                  let status = null;
      						
      						// 맑은, 흐림, 비, 눈 선택
                  if (forecast[selectedTime].pty == 0) {
                    status = skyMap[forecast[selectedTime].sky];
                  } else {
                    status = ptyMap[forecast[selectedTime].pty];
                  }
      						
      						// 날씨 양식 Text 파일로 변경 후 innerHTML로 입력
                  let whetherTag = `<i class="${status}"></i> &nbsp; ${tmp}°C`           
                  document.getElementById("header_whether").innerHTML = whetherTag;
                } else {
                  console.log("예보 정보가 없습니다.");
                }
              })
              .catch(error => {
                console.error("날씨 정보를 가져오는 데 실패했습니다:", error);
              });
          }
  • 화면표시

  • 아쉬운 점
    • 카카오맵 API 사용하여 현재 위치에 해당하는 주소지 이름도 가져오고 싶었으나 사이트 도메인을 등록해야 하기에 다음에 구현하기로 함
    • api 특성상 데이터를 못가지고 오는 경우가 종종 있음
    • 많은 노력이 들어갔지만 티가 안남
profile
기어 올라가는 개발

0개의 댓글