개발조각

[JavaScript 간단한 날씨 웹 만들기] 최종 본문

엘리스 AI 트랙🐇/토이 프로젝트🚗

[JavaScript 간단한 날씨 웹 만들기] 최종

개발조각 2022. 8. 3. 11:15
728x90
반응형

드디어 JavaScript 간단한 날씨 웹 만들기를 마무리하였습니다.

일주일에 5시간정씩 투자하면서 만들다 보니 3주나 걸리네요...

(js가 꼴랑 135줄인데;;;;)

 

이번 토이프젝을 만들면서 함수 분할을 신경을 쓰다 보니 생각보다 더 걸린 것 같아요.

이번 기회에 자바스크립트 함수 사용에 대해 많이 익숙해진 것 같아 뿌듯합니다.

 

최종적으로 코드 올리고 마치겠습니다.


날씨 API : https://openweathermap.org/api
날씨 아이콘 : https://darkskyapp.github.io/skycons/
그 외 아이콘 : https://fontawesome.com/

 

구현하고자 하는 기능

  • 시계 구현
  • 현재 위치
  • 현재 온도
  • 현재 날씨 정보
  • 날씨 정보 토대로 스카이콘 띄우기
  • 바람
  • 습도
  • 일출, 일몰 데이터를 가지고 낮, 밤 구현

HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>날씨 & 시간</title>
</head>

<!-- css -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet">

<link rel="stylesheet" href="./style.css">

<!-- script -->
<script src="./main.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/skycons/1396634940/skycons.min.js"></script>

<body>
  <!-- day, night -->
  <div id="dayNight" class="container day">
    <div class="top">
      <p id="location">서울, 강서구</p>
      <p id="time"></p>
    </div>

    <div class="middle">
      <div class="main_icon">
        <canvas id="mainIcon" width="72" height="72">
      </div>
      <p id="temperature"></p>
      <p id="WeatherInfo">맑음</p>
    </div>

    <span class="line"></span>
    <ul class="bottom">
      <li>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M32 192h320c52.94 0 96-43.06 96-96s-43.06-96-96-96h-32c-17.69 0-32 14.31-32 32s14.31 32 32 32h32c17.66 0 32 14.34 32 32s-14.34 32-32 32H32C14.31 128 0 142.3 0 160S14.31 192 32 192zM160 320H32c-17.69 0-32 14.31-32 32s14.31 32 32 32h128c17.66 0 32 14.34 32 32s-14.34 32-32 32H128c-17.69 0-32 14.31-32 32s14.31 32 32 32h32c52.94 0 96-43.06 96-96S212.9 320 160 320zM416 224H32C14.31 224 0 238.3 0 256s14.31 32 32 32h384c17.66 0 32 14.34 32 32s-14.34 32-32 32h-32c-17.69 0-32 14.31-32 32s14.31 32 32 32h32c52.94 0 96-43.06 96-96S468.9 224 416 224z"/></svg>
        <p>바람</p>
        <p id="wind"></p>
      </li>
      <span></span>
      <li>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M16 319.1C16 245.9 118.3 89.43 166.9 19.3C179.2 1.585 204.8 1.585 217.1 19.3C265.7 89.43 368 245.9 368 319.1C368 417.2 289.2 496 192 496C94.8 496 16 417.2 16 319.1zM112 319.1C112 311.2 104.8 303.1 96 303.1C87.16 303.1 80 311.2 80 319.1C80 381.9 130.1 432 192 432C200.8 432 208 424.8 208 416C208 407.2 200.8 400 192 400C147.8 400 112 364.2 112 319.1z"/></svg>
        <p>습도</p>
        <p id="humidity"></p>
      </li>
    </ul>
  </div>
</body>
</html>

 

CSS

/* reset */
*{box-sizing: border-box; margin: 0; padding: 0;}
body{font-family: 'Noto Sans KR', sans-serif; line-height: 1;}
li{list-style: none;}

body{display: flex; justify-content: center; align-items: center; height: 100vh;}
.container{display: flex; flex-direction: column; justify-content: center; align-items: center; width: 360px; height: 640px;}
.top, .middle, .bottom{text-align: center;}

/* top */
.top p:first-child{font-weight: 500; font-size: 20px;}
.top p:last-child{font-size: 14px; margin-top: 8px;}

/* middle */
.middle{margin-top: 80px;}
.middle .main_icon{margin: 0 auto; width: 72px; height: 72px;}
.middle p:first-of-type{font-weight: 700; font-size: 64px; margin: 24px 0 16px 0;}

.line{margin-top: 40px; width: 32px; height: 1px;}
/* bottom */
.bottom{display: flex; align-items: center; margin-top: 48px;}
.bottom li{width: 100px;}
.bottom li svg{height: 32px;}
.bottom li p:first-of-type{margin-top: 12px;}
.bottom li p:last-of-type{margin-top: 4px; font-weight: 300; font-size: 14px;}
.bottom span{display: block; margin: 0 20px; width: 1px; height: 32px;}

