harunpehlivan
3/6/2018 - 5:07 PM

Show the Local Weather

Show the Local Weather

<link href="https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.5/css/weather-icons.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.5/css/weather-icons-wind.min.css" rel="stylesheet" />
/* Add box-sizing universally */
* {
  box-sizing: border-box;
}

/* Set the default background image as Google Maps water color*/
html {
  background-color: #a3ccfd;
  background-image: linear-gradient(#a3ccfd, #a3ccfd);
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  font-family: 'Josefin Sans', sans-serif;
  height: 100vh;
}

body {
  align-items: center;
  background-image: url(data:image/png;base64,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);
  display: flex;
  flex-direction: column;
  height: 100vh;
  justify-content: center;
}

/* Header style */
h1 {
  color: #fdfdfd;
  font-family: Pacifico;
  font-size: 4em;
  font-weight: normal;
  line-height: 1em;
  margin: 0;
  text-shadow: .25rem .25rem 0 rgba(#000000, .75);
}

h1:after {
  
}

/* Main content */
#main {
  background: rgba(0,51,102, .5);
  margin: 0 auto;
  max-width: 100%;
  padding: 1.5em 2em .5em;
  text-align: center;
  box-shadow: .25em .25em 0 black;
  border: .25em solid white;
  border-radius: .5rem;
}

#quick-view {
  color: white;
  font-size: 3em;
  font-size: calc(1em + 8vw);
  margin: .4em 0 .2em 0;
  text-shadow: .25rem .25rem 0 rgba(#000000, .75);
}

#quick-view div {
  display: inline;
}

#grid {
  margin: .5em 0;
}

#grid div {
  background: white;
  border-radius: .75em;
  box-shadow: .25rem .25rem 0 rgba(#000000, .75);
  color: black;
  display: inline-block;
  letter-spacing: .1em;
  margin: .5em .4em;
  overflow: hidden;
  padding: 1.2rem;
  vertical-align: middle;
  white-space: nowrap;
}

/* Show/hide classes to toggle imperial and metric values */
.show {
  display: inline-table;
}
.hide {
  display: none;
}

/* Conversion button */
button {
  bottom: 0;
  background-color: rgba(250,250,255,.4);
  border: none;
  padding: 1em;
  position: absolute;
  right: 0;
}

/* Create a loading animation */
@keyframes opacity {
	0% { opacity: 1; }
	100% { opacity: 0; }
}

#loading {
	margin: 6rem 0 0 0;
	text-align: center; 
}

#loading span {
	animation-name: opacity;
	animation-duration: 1s;
	animation-iteration-count: infinite;
}

#loading span:nth-child(2) {
	animation-delay: 250ms;
	animation-delay: 250ms;
}

#loading span:nth-child(3) {
	animation-delay: 500ms;
	animation-delay: 500ms;
}

.wi-wind {
  font-size: 3em;
  line-height: 0;
  margin-right: .5rem;
  vertical-align: middle;
}

.visually-hidden {
  position: absolute;
  transform: scale(0);
}

#miles,#meters {
  vertical-align: sub;
}

Show the Local Weather

Refactored and improved. Geolocation is faster and more accurate. Updated with the latest version of Weather Icons. Wind direction is now perfect to the degree.

A local weather app using geolocation. A fixed button in the bottom right toggles between imperial and metric for both wind speed (MPH vs. m/s) and temperature (Fahrenheit vs. Celsius).

Built as part of the Free Code Camp curriculum.

Edit: Added CORS-proxy and updated API used to get location by IP so this works again. Also swapped out the Game of Thrones background images with a static Google Map based on the user's IP address.

A Pen by HARUN PEHLİVAN on CodePen.

