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;
}
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.
<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>