<div class="container" id="wrapper">
<div class="container-fluid" id="current-weather">
<div class="row">
<!-- Right panel -->
<div class="col-md-4 col-sm-5">
<h5><spam id="cityName"></spam>, <spam id="cityCode"></spam></h5>
<h6 id="localDate"></h6>
<h5 id="localTime"></h5>
<a id="refreshButton" href="#"><i class="fa fa-refresh fa-fw" aria-hidden="true"></i> Refresh</a>
</div>
<!-- Center panel -->
<div class="col-md-5 col-sm-7" style="margin: 10px auto;padding:0;">
<div class="row">
<i class="wi" id ="main-icon" style="font-size: 85px;"></i>
<div>
<spam id="mainTemperature"></spam>
<p id="tempDescription"></p>
</div>
<p style="font-size: 1.5rem;"><a href="#" class="active" id="celcius">°C</a> | <a href="#" id="farenheit">°F</a></p>
</div>
</div>
<!-- Left panel -->
<div class="col-xs-12 col-sm-12 col-md-3 row" style="text-align: right;">
<div class="col-md-12 col-sm-3 col-xs-3 side-weather-info">
<h6>Humidity: <spam id="humidity"></spam>%</h6>
</div>
<div class="col-md-12 col-sm-3 col-xs-3 side-weather-info">
<h6>Wind: <spam id="wind"></spam> m/s</h6>
</div>
<div class="col-md-12 col-sm-3 col-xs-3 side-weather-info">
<h6>High: <spam id="mainTempHot"></spam>°</h6>
</div>
<div class="col-md-12 col-sm-3 col-xs-3 side-weather-info">
<h6>Low: <spam id="mainTempLow"></spam>°</h6>
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="protocol-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<p>Due to weather api restrictions, data can only be shown via HTTP request.</p>
<p>Sorry for the inconvenience.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- 4 days forecast -->
<div class="container-fluid">
<div class="row" style="padding: 2px;">
<!-- Day 1 -->
<div class="col-md-3 col-sm-6 day-weather-box">
<div class="col-sm-12 day-weather-inner-box">
<div class="col-sm-8 forecast-main">
<p id="forecast-day-1-name"></p>
<div class="row">
<h5 id="forecast-day-1-main">°</h5>
<i class="wi forecast-icon" id="forecast-day-1-icon"></i>
</div>
</div>
<div class="col-sm-4 forecast-min-low">
<p><spam class="high-temperature" id="forecast-day-1-ht"></spam></p>
<p><spam class="low-temperature" id="forecast-day-1-lt"></spam></p>
</div>
</div>
</div>
<!-- Day 2 -->
<div class="col-md-3 col-sm-6 day-weather-box">
<div class="col-sm-12 day-weather-inner-box">
<div class="col-sm-8 forecast-main">
<p id="forecast-day-2-name"></p>
<div class="row">
<h5 id="forecast-day-2-main">°</h5>
<i class="wi forecast-icon" id="forecast-day-2-icon"></i>
</div>
</div>
<div class="col-sm-4 forecast-min-low">
<p><spam class="high-temperature" id="forecast-day-2-ht"></spam></p>
<p><spam class="low-temperature" id="forecast-day-2-lt"></spam></p>
</div>
</div>
</div>
<!-- Day 3 -->
<div class="col-md-3 col-sm-6 day-weather-box">
<div class="col-sm-12 day-weather-inner-box">
<div class="col-sm-8 forecast-main">
<p id="forecast-day-3-name"></p>
<div class="row">
<h5 id="forecast-day-3-main">°</h5>
<i class="wi forecast-icon" id="forecast-day-3-icon"></i>
</div>
</div>
<div class="col-sm-4 forecast-min-low">
<p><spam class="high-temperature" id="forecast-day-3-ht"></spam></p>
<p><spam class="low-temperature" id="forecast-day-3-lt"></spam></p>
</div>
</div>
</div>
<!-- Day 4 -->
<div class="col-md-3 col-sm-6 day-weather-box">
<div class="col-sm-12 day-weather-inner-box">
<div class="col-sm-8 forecast-main">
<p id="forecast-day-4-name"></p>
<div class="row">
<h5 id="forecast-day-4-main">°</h5>
<i class="wi forecast-icon" id="forecast-day-4-icon"></i>
</div>
</div>
<div class="col-sm-4 forecast-min-low">
<p><spam class="high-temperature" id="forecast-day-4-ht"></spam></p>
<p><spam class="low-temperature" id="forecast-day-4-lt"></spam></p>
</div>
</div>
</div>
</div>
</div>
</div>
a {
color: white;
opacity: 0.6;
text-decoration: none;
}
a:hover, a:active, a:focus{
color: white;
text-decoration: none;
opacity: 1;
}
.active {
color: white;
text-decoration: none;
opacity: 1;
}
body{
background-color: #F4F6F7;
}
#wrapper {
background-color: #28688C;
box-shadow: 1px 5px 25px 3px #444;
border-radius: 10px;
margin: 100px auto;
max-width: 720px;
padding: 0px;
color: white;
}
#current-weather{
padding: 15px;
}
#mainTemperature{
font-size: 5.5em;
line-height: 0.7;
}
#tempDescription {
margin-top: 10px;
text-align: center;
}
.day-weather-box {
border: 1px solid #28688C;
background-color: #2E7FA1;
border-radius: 5px;
height: 5em;
}
.day-weather-box p{
margin-bottom: 0;
}
.side-weather-info {
padding: 0px 10px;
}
.day-weather-inner-box {
display: inline-flex;
margin: 14px auto;
padding: 0px 5px;
}
.forecast-main {
padding: 0px 0px 0px 30px;
}
.forecast-icon {
font-size: 25px;
margin-left: 5px;
}
.modal-body p{
color: #333;
}
var unitIsCelcius = true;
var globalForecast = [];
// Maps the API's icons to the ones from https://erikflowers.github.io/weather-icons/
var weatherIconsMap = {
"01d": "wi-day-sunny",
"01n": "wi-night-clear",
"02d": "wi-day-cloudy",
"02n": "wi-night-cloudy",
"03d": "wi-cloud",
"03n": "wi-cloud",
"04d": "wi-cloudy",
"04n": "wi-cloudy",
"09d": "wi-showers",
"09n": "wi-showers",
"10d": "wi-day-hail",
"10n": "wi-night-hail",
"11d": "wi-thunderstorm",
"11n": "wi-thunderstorm",
"13d": "wi-snow",
"13n": "wi-snow",
"50d": "wi-fog",
"50n": "wi-fog"
};
$(function(){
getClientPosition();
startClock();
});
function startClock(){
setInterval(function(){
$("#localTime").text(new Date().toLocaleTimeString());
}, 1000);
}
function getClientPosition(){
$.getJSON("https://ipapi.co/json/", function(position) {
$("#cityName").text(position.city);
$("#cityCode").text(position.country);
getWeatherData(position.latitude, position.longitude);
});
}
function getWeatherData(latitude, longitude){
$.ajax({
type: "GET",
url: "https://cors-anywhere.herokuapp.com/http://api.openweathermap.org/data/2.5/forecast/daily?APPID=9b4bbf30228eb8528d36e79d05da1fac&lat=" + latitude + "&lon=" + longitude + "&units=metric&cnt=5",
cache: true,
headers: {
"Access-Control-Allow-Headers": "x-requested-with"
},
success: function(forecast){
globalForecast = forecast;
updateForecast(forecast);
// Stops Refresh button's spinning animation
$("#refreshButton").html("<i class='fa fa-refresh fa-fw'></i> Refresh");
},
error: function(error){
console.log("Error with ajax: "+ error);
}
});
}
// Update view values from passed forecast
function updateForecast(forecast){
// Present day
var today = forecast.list[0];
$("#tempDescription").text(toCamelCase(today.weather[0].description));
$("#humidity").text(today.humidity);
$("#wind").text(today.speed);
$("#localDate").text(getFormattedDate(today.dt));
$("#main-icon").addClass(weatherIconsMap[today.weather[0].icon]);
$("#mainTemperature").text(Math.round(today.temp.day));
$("#mainTempHot").text(Math.round(today.temp.max));
$("#mainTempLow").text(Math.round(today.temp.min));
// Following days data
for(var i = 1; i < (forecast.list).length; i++){
var day = forecast.list[i];
// Day short format e.g. Mon
var dayName = getFormattedDate(day.dt).substring(0,3);
// weather icon from map
var weatherIcon = weatherIconsMap[day.weather[0].icon];
$("#forecast-day-" + i + "-name").text(dayName);
$("#forecast-day-" + i + "-icon").addClass(weatherIcon);
$("#forecast-day-" + i + "-main").text(Math.round(day.temp.day));
$("#forecast-day-" + i + "-ht").text(Math.round(day.temp.max));
$("#forecast-day-" + i + "-lt").text(Math.round(day.temp.min));
}
}
// Refresh button handler
$("#refreshButton").on("click", function(){
// Starts Refresh button's spinning animation
$("#refreshButton").html("<i class='fa fa-refresh fa-spin fa-fw'></i>");
getWeatherData();
});
// Celcius button handler.
// Converts every shown value to Celcius
$("#celcius").on("click", function(){
if(!unitIsCelcius){
$("#farenheit").removeClass("active");
this.className = "active";
// main day
var today = globalForecast.list[0];
today.temp.day = toCelcius(today.temp.day);
today.temp.max = toCelcius(today.temp.max);
today.temp.min = toCelcius(today.temp.min);
globalForecast.list[0] = today;
// week
for(var i = 1; i < 5; i ++){
var weekDay = globalForecast.list[i];
weekDay.temp.day = toCelcius(weekDay.temp.day);
weekDay.temp.max = toCelcius(weekDay.temp.max);
weekDay.temp.min = toCelcius(weekDay.temp.min);
globalForecast[i] = weekDay;
}
// update view with updated values
updateForecast(globalForecast);
unitIsCelcius = true;
}
});
// Farenheit button handler
// Converts every shown value to Farenheit
$("#farenheit").on("click", function(){
if(unitIsCelcius){
$("#celcius").removeClass("active");
this.className = "active";
// main day
var today = globalForecast.list[0];
today.temp.day = toFerenheit(today.temp.day);
today.temp.max = toFerenheit(today.temp.max);
today.temp.min = toFerenheit(today.temp.min);
globalForecast.list[0] = today;
// week
for(var i = 1; i < 5; i ++){
var weekDay = globalForecast.list[i];
weekDay.temp.day = toFerenheit(weekDay.temp.day);
weekDay.temp.max = toFerenheit(weekDay.temp.max);
weekDay.temp.min = toFerenheit(weekDay.temp.min);
globalForecast[i] = weekDay;
}
// update view with updated values
updateForecast(globalForecast);
unitIsCelcius = false;
}
});
// Applies the following format to date: WeekDay, Month Day, Year
function getFormattedDate(date){
var options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
return new Date(date * 1000).toLocaleDateString("en-US",options);
}
// Formats the text to CamelCase
function toCamelCase(str) {
var arr = str.split(" ").map(
function(sentence){
return sentence.charAt(0).toUpperCase() + sentence.substring(1);
}
);
return arr.join(" ");
}
// Converts to Celcius
function toCelcius(val){
return Math.round((val - 32) * (5/9));
}
// Converts to Farenheit
function toFerenheit(val){
var degrees = (val * 1.8) + 32;
var rounded = Math.round(degrees);
return rounded;
}