License.

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://codepen.io/denmch/pen/debe9e615df1b7ac57a5e7603322870c"></script>
// Grab the latitude & longitude
$.getJSON("https://freegeoip.net/json/", function(ipAPI) {
  var latitude = ipAPI.latitude;
  var longitude = ipAPI.longitude;
  var city = ipAPI.city.replace(/(\s)/gi, "+"); // Replace spaces
  var region = ipAPI.region_code;
  
  // Grab a local map as background based on user's IP
  var imageURL =
    "https://maps.googleapis.com/maps/api/staticmap?center=" +
    city +
    "&zoom=10&size=640x640&scale=2&format=jpeg&key=" + gmapsKey;
  $("html").css("background-image", "url(" + imageURL + ")");

  // Feed the latitude and longitude to the OpenWeatherMap API
  $.getJSON(
    "https://cors-everywhere.herokuapp.com/http://api.openweathermap.org/data/2.5/weather?lat=" +
      latitude +
      "&lon=" +
      longitude +
      "&APPID=" + owKey,
    function(ow) {
      var location = city + ", " + region,
        status = ow.weather[0].main,
        windMeters = ow.wind.speed,
        windMiles = ow.wind.speed * Math.round(2.23694),
        tempF = Math.round(
          ((ow.main.temp - 273.15) * 1.8 + 32) * 10 / 10
        ).toFixed(0),
        tempC = Math.round(ow.main.temp - 273.15),
        iconSource = ow.weather[0].icon,
        icons = {
          // ow.weather[0].icon to wi
          // Daytime conditions
          "01d": "wi-day-sunny",
          "02d": "wi-day-sunny-overcast",
          "03d": "wi-day-cloudy",
          "04d": "wi-cloudy",
          "09d": "wi-day-sprinkle",
          "10d": "wi-day-rain",
          "11d": "wi-day-thunderstorm",
          "13d": "wi-day-snow",
          "50d": "wi-day-fog",

          // Nightime conditions
          "01n": "wi-stars",
          "02n": "wi-night-partly-cloudy",
          "03n": "wi-night-cloudy",
          "04n": "wi-cloudy",
          "09n": "wi-night-sprinkle",
          "10n": "wi-night-rain",
          "11n": "wi-night-thunderstorm",
          "13n": "wi-night-snow",
          "50n": "wi-night-fog"
        },
        iconName = iconSource.split(" ").map(function(code) {
          var results = [];
          results.push(icons[code]);
          return results.join("");
        }),
        icon = iconName[0],
        extremeSource = ow.weather[0].id.toString(),
        extremes = {
          // ow.weather[0].id to wi
          // Extreme weather conditions
          "900": "wi-tornado",
          "901": "wi-hurricane",
          "902": "wi-hurricane",
          "903": "wi-snowflake-cold",
          "904": "wi-hot",
          "905": "wi-windy",
          "906": "wi-hail",

          // Beaufort wind scale
          "951": "wi-beafort-1",
          "952": "wi-beafort-2",
          "953": "wi-beafort-3",
          "954": "wi-beafort-4",
          "955": "wi-beafort-5",
          "956": "wi-beafort-6",
          "957": "wi-beafort-7",
          "958": "wi-beafort-8",
          "959": "wi-beafort-9",
          "960": "wi-beafort-10",
          "961": "wi-beafort-11",
          "962": "wi-beafort-12"
        },
        extremeName = extremeSource.split(" ").map(function(code) {
          var results = [];
          results.push(extremes[code]);
          return results.join("");
        }),
        extreme = extremeName[0];

      var windIcon = "wi-wind towards-" + ow.wind.deg + "-deg";

    $('.sr-only').empty().append("Current conditions in " + city + ": " + status + ", wind at " + windMiles + " MPH (" + windMeters + " m/s)");
      // #quick-view
      $("#loading").hide();
      $("#tempF > span")
        .empty()
        .append(tempF);
      $("#tempC > span")
        .empty()
        .append(tempC);
      $("#weather-icons > i:first-child").addClass(icon);
      $("#weather-icons > i:last-child").addClass(extreme);

      // #grid
      $("#location")
        .empty()
        .append(location);
      $("#status")
        .empty()
        .append(status);
      // #wind
      $(".compass > i")
        .empty()
        .addClass(windIcon);
      $("#miles")
        .empty()
        .append(windMiles + " MPH");
      $("#meters")
        .empty()
        .append(windMeters + " m/s");
    }
  );

  function error() {
    $("#main").append("Unable to retrieve your location");
  }
});

$("button").click(function() {
  $("#tempF").toggleClass("show hide");
  $("#tempC").toggleClass("show hide");
  $("#miles").toggleClass("show hide");
  $("#meters").toggleClass("show hide");
});
<div id="main">
  <h1>Your Weather</h1>
  <div class="visual-only" aria-hidden="true">
    <div id="quick-view">
      <div id="weather-icons">
        <i class="wi"></i>
        <i class="wi"></i>
      </div>

      <div id="loading">
        Loading<span>.</span><span>.</span><span>.</span>
      </div>

      <span id="tempF" class="show">
        <span></span>
        <i class='wi wi-fahrenheit'></i>
      </span>

      <span id="tempC" class="hide">
        <span></span>
        <i class='wi wi-celsius'></i>
      </span>
    </div>
    <div id="grid">
      <div id="location">…</div>
      <div id="status">…</div>
      <div id="wind">
        <span class="compass">
        <i class="wi">…</i>
      </span>
        <span id="miles" class="show">
      </span>
        <span id="meters" class="hide">
      </span>
      </div>
    </div>
    <button>F / C</button>
  </div>
  <p class="visually-hidden">
    Weather data currently unavailable.
  </p>
</div>