/* 낮 */
.day{background: #DBE2EA; color: #2B323C;}

.day .line{background: #C2C5CC;}

.day svg{fill: #5D6169;}
.day .bottom li:first-child::after{background: #C2C5CC;}
.day .bottom li p:last-of-type{color: #5D6169;}
.day .bottom span{background: #C2C5CC;}


/* 밤 */
.night{background: #2B323C; color: #DBE2EA;}

.night .line{background: #979EA6;}

.night svg{fill: #A3AAB2;}
.night .bottom li:first-child::after{background: #979EA6;}
.night .bottom li p:last-of-type{color: #A3AAB2;}
.night .bottom span{background: #979EA6;}

 

js

const dayNight = document.querySelector('#dayNight');

const locationName = document.querySelector('#location');
const timeText = document.querySelector('#time');

const mainIcon = document.querySelector('#mainIcon');
const tempText = document.querySelector('#temperature');
const WeatherInfoText = document.querySelector('#WeatherInfo');

const windText = document.querySelector('#wind');
const humidityText = document.querySelector('#humidity');

// 시계 구현
function clock(){
  const now = new Date();
  
  const day = now.getDay();
  const week = ['일', '월', '화', '수', '목', '금', '토'];
  let hours = now.getHours();
  const minutes = now.getMinutes();

  let ampm =  '';
  if(hours > 12){
    hours -= 12;
    ampm = '오후';
  }else ampm = '오전';

  // 예시 : 화, 오후 12:36
  timeText.innerText = `${week[day]}, ${ampm} ${hours < 10 ? `0${hours}` : hours}:${minutes < 10 ? `0${minutes}` : minutes}`

  // 현재시간 초로
  let nowSecTime = now.getHours()*3600 + now.getMinutes()*60 + now.getSeconds();
  return nowSecTime
}

// // 1초마다 시간 실행
(() => {
  clock();
  setInterval(clock, 1000);
})();


// 위도, 경도
navigator.geolocation.getCurrentPosition((position) => {
  const lat = position.coords.latitude; // 위도
  const lon = position.coords.longitude; // 경도
  showWeather(lat, lon)
});

// 날씨 데이터 가져오기
async function weatherData(lat, lon){
  const res = await fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=317eb535e8ab6157652cc6cfc8ae8500`);
  const data = await res.json();

  return data;
}

// 필요한 날씨 데이터 사용
async function showWeather(lat, lon){
  const data = await weatherData(lat, lon);
  console.log(data);

  const temp = data.main.temp // 온도
  const cityName = data.name; // 도시 이름
  const weather = data.weather[0].main // 날씨
  const icon = data.weather[0].icon // 날씨 아이콘
  const windSppeed = data.wind.speed; // 풍속
  const humidity = data.main.humidity; // 습도
  const sunrise = data.sys.sunrise; // 일출시간
  const sunset = data.sys.sunset; // 일몰시간

  locationName.innerText = `${cityName}`
  
  tempText.innerText = `${Math.floor(temp - 273.15)}°`
  WeatherInfoText.innerText = `${weather}`

  windText.innerText = `${Math.floor(windSppeed)}m / s`
  humidityText.innerText = `${humidity}%`

  const sunTime = unixChange(sunrise, sunset);
  const dayAndNight = dayNightChange(sunTime['sunrise'], sunTime['sunset'], clock());
  
  skyconWeather(icon, dayAndNight);
}

// 유닉스시간 일반시간으로 변경 -> 초시간으로 변경
function unixChange(sunrise, sunset){
  const sunriseDate = new Date(sunrise*1000);
  const sunsetDate = new Date(sunset*1000);

  // 일반시간 시, 분, 초를 다 합산하여 초로 만들기
  const sunriseSec = sunriseDate.getHours()*3600 + sunriseDate.getMinutes()*60 + sunriseDate.getSeconds();
  const sunsetSec = sunsetDate.getHours()*3600 + sunsetDate.getMinutes()*60 + sunsetDate.getSeconds();

  return {'sunrise': sunriseSec, 'sunset': sunsetSec}
}

// 낮, 밤 구현하기
function dayNightChange(sunrise, sunset, now){
  if(now >= sunrise && now < sunset){
    dayNight.classList.remove('night');
    dayNight.classList.add('day');
    return 1;
  }else{
    dayNight.classList.remove('day');
    dayNight.classList.add('night');
    return 0;
  }
}

// 날씨데이터에 따라 skycon적용
function skyconWeather(icon, dayAndNight){
  const iconNum = icon.slice(0, -1);
  const weatherData = {
    '01' : ['clear-day', 'clear-night'],
    '02' : ['partly-cloudy-day', 'partly-cloudy-night'],
    '03' : 'cloudy',
    '04' : 'cloudy',
    '09' : 'rain',
    '10' : 'rain',
    '13' : 'snow',
    '50' : 'fog',
  }

  let skyconName = '';
  if(iconNum === '01' || iconNum === '02'){
    skyconName = dayAndNight ? weatherData[iconNum][0] : weatherData[iconNum][1];
  }else{
    skyconName = weatherData[iconNum];
  }

  let icons = new Skycons({'color': dayAndNight ? '#2B323C' : '#DBE2EA'});
  icons.set(mainIcon, skyconName);
  icons.play();
}

 

 

마지막으로  깃허브에다가 올려보았습니다.

https://yyoumi4854.github.io/weatherAndTime/

 

날씨 & 시간

 

yyoumi4854.github.io

맑음일 때의 아이콘을 보고 싶지만

일주일 내내 비가 내릴 예정이라ㅋㅋㅋ 아마 오래 뒤에 볼 것 같습니다.

728x90
반응형
Comments