FCC Local Weather App
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.css" rel="stylesheet" />
body { background-color: #333; }
#background-images {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* opacity: 0;
-webkit-transition: opacity 2.0s ease-in-out;
-o-transition: opacity 2.0s ease-in-out;
transition: opacity 2.0s ease-in-out; */
}
#bgImg1, #bgImg2 {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background-attachment: fixed;
background-position-x: center;
background-position-y: center;
background-size: cover;
background-repeat: no-repeat;
}
#bgImg1 {
background-image: url("https://aboutme.imgix.net/background/users/h/a/r/harun.pehlivan_1511592423_808.jpg?q=40&dpr=2&auto=format&fit=max&w=620&h=413.3333333333333&rect=255,0,2754,1836");
background-color: #333;
}
#bgImg2 {
background-image: url("https://tebm.files.wordpress.com/2010/02/arge-proje-egitim-esnasc4b1nda-hallerim-3.jpg");
background-color: #333;
}
#background-images div.front {
z-index: 3;
}
#background-images div.back {
z-index: 2;
}
#main {
/* opacity: 0; */
-webkit-transition: opacity 1.0s ease-in-out;
-o-transition: opacity 1.0s ease-in-out;
transition: opacity 1.0s ease-in-out;
z-index: 10;
position: relative;
}
.ui.masthead.segment {
/* min-height: 50vh; */
border-bottom: none;
}
#content {
background-color: #EEE;
/* opacity: 0.8; */
border: 10px solid #666;
border-radius: 20px;
padding: 20px;
position: relative;
/* color: #fff; */
}
#debug-btn {
/* padding-bottom: 6px; */
/* vertical-align: top; */
position: absolute;
top: 10px;
right: 10px;
}
.ui.grid {
margin-top: 0;
}
/* .ui.grid > .column:not(.row) { padding-top: 0; } */
/* Compass left panel */
#compass-label {
margin: 0;
}
/* #compass-deg { margin-bottom:6px; } */
.compass {
margin: 10px 0;
position: relative;
width: 100%;
/* height:200px; */
}
.arrow {
position: absolute;
z-index: 300;
/* width: 160px;
height: 160px; */
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
-webkit-transition: -webkit-transform 0.5s ease-in-out;
transition: -webkit-transform 0.5s ease-in-out;
-o-transition: transform 0.5s ease-in-out;
transition: transform 0.5s ease-in-out;
transition: transform 0.5s ease-in-out, -webkit-transform 0.5s ease-in-out;
width: 100%;
max-width: 180px;
}
.arrow:hover {
-webkit-transform: rotate(225deg);
-ms-transform: rotate(225deg);
transform: rotate(225deg);
-webkit-transition: -webkit-transform 0.7s ease-in-out;
transition: -webkit-transform 0.7s ease-in-out;
-o-transition: transform 0.7s ease-in-out;
transition: transform 0.7s ease-in-out;
transition: transform 0.7s ease-in-out, -webkit-transform 0.7s ease-in-out;
}
.disc {
/* position: absolute; */
z-index: 200;
/* width: 160px;
height: 160px; */
width: 100%;
max-width: 180px;
}
#compass-stats {
margin: 10px 0;
padding: 0.8em 0.6em;
}
/* weather center panel 'temp-group' */
#city {
margin: 20px 0 0 0;
display: inline-block;
}
#icon {
margin-bottom: -6px;
}
#temp {
display: inline-block;
/* margin: 24px 0; */
margin: 6px 0 0;
font-size: 4em;
position: relative;
color: darkgreen;
}
#temp::after {
content: "\00b0";
color: darkgreen;
font-size: 28px;
position: absolute;
top: -9px;
right: -14px;
}
#temp-deg {
font-size: 0.8em;
vertical-align: top;
}
#high-low {
margin-bottom: 24px;
margin-top: -5px;
}
#sky, #humidity, #wind-dir, #wind-speed, #sunrise, #sunset, #vis {
color: darkgreen;
/* font-weight: bold; */
font-style: italic;
}
/* City buttons right column */
#city-buttons {
/* margin-top: 20px; */
z-index: 400;
}
#city-buttons .ui.button {
width: 120px;
/* margin: 1px 0; */
}
.ui.buttons .or::before {
line-height: 1.60em;
border: 1px solid #999;
font-size: 14px;
top: 55%;
background-color: #f6f6f6;
}
.ui.button, .ui.buttons .button {
border: 1px solid #666;
margin: 1px 0;
}
/* Next row */
/* temp toggle left column */
#temp-group {
/* margin-top: 20px; */
border: 1px solid #666;
padding-top: 6px;
}
#temp-toggle {
border-left: unset;
}
#temp-toggle .button:first-child {
border-left: 1px solid #666;
border-top-left-radius: .28571429rem;
border-bottom-left-radius: .28571429rem;
}
/* debug panel */
#debug-container {
display: none;
}
#debug-content {
background: #eee;
padding: 10px 20px 20px 20px;
border: 1px solid #999;
}
.debug {
clear: both;
}
#hard-coded {
position: relative;
}
#hard-coded dl {
/* float: left; */
/* padding: 0 40px 0 30px; */
}
#hard-coded dl:last-child {
padding-right: 10px;
}
.hidden {
display: none;
}
#traverse-json, #json-fields-loop {
height: 270px;
}
#debug-content {
height: 380px;
}
#traverse-json, #json-fields-loop {
overflow-y: scroll;
}
.ui.popup.wide.center.transition {
width: 340px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.js"></script>
// Let's start with Los Angeles cause... why not?
let lat = 34.052234;
let lon = -118.243685;
// Google Maps Geocoding API key
const GeocodeAPIKey = "AIzaSyATszLTrO3Njt52156ddkyk85WcFRzgZEg"; // will use this later...
const TimeZoneAPIKey = "AIzaSyB80idMRjgP_qHfbqMZaYOuJSnGwME5LSY";
const DaysOfWeek = ["Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat", "Sun"];
const crossFadeTime = 1200;
const pathToImages = "https://local-weather-app.netlify.com/images/";
// json vars
let interval = null; // used to stop setInterval in whatTimeIsIt function so we can set a new time
let currentUnit = "imperial"; // keep track of current unit
let temp = 0;
let high = 0;
let low = 0;
let windSpeed = 0;
let windDegree = 0; // default val in case it isn't returned in json
let vis = 0;
// locations for each of the buttons
var locations = {
nairobi: { lat: -1.292066, lon: 36.821946 },
frankfurt: { lat: 50.110922, lon: 8.682127 },
lagos: { lat: 6.524379, lon: 3.379206 },
cape_code: { lat: 41.668948, lon: -70.293295 }, // Hyannis
paris: { lat: 48.858547, lon: 2.294449 }, // Tour Eiffel
// paris: { lat: 48.856614, lon: 2.352222 }, // Paris proper
// paris: { lat: 48.873792, lon: 2.295028 }, // Arc de Triomphe
// london: { lat: 51.520093, lon: -0.122097 }, // London's West End
london: { lat: 51.513676, lon: -0.12671 }, // London's theatre district
los_angeles: { lat: 34.052234, lon: -118.243685 } // my hood
};
// allows us to change background images
var bgImages = [
"clear-d.jpeg",
"clear-n.jpg",
"clouds-n.jpeg",
"cloudy-sky.jpg",
"clouds-pink.jpeg",
"drizzle-d.jpg",
"fog.jpg",
"night-fog1.jpg",
"night-fog3.jpg",
"purple-tree.jpg",
// "rain-d.jpeg",
"rain1.jpg",
"rain-thunder.jpg",
"snow-d.jpeg",
"snow-n.jpeg",
"wind-d.jpg",
"wind-n.jpeg"
];
// lets get started!
$(document).ready(function () {
// do semantic-ui calls before my init() function
$('.menu .item').tab(); // create the debug tabs
shoutOutToMyPeeps() // set up the callouts
init(); // let's start the show!
});
function init() {
// pre-load bgImages
for (var i = 0; i < bgImages.length; ++i) {
var img = new Image();
img.src = pathToImages + bgImages[i];
}
// for initial load
$("#main").css("opacity", "1.0");
$("#background-images").css("opacity", "1.0");
// setup button click event handlers
// Imperial or Metric? Set click eventhandler to toggle values
$(".cf-toggle").on("click", function(event) {
// console.log(event.target.id);
if (event.target.id != currentUnit) {
$(".cf-toggle").toggleClass("positive active");
// console.log(event.target.id);
if (event.target.id === "metric") {
toggleUnits("metric");
currentUnit = "metric";
} else {
toggleUnits("imperial");
currentUnit = "imperial";
}
}
});
// Geolocate me!
$("#use-my-location").on("click", getGeolocation);
// city buttons (lets write long form js)
document.getElementById("btn-Nairobi").addEventListener("click", function() {
getWeather(locations.nairobi.lat, locations.nairobi.lon);
});
document
.getElementById("btn-Frankfurt")
.addEventListener("click", function() {
getWeather(locations.frankfurt.lat, locations.frankfurt.lon);
});
document.getElementById("btn-Lagos").addEventListener("click", function() {
getWeather(locations.lagos.lat, locations.lagos.lon);
});
document.getElementById("btn-Cape-Cod").addEventListener("click", function() {
getWeather(locations.cape_code.lat, locations.cape_code.lon);
});
document.getElementById("btn-London").addEventListener("click", function() {
getWeather(locations.london.lat, locations.london.lon);
});
document.getElementById("btn-Paris").addEventListener("click", function() {
getWeather(locations.paris.lat, locations.paris.lon);
});
document
.getElementById("btn-Los-Angeles")
.addEventListener("click", function() {
getWeather(locations.los_angeles.lat, locations.los_angeles.lon);
});
// loop through bgImages array & create an event handler for each bgImage button
// need to use 'let' in for..loop for block level scope: https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
/*for (let i = 0; i < bgImages.length; i++) {
var btn = document.getElementById("bgImage-btn" + i);
btn.title = bgImages[i]; // set tooltip with image name
btn.setAttribute("rel", bgImages[i]); // set attribute for use in updateBackgroundImage()
btn.addEventListener("click", function() {
updateBackgroundImage(bgImages[i]);
});
}*/
bgImages.forEach(function changeImages(el, index) {
var btn = document.getElementById("bgImage-btn" + index);
btn.title = el; // set tooltip with image name
btn.setAttribute("rel", el); // set attribute for use in updateBackgroundImage()
btn.addEventListener("click", function () {
updateBackgroundImage(el);
});
});
// Above code can be replaced by creating bg-links dynamically - see crossfade.html #107-#114
// $("bg-controls a.label").click(function () {
// updateBackgroundImage(bgImages[i]);
// });
// debug panel
$("#debug-btn").click(function() {
$("#debug-container").transition("slide up");
});
// do the magic
getWeather(lat, lon);
}
// where am I?
function getGeolocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
lat = (position.coords.latitude).toFixed(6);
lon = (position.coords.longitude).toFixed(6);
console.log("lon:", lon, "lat", lat);
getWeather(lat, lon);
});
}
}
// ajax call using jquery (we use straight javascript ajax further down)
function getWeather(lat1, lon1) {
lat = lat1;
lon = lon1;
$.ajax({
url: "https://fcc-weather-api.glitch.me/api/current",
dataType: "jsonp",
data: {
lat: lat,
lon: lon,
units: "imperial"
},
jsonpCallback: "displayWeather"
});
}
// throw it up on the page
function displayWeather(json) {
console.log(json);
console.log("global temp ", json.main.temp);
// assign to global vars
temp = json.main.temp;
high = json.main.temp_max;
low = json.main.temp_min;
windSpeed = json.wind.speed;
windDegree = json.wind.deg || 0; // in case json.wind.deg is null or undefined
vis = json.visibility || 0;
// output temp & distance items in metric or imperial units
toggleUnits(currentUnit);
// fill page with the remaining data (using vanilla js here)
document.getElementById("city").innerHTML = json.name;
if (typeof json.weather[0].icon === "undefined") {
document.getElementById("icon").style.display = "none";
}else {
document.getElementById("icon").style.display = "inline-block";
}
document.getElementById("icon").src = json.weather[0].icon || "";
document.getElementById("sky").innerHTML =
json.weather[0].description.charAt(0).toUpperCase() +
json.weather[0].description.slice(1);
document.getElementById("humidity").innerHTML = json.main.humidity + "%";
document.getElementById("wind-dir").innerHTML = windDirection(windDegree);
document.getElementById("sunrise").innerHTML = new Date(
Number(json.sys.sunrise + "000")
).toLocaleTimeString();
document.getElementById("sunset").innerHTML = new Date(
Number(json.sys.sunset + "000")
).toLocaleTimeString();
document.getElementById("compass-deg").innerHTML =
windDegree.toFixed(2) + "°";
document.getElementById("conditionCode").innerHTML = json.weather[0].id;
document.getElementById("lat").innerHTML = lat; // json.coord.lat is truncated to 2 decimal places - don't use
document.getElementById("lon").innerHTML = lon; // json.coord.lon is truncated to 2 decimal places - don't use
// point me in the right direction
setCompass(windDegree);
// console.log(json.wind.deg);
// console.log(windDegree);
// set background image based on weather condition
// FIX: This is now moved to whatTimeIsIt() function so it can be based on time of day also
// doWeatherCondition(json.weather[0].id, timeOfDay);
// show me local time & set background image
whatTimeIsIt(lat, lon, "localTime", json.weather[0].id);
// build debug panel
buildDebugPanel(json);
}
// make the magic with css transform, rotate, & degree - this is cool
function setCompass(degree) {
setTimeout(function() {
$(".arrow").css("transform", "rotate(" + degree + "deg)");
}, 1000);
//$(".arrow:hover").css("transform", "rotate(225deg)")
// var prev = $(".arrow").css("transform");
$(".arrow").hover(
function() {
$(".arrow").css("transform", "rotate(0deg)");
// console.log("hover in");
},
function() {
$(".arrow").css("transform", "rotate(" + degree + "deg");
// console.log("hover out");
}
);
}
// Display localized time for a chosen city
function whatTimeIsIt(lat, lon, tagId, conditionCode) {
// console.log("lat:", lat);
// console.log("lon:", lon);
// http://www.javascriptkit.com/dhtmltutors/local-time-google-time-zone-api.shtml
// http://www.javascriptkit.com/dhtmltutors/live-local-time-google-time-zone-api.shtml
var container = document.getElementById(tagId);
var targetDate = new Date(); // Current date/time of user computer
var timestamp =
targetDate.getTime() / 1000 + targetDate.getTimezoneOffset() * 60; // Current UTC date/time expressed as seconds since midnight, January 1, 1970 UTC
var apiCall =
"https://maps.googleapis.com/maps/api/timezone/json?location=" +
lat +
", " +
lon +
"×tamp=" +
timestamp +
"&key=" +
TimeZoneAPIKey;
// set new time
clearInterval(interval);
var xhr = new XMLHttpRequest(); // create new XMLHttpRequest2 object
xhr.open("GET", apiCall); // open GET request
xhr.onload = function() {
if (xhr.status === 200) {
// if Ajax request successful
var output = JSON.parse(xhr.responseText); // convert returned JSON string to JSON object
// console.log(output.status); // log API return status for debugging purposes
if (output.status === "OK") {
// if API reports everything was returned successfully
var offsets = output.dstOffset * 1000 + output.rawOffset * 1000; // get DST and time zone offsets in milliseconds
var localDate = new Date(timestamp * 1000 + offsets); // Date object containing current time of city(timestamp + dstOffset + rawOffset)
// console.log("in: ", localDate.toLocaleString()); // Display current citydate and time
var refreshDate = new Date(); // get current date again to calculate time elapsed between targetDate and now
var millisecondsElapsed = refreshDate - targetDate; // get amount of time elapsed between targetDate and now
localDate.setMilliseconds(
localDate.getMilliseconds() + millisecondsElapsed
); // update localDate to account for any time elapsed
interval = setInterval(function() {
localDate.setSeconds(localDate.getSeconds() + 1);
container.innerHTML =
localDate.toLocaleTimeString() +
" (" +
DaysOfWeek[localDate.getDay()] +
")";
}, 1000);
// set background image based on weather condition
var timeOfDay = "d";
if (localDate.getHours() < 7 || localDate.getHours() > 17) {
timeOfDay = "n";
console.log("night", "hour", localDate.getHours());
} else {
console.log("day", "hour", localDate.getHours());
}
doWeatherCondition(conditionCode, timeOfDay);
}
} else {
alert("Request failed. Returned status of " + xhr.status);
}
};
xhr.send(); // send request
}
// functions to toggle between Celcius & Fahrenheit
function toggleUnits(unit) {
if (unit === "imperial") {
// console.log("imperial", convertCtoF(temp));
document.getElementById("temp").innerHTML = convertCtoF(temp);
document.getElementById("high").innerHTML = convertCtoF(high) + "°";
document.getElementById("low").innerHTML = convertCtoF(low) + "°";
document.getElementById("wind-speed").innerHTML = convertWindToMiles(
windSpeed
);
document.getElementById("vis").innerHTML = convertVisToMiles(vis);
} else if (unit === "metric") {
// console.log("metric", temp);
// console.log("vis",vis);
document.getElementById("temp").innerHTML = temp.toFixed();
document.getElementById("high").innerHTML = high + "°";
document.getElementById("low").innerHTML = low + "°";
document.getElementById("wind-speed").innerHTML = windSpeed + " m/s";
document.getElementById("vis").innerHTML = vis.toLocaleString() + " m";
}
}
function convertCtoF(cel) {
return Math.floor(cel * 1.8 + 32);
}
function convertVisToMiles(meters) {
return (meters / 1609.344).toFixed(2) + " mi";
}
function convertWindToMiles(meters) {
return (meters * 2.2369).toFixed(2) + " mph";
}
function windDirection(degree) {
var dir = "";
switch (true) {
case degree < 11.25:
dir = "North";
break;
case degree < 33.75:
dir = "North NW";
break;
case degree < 56.25:
dir = "NorthEast";
break;
case degree < 78.75:
dir = "East NE";
break;
case degree < 101.25:
dir = "East";
break;
case degree < 123.75:
dir = "East SE";
break;
case degree < 146.25:
dir = "SouthEast";
break;
case degree < 168.75:
dir = "South SE";
break;
case degree < 191.25:
dir = "South";
break;
case degree < 213.75:
dir = "South SW";
break;
case degree < 236.25:
dir = "SouthWest";
break;
case degree < 258.75:
dir = "West SW";
break;
case degree < 281.25:
dir = "West";
break;
case degree < 303.75:
dir = "West NW";
break;
case degree < 326.25:
dir = "NorthWest";
break;
case degree < 348.75:
dir = "North NE";
break;
default:
dir = "North";
}
return dir;
}
function doWeatherCondition(conditionCode, timeDay) {
var bgImage = "";
switch (true) {
case conditionCode < 240: //Thunderstorm
if (timeDay === "d") {
bgImage = "thunder-d.jpeg";
} else {
bgImage = "thunder-n.jpg";
}
break;
case conditionCode < 330: //Drizzle
bgImage = "drizzle-d.jpg";
break;
case conditionCode < 540: //Rain
if (timeDay === "d") {
// bgImage = "rain-d.jpeg";
bgImage = "rain1.jpg";
} else {
bgImage = "rain-on-black.jpg";
}
break;
case conditionCode < 630: //Snow
if (timeDay === "d") {
bgImage = "snow-d.jpeg";
} else {
bgImage = "snow-n.jpeg";
}
break;
case conditionCode < 790: //Atmospheric - haze, fog, mist
if (timeDay === "d") {
bgImage = "fog.jpg";
} else {
bgImage = "night-fog3.jpg";
}
break;
case conditionCode === 800: //Clear
if (timeDay === "d") {
bgImage = "clear-d.jpeg";
} else {
bgImage = "clear-n.jpg";
}
break;
case conditionCode < 805: //Clouds
if (timeDay === "d") {
bgImage = "cloudy-sky.jpg";
} else {
bgImage = "clouds-n.jpeg";
}
break;
case conditionCode < 910: //Extreme - tropical storm, hail, hurricane, tornado
bgImage = "rain-thunder.jpg";
break;
case conditionCode < 970: //Additional - breeze, wind, gale
if (timeDay === "d") {
bgImage = "wind-d.jpg";
} else {
bgImage = "wind-n.jpeg";
}
break;
default:
bgImage = "";
}
// bgImage = "cloudy-sky.jpg";
updateBackgroundImage(bgImage);
}
function updateBackgroundImage(img) {
// $("body").css("background-image", "url('" + pathToImages + img + "')");
if ($("#background-images div.front").attr("rel") !== img) {
// if this isn't already the bg image
$("background-images div.back").attr("rel", img); // set rel to image name
$("#background-images div.back").css(
"background-image",
"url('" + pathToImages + img + "')"
); //set background-image on .back div
crossFadeImages(); // do the magic
}
}
function crossFadeImages() {
var $front = $("#background-images .front");
var $back = $("#background-images .back");
$front.fadeOut(crossFadeTime, function() {
//fade out the top image
$front.addClass("back").removeClass("front").show(); //remove class which resets z-index to 1 and unhide the image (which is now behind 'back') with show()
$back.addClass("front").removeClass("back"); // give new image z-index of 3 from z-index 2
});
}
// Debug panel, object iteration, & raw json output
function buildDebugPanel(json) {
var html = "";
html += "<p>" + new Date(Number(json.dt + "000")).toLocaleString() + "</p>";
html += "<div class='ui horizontal segments'>";
html += "<dl class='ui segment'>";
html += "<dt>Location:</dt><dd>" + json.name + "</dd>"; // name
html += "<dt>Temp:</dt><dd>" + convertCtoF(json.main.temp) + "</dd>"; //main.temp
html += "<dt>High:</dt><dd>" + convertCtoF(json.main.temp_max) + "</dd>"; //main.temp_max
html += "<dt>Low:</dt><dd>" + convertCtoF(json.main.temp_min) + "</dd>"; //main.temp_min
// html += "<dt>Date/Time run:</dt><dd>" + new Date(Number(json.dt + '000')).toLocaleString() + "</dd>"; // dt
html += "</dl>";
html += "<dl class='ui segment'>";
html += "<dt>Conditions:</dt><dd>" + json.weather[0].main + "</dd>"; // weather[0].main
html += "<dt>Description:</dt><dd>" + json.weather[0].description + "</dd>"; //weather[0].description
html +=
"<dt>Icon:</dt><dd>" +
"<img id='icon' src='" +
(json.weather[0].icon || "#") +
"'></dd>"; //weather[0].icon
html += "</dl>";
html += "<dl class='ui segment'>";
html +=
"<dt>Sunrise:</dt><dd>" +
new Date(Number(json.sys.sunrise + "000")).toLocaleTimeString() +
"</dd>"; //sys.sunrise
html +=
"<dt>Sunset:</dt><dd>" +
new Date(Number(json.sys.sunset + "000")).toLocaleTimeString() +
"</dd>"; //sys.sunset
html += "</dl>";
html += "<dl class='ui segment'>";
html +=
"<dt>Wind:</dt><dd>" +
convertWindToMiles(json.wind.speed) +
" " +
windDirection(json.wind.deg) +
"</dd>"; //wind.speed
// html += "<dt>Direction:</dt><dd>" + windDirection(json.wind.deg) + "</dd>"; //wind.deg
html += "<dt>Pressure:</dt><dd>" + json.main.pressure + " hPa</dd>"; //main.pressure
html += "<dt>Humidity:</dt><dd>" + json.main.humidity + "%<br />"; //main.humidity
html +=
"<dt>Visibility:</dt><dd>" + convertVisToMiles(json.visibility) + "</dd>"; //visibility
html += "</dl>";
html += "<dl class='ui segment'>";
html += "<dt>Country:</dt><dd>" + json.sys.country + "</dd>"; //sys.country
html += "<dt>Latitude:</dt><dd>" + json.coord.lat + "</dd>"; // coord.lat
html += "<dt>Longitude:</dt><dd>" + json.coord.lon + "</dd>"; // coord.lon
html += "</dl>";
html += "</div>";
$("#hard-coded").html(html);
// vanilla JS expression for fun
document.getElementById("traverse-json").innerHTML = traverse(json, "");
// jQuery expression for fun
$("#json-fields-loop").html(jsonFieldsLoop(json, ""));
$("#output").html(JSON.stringify(json));
}
// jQuery object loop
function jsonFieldsLoop(json, htmlStr) {
// Loop done with jQuery
$.each(json, function(k, v) {
if (typeof v === "object") {
htmlStr += k + "<br />";
htmlStr = jsonFieldsLoop(v, htmlStr);
} else {
htmlStr += k + ": " + v + "<br />";
}
});
return htmlStr;
}
// Vanilla JS object loop
function traverse(obj, htmlStr) {
htmlStr += "<ul>";
// Loop done with for..in which needs hasOwnProperty check
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (!!obj[property] && typeof obj[property] === "object") {
htmlStr += "<li><b>" + property + "</b>";
htmlStr = traverse(obj[property], htmlStr);
htmlStr += "</li>";
} else {
switch (property) {
case "sunrise":
case "sunset":
obj[property] = new Date(
Number(obj[property] + "000")
).toLocaleTimeString();
break;
case "temp":
case "temp_min":
case "temp_max":
obj[property] = convertCtoF(obj[property]);
break;
}
htmlStr += "<li>" + property + ": " + obj[property] + "</li>";
}
}
}
htmlStr += "</ul>";
return htmlStr;
}
// res ipsa ...
function shoutOutToMyPeeps() {
$("#btn-Nairobi").popup({
title: "Go Hufflepuff!γ",
content:
"This is for my friend in Kenya who's gonna run her own game dev company one day!ππ",
variation: "wide",
position: "left center",
inline: "true"
});
$("#btn-Frankfurt").popup({
html:
"<div class='header'>She codes the best Bear on a Waffle!ππ</div><div class='content'>This is really for my favorite cat Cuddle Bear!π<br />His owner is pretty cool too. She has <strong>mad</strong> CSS skills!ππ</div>",
variation: "wide",
position: "left center",
inline: "true"
});
$("#btn-Lagos").popup({
// title: "Representing Africa's West Side",
html:
"<div class='header'>Representing Africa's West Side</div><div class='content'>This is for my friend in Nigeria who likes π₯Simiπ₯ and the finer things in life! πππ·π<br /><br/ >(BTW, 'Original Baby', 'One Kain', 'Smile For Me', 'Love Don't Care', & 'Jamb Question' all get ππ)</div>",
variation: "wide",
position: "left center",
inline: "true"
});
$("#btn-Cape-Cod").popup({
title: "Living the dream!",
content:
"This is for my Twitter friend and fellow countryman on the East Coast who always has words of encouragement and support for his fellow coders.ππππ",
variation: "wide",
position: "left center",
inline: "true"
});
$("#btn-London").popup({
html:
"<div class='header'>And the award goes to...πππ</div><div class='content'>This is for my friend in London who's a star of the stageππΆ and computer screen!π»π<br /><br />I use her post on how to break down arrow functions regularly!ππ</div>",
variation: "wide",
position: "left center",
inline: "true"
});
$("#btn-Paris").popup({
title: "For my Ryan Reynoldsπ Fan Clubβ’ friends..",
html:
"<div class='header'>For my Ryan Reynoldsπ Fan Clubβ’ friends..</div><div class='content'>I don't know where you two live* but I think Paris is the perfect place for soul mates to meet for coffee.ππ<br><br>* Laniakea... Really? the Local Supercluster home to our Milky Way Galaxy?... Doesn't really narrow it down, does it... and what is this place called 'Germany' for that matter?ππ",
variation: "wide",
position: "left center",
inline: "true"
});
$("#btn-Los-Angeles").popup({
title: "πβ My Hood. ππ",
content:
"This is for me so I can see what the β
weather's like before a run π½πor hikeππ.",
variation: "wide",
position: "left center",
inline: "true"
});
}
<div id="background-images">
<div class="bgImages front" id="bgImg1"><div class="view"><!--Img 1 - front--></div></div>
<div class="bgImages back" id="bgImg2"><br><div class="view"><!--Img 2 - back--></div></div>
</div>
<main class="ui fluid container" role="main" id="main">
<section class="ui vertical masthead center aligned segment">
<div class="ui text container" id="content">
<h1 id="header">Local Weather App</h1>
<i id="debug-btn" class="link bordered setting icon" ></i>
<p><i>Check out some of the cities I have Twitter friends in or click "Use my location".</i></p>
<div class="ui three column stackable grid" id="row">
<div class="four wide column">
<div id="compass-label">Wind Direction</div>
<div class="animate" id="compass-deg">0.00</div>
<div class="compass">
<img class="arrow" src="https://local-weather-app.netlify.com/images/arrow.svg" alt="arrow">
<img class="disc" src="https://local-weather-app.netlify.com/images/disc.svg" alt="disc">
</div>
<div class="ui segment" id="compass-stats">
<div class="hidden">Code: <span id="conditionCode"></span></div>
<div>Lat: <span class="animate" id="lat">0.000000</span></div>
<div>Lon: <span class="animate" id="lon">0.000000</span></div>
</div>
</div>
<div class="eight wide column">
<div class="ui segment" id="temp-group">
<div class="animate" id="loc-header-container">
<div class="ui large header" id="city">City</div>
<img id="icon" src="#" alt="icon">
</div>
<div class="animate" id="localTime">Time & Day</div>
<div class="ui huge header animate" id="temp">0</div>
<div id="high-low"><span id="high" class="ui red label animate" data-tooltip="Today's High">Hi</span> <span id="low" class="ui blue label animate" data-tooltip="Today's Low">Low</span></div>
<div><span class="animate" id="sky">Condition</span> with <span class="animate" id="humidity">0%</span> humidity</div>
<div>Wind: <span class="animate" id="wind-dir">Direction</span> at <span class="animate" id="wind-speed">0 mph</span></div>
<div>Visibility: <span class="animate" id="vis">0.00 mi</span></div>
<div class="hidden">Sunrise: <span id="sunrise"></span> - Sunset: <span id="sunset"></span></div>
</div>
</div>
<div class="four wide column" id="city-buttons">
<button class="ui button" id="btn-Nairobi">Nairobi</button>
<button class="ui button" id="btn-Frankfurt">Frankfurt</button>
<button class="ui button" id="btn-Lagos">Lagos</button>
<button class="ui button" id="btn-Cape-Cod">Cape Cod</button>
<button class="ui button" id="btn-London">London</button>
<button class="ui button" id="btn-Paris">Paris</button>
<button class="ui button" id="btn-Los-Angeles">Los Angeles</button>
</div>
<div class="four wide column">
<div class="ui buttons tiny" id="temp-toggle">
<button class="ui button cf-toggle" id="metric">C</button>
<div class="or"></div>
<button class="ui button cf-toggle active positive" id="imperial">F</button>
</div>
</div>
<div class="eight wide column bg-controls">
<a class="ui red empty circular label" id="bgImage-btn0"></a>
<a class="ui orange empty circular label" id="bgImage-btn1"></a>
<a class="ui yellow empty circular label" id="bgImage-btn2"></a>
<a class="ui olive empty circular label" id="bgImage-btn3"></a>
<a class="ui green empty circular label" id="bgImage-btn4"></a>
<a class="ui teal empty circular label" id="bgImage-btn5"></a>
<a class="ui blue empty circular label" id="bgImage-btn6"></a>
<a class="ui violet empty circular label" id="bgImage-btn7"></a>
<a class="ui purple empty circular label" id="bgImage-btn8"></a>
<a class="ui pink empty circular label" id="bgImage-btn9"></a>
<a class="ui brown empty circular label" id="bgImage-btn10"></a>
<a class="ui grey empty circular label" id="bgImage-btn11"></a>
<a class="ui black empty circular label" id="bgImage-btn12"></a>
<a class="ui red empty circular label" id="bgImage-btn13"></a>
<a class="ui orange empty circular label" id="bgImage-btn14"></a>
<a class="ui yellow empty circular label" id="bgImage-btn15"></a>
</div>
<div class="four wide column">
<button class="ui button positive tiny" id="use-my-location">Use my location</button>
</div>
</div>
</div>
</section>
<div class="ui text container" id="debug-container">
<h2 class ="ui small center aligned top attached block header">Debug Info</h2>
<section class="ui attached segment" id="debug-content">
<div class="ui top attached tabular stackable menu">
<a class="active item column" data-tab="first">Hard coded</a>
<a class="item column" data-tab="second">Traverse JSON</a>
<a class="item column" data-tab="third">JSON Fields Loop</a>
<a class="item column" data-tab="fourth">Raw Output</a>
</div>
<div class="ui bottom attached active tab segment" data-tab="first" id="hard-coded">
</div>
<div class="ui bottom attached tab segment " data-tab="second">
<div id="traverse-json"></div>
</div>
<div class="ui bottom attached tab segment" data-tab="third">
<!-- <h3>JSON Fields loop</h3> -->
<div id="json-fields-loop"></div>
</div>
<div class="ui bottom attached tab segment" data-tab="fourth">
<!-- <h3>Raw Output</h3> -->
<div id="output"></div>
</div>
</section>
</div>
</main>
Uses Semantic-UI, jQuery, Ajax, JSONP, Web APIs, SVG & CSS transitions. Free Code Camp Intermediate Front End Development Project.
A Pen by HARUN PEHLΔ°VAN on CodePen.