HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URL's added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by Skypack, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ES6 import
usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<div class="background dusk">
</div>
<div class="background dawn">
</div>
<div class="author_info" id="author_info">
<h1>My Overachieving Weather App</h1>
<div class="author_info_content">
<p>Hey there! So here is my little weather app. I'm currently going through the Free Code Camp curriculum on a part-time basis. I've been involved with web technologies since the mid-1990s - the Compuserve era in fact!</p>
<p>This little page is my answer to their Weather App challenge. I decided to spice it up a bit. The original challenge called for the user of the browser geolocation API as well as a weather API to show current weather for the user's location as well as the ability to toggle temperatures between Fahrenheit and Celsius.</p>
<p>I wanted the challenge of working with multiple APIs to put together a page. So this page presents a small, arbitrary gallery of 10 cities around the planet for which you can view the weather. Additionally, it is backed by Google's places API, so you can enter any city and it will display the weather first result found.</p>
<p>
Using Sunset/Sunrise times the page will also update its look based on the time of day as well as for current weather conditions.
</p>
<p>In the end, nothing super groundbreaking (in fact, I don't think there's anything done here that hasn't been done before). But it was a fun challenge for myself and I hope you enjoy it!</p>
</div>
</div>
<div class="main container">
<div class="row">
<div class="left hidden-xs col-xs-12 col-sm-2 col-md-2 col-lg-2">
</div>
<div class="middle col-xs-12 col-sm-8 col-md-8 col-lg-8">
<div class="upper grid">
<div class="top conditions">
<h1 class="location_name">
</h1>
<h3 class="current_conditions"></h3>
<div class="weather_icon"><img class="day"><img class="night"></div>
<div class="info temperature margin_left hidden" title="Toggle Temperature Scale" data-clickhandler="temperature">
<p>Temperature <span class="temp"></span>° <span class="scale"></span></p>
</div>
<div class="info wind hidden">
<p>Wind <span class="wind_speed" title="Meters/Second"></span> <span class="wind_direction"></span>° (<span class="wind_compass_direction"></span>)</p>
</div>
<div class="info latlong margin_left hidden" data-clickhandler="display_map" title="Open in Google Maps!">
<p>Latitude: <span class="lat"></span>°</p>
<p>Longitude: <span class="lng"></span>°</p>
</div>
<div class="info time hidden" title="These times are adjusted relative to the location you are viewing.">
<p>Sunrise: <span class="sunrise"></span></p>
<p>Sunset: <span class="sunset"></span></p>
</div>
</div>
</div>
<div class="lower">
<div class="top forecast">
<h3>Forecast</h3>
</div>
<div class="bottom">
</div>
</div>
</div>
<div class="right hidden-xs ccol-xs-12 col-sm-2 col-md-2 col-lg-2">
</div>
</div>
<div class="row">
<div class="text-center find_location col-xs-12 col-sm-12 col-md-12 col-lg-12">
<form class="find_city"><input type="text" class="location" value="" placeholder="Enter a City Name"><button class="find" type="button" data-clickhandler="load_city">Find it!</button></form>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<p class="text-center"><span data-clickhandler="show_author_info" class="show_author_info">About this Weather App.</span> | Micheal Hall, 2016 </p>
</div>
</div>
</div>
/* COLORS */
.main a,
.main a:hover{
color: white;
}
.background{
position: fixed;
left: 0;
top: 0;
height: 100%;
width: 100%;
}
button {
font-family: 'Oswald';
color: black;
font-size: .8em;
}
body{
background-color: rgb(122, 122, 122);
}
body,
input
{
transition: background-color 3s, color .5s;
}
input{
color: rgba(0,0,0,.5);
}
.info,
input{
transition: background-color .5s, color .5s;
}
.latlong:hover,
.temperature:hover{
cursor: pointer;
}
body .weather_icon img.day,
body .weather_icon img.night{
display: none;
}
body.day .weather_icon img.day,
body.night .weather_icon img.night{
display: inline-block;
}
body.temp_scale_C .min_f,
body.temp_scale_C .max_f,
body.temp_scale_F .min_c,
body.temp_scale_F .max_c{
display: none;
}
.author_info {
z-index: 15;
position: absolute;
left: 0;
top: 0;
width: 50%;
height: 75%;
margin-left: 25%;
margin-top: 5%;
background-color: rgb( 200,200,200);
color: black;
border-radius: 6px;
transition: transform .25s cubic-bezier(.42,0,.91,1.22), background-color 3s, color 3s;
box-shadow: 0 0 6px rgba( 0,0,0,.5 );
overflow: hidden;
}
.author_info.hidden_left{
transition: transform .25s ease-out;
transform: translateX(-200%);
}
.author_info p{
margin: 1em 2em;
}
.author_info .author_info_content{
overflow: auto;
margin-top: 1em;
height: calc( 100% - 8em );
}
span.show_author_info:hover{
cursor: pointer;
text-decoration: underline;
}
/* SUNNY COLOR STYLES */
body .dusk,
body .dawn{
opacity: 0;
transition: opacity 3s;
}
body.clear.dawn .dawn{
transition: opacity 3s;
opacity: 1;
background: linear-gradient(to bottom, rgba(6,3,79,1) 0%,rgba(54,46,209,1) 29%,rgba(175,196,208,1) 65%,rgba(247,220,81,1) 81%,rgba(244,168,80,1) 88%,rgba(210,42,22,1) 96%,rgba(210,42,22,1) 100%);
}
body.clear.dusk .dusk{
transition: opacity 3s;
opacity: 1;
background: linear-gradient(to bottom, rgba(6,3,79,1) 0%,rgba(46,42,170,1) 29%,rgba(206,175,194,1) 65%,rgba(247,230,145,1) 81%,rgba(244,168,80,1) 88%,rgba(209,23,47,1) 96%,rgba(209,23,72,1) 100%);
}
body.clear .author_info{
color: white;
background-color: rgb(128, 187, 247);
}
body.clear ::-webkit-input-placeholder{
color: white;
}
.clear input{
color: white;
background-color: rgb(128, 187, 247);
}
.clear .gallery_item img:hover {
box-shadow: 0 0 3px 3px rgb(224, 161, 13);
}
.clear .latlong:hover,
.clear .temperature:hover,
.clear input:focus{
background-color: rgb(255, 212, 112);
color: rgba(0,0,0,.5);
}
body.clear{
background: none;
background-color: rgb(7, 99, 191);
}
body.clear.night {
background-color: rgb(9, 12, 71);
}
.clear.night .gallery_item img:hover{
box-shadow: 0 0 3px 3px rgb(95, 103, 239);
}
/* THUNDERSTORM COLOR STYLES */
body.thunderstorm{
background-color: rgb(15,15,15);
}
body.thunderstorm.night{
color: white;
background-color: rgb(0, 0, 0);
}
body.thunderstorm .author_info{
background-color: rgb(45,45,45);
}
.thunderstorm input{
background-color: rgb(64, 64, 64);
}
.thunderstorm .latlong:hover,
.thunderstorm .info.temperature:hover,
.thunderstorm input:focus{
background-color: rgb(255, 253, 155);
color: black;
}
.thunderstorm .forecast_box{
color: rgb(255, 253, 155);
}
/* CLOUDY COLOR STYLES */
body.cloudy{
background-color: rgb(68, 68, 68);
}
body.cloudy.night{
background-color: rgb(8,8,8);
}
body.cloudy .author_info{
color: white;
background-color: rgb(128,128,128);
}
.cloudy .middle{
border-color: rgb(12, 12, 12);
}
.cloudy input{
background-color: rgb(64,64,64);
}
.cloudy .latlong:hover,
.cloudy .temperature:hover,
.cloudy input:focus{
background-color: rgb(112, 193, 255);
color: rgba(0,0,0,.5);
}
.cloudy .gallery_item img{
filter: grayscale(75%);
}
.cloudy .gallery_item img:hover {
box-shadow: 0 0 3px 3px rgb(28, 28, 28);
}
/* SNOWY COLOR STYLES */
.snowy a,
.snowy a:hover{
color: black;
}
body.snowy{
background: none;
background-color: rgb(255,255,255);
}
.snowy .lower .forecast{
background-color: rgba( 0,0,0,.3);
border: solid 1px black;
border-radius: 3px;
}
.snowy input:focus{
background-color: black;
color: white;
}
.snowy .gallery_item img{
filter: grayscale(100%);
}
.snowy .latlong:hover,
.snowy .temperature:hover{
cursor: pointer;
}
.snowy .latlong:hover,
.snowy .info.temperature:hover{
background-color: rgb(170, 212, 255);
}
.snowy {
color: rgb(28,28,28);
}
.snowy .info{
background-color: rgba(0,0,0,.1);
}
.snowy .gallery_item img:hover {
box-shadow: 0 0 3px 3px rgb(28, 28, 28);
}
/* END COLOR THEMES */
body {
font-family: 'Montserrat', sans-serif;
color: white;
}
h1,
h3{
text-align: center;
margin: 0;
}
h1{
margin-top: 1em;
}
h1,
.top.forecast{
font-family: 'Oswald';
}
.middle{
margin: 0;
height: 100%;
z-index: 10;
overflow: hidden;
}
.lower .bottom,
.lower .top,
.middle .upper,
.middle .lower{
height: 65%;
}
.lower .top{
margin-top: 2em;
}
.middle .upper {
left: 0;
top: 0;
height: 75%;
}
.middle .lower {
left: 0;
top: 65%;
height: 50%;
z-index: 10;
}
.find_location {
text-align: center;
padding: 1em;
bottom: 0;
font-size: 1.5em;
}
.forecast h3{
margin: .5em 0;
}
.forecast {
overflow: hidden;
position: relative;
}
.forecast_box {
opacity: 1;
display: inline-block;
width: 23%;
height: calc( 100% - 6em );
margin-left: 1.25%;
text-align: center;
padding-top: .5em;
overflow: hidden;
box-sizing: border-box;
}
.forecast_box._0{
transition: transform .2s cubic-bezier(.56,-0.01,.9,1.33), opacity .35s ease-out .1s;
}
.forecast_box._1{
transition: transform .2s cubic-bezier(.56,-0.01,.9,1.33) .125s, opacity .35s ease-out .15s;
}
.forecast_box._2{
transition: transform .2s cubic-bezier(.56,-0.01,.9,1.33) .25s, opacity .35s ease-out .2s;
}
.forecast_box._3{
transition: transform .2s cubic-bezier(.56,-0.01,.9,1.33) .375s, opacity .35s ease-out .25s;
}
.forecast_box.hidden_bottom{
transform: translateY(350px);
opacity: 0;
}
.forecast_box p.in_left{
transition: transform .25s ease-in .25s, opacity .25s ease-in .21s;
opacity: 0;
transform: translateX(-200%);
}
.forecast_box p.in_right{
transition: transform .25s ease-in .25s, opacity .25s ease-in .21s;
opacity: 0;
transform: translateX(200%);
}
.forecast_box:hover p.in_bottom,
.forecast_box:hover p.in_left,
.forecast_box:hover p.in_right{
opacity: 1;
transition: transform .25s ease-in, opacity .25s ease-in .05s;
transform: translateX(0) translateY(0);
}
.forecast_box p.in_bottom{
transition: transform .25s ease-in .25s, opacity .25s ease-in .21s;
opacity: 0;
transform: translateY(-200%);
}
.forecast_box p{
margin-bottom: 0;
}
.forecast_box img{
margin: 0;
margin-left: -.75em;
width: 100%;
max-width: 170px;
height: auto;
}
input{
padding-left: .5em;
border: none;
border-radius: 3px;
box-shadow: inset 2px 2px 2px rgba( 0,0,0, .5);
}
.gallery_item {
height: calc( 20% - .5em );
width: 100%;
float: left;
overflow: hidden;
margin-bottom: .5em;
text-align: center;
color: white;
text-shadow: 1px 1px 1px rgba( 0,0,0,.8);
}
.gallery_item:hover{
cursor: pointer;
}
.gallery_item img:hover{
filter: none;
}
.gallery_item img{
width: 100px;
height: auto;
margin-top: .5em;
border-radius: 50%;
border: none;
box-shadow: 0 0 6px rgba( 0,0,0,.75);
}
.info{
border-radius: 3px;
background-color: rgba(255,255,255,.2);
display: inline-block;
width: 35%;
font-size: .8em;
text-align: center;
min-height: 25%;
font-size: 1.2em;
margin-top: 1em;
margin-left: 3%;
overflow: hidden;
}
.info.margin_left {
margin-left: 15%;
}
.info p {
margin-top: 1em;
}
.weather_icon{
height: 120px;
}
.weather_icon img{
display: block;
width: 175px;
height: 120px;
margin-left: calc( 50% - 90px );
}
.reset {
position: relative;
}
@media all and (min-width: 480px) {
.author_info{
margin: 0;
width: 100%;
height: 100%;
}
.gallery_item {
margin-top: 0;
width: 20%;
}
.gallery_item img{
width: 85px;
}
.info {
font-size: .8em;
}
}
@media all and (min-width: 768px) {
.author_info{
width: 50%;
height: 75%;
margin-left: 25%;
margin-top: 5%;
}
.gallery_item:first-child{
margin-top: 1em;
}
.gallery_item {
width: 100%;
}
.gallery_item img {
width: 85px;
}
}
@media all and (min-width: 992px) {
.gallery_item img {
width: 105px;
}
.info {
font-size: 1em;
}
}
(() => {
var now = new Date();
const $body = $( 'body' );
const $time = $body.find( '.info.time' );
const config = {
'templates':{
'gallery_item': $( '<div class="gallery_item" data-clickhandler="load_gallery_city"><img class="city_image clickable" title="Click to check the weather!"><p class="city_name"></p></div>' ),
'forecast_item': $( '<div class="forecast_box hidden_bottom"><p class="in_left date"></p><p class="in_right time"><span class="min_f"></span><span class="min_c"></span>° - <span class="max_f"></span><span class="max_c"></span>°</p><img class="forecast_icon"><p class="in_bottom conditions"></p></div>' ),
'author_info': null,
},
'condition_classes': [ 'day', 'clear', 'cloudy', 'snowy', 'thunderstorm', 'night', 'dawn', 'dusk' ].join( ' ' ),
'temperature_classes': [ 'temp_scale_F', 'temp_scale_C' ].join( ' '),
'current_conditions': {},
'do_location_query': true,
'forecast_conditions': {},
'forecast_limit': 4,
'forecast_time': '12:00:00',
'weather_conditions' : {
'200': {
'condition': 'Thunderstorms with light rain.',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'201': {
'condition': 'Thunderstorms with rain.',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'202': {
'condition': 'Thunderstorms with heavy rain.',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'203': {
'condition': 'Light thunderstorms.',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'204': {
'condition': 'Thunderstorm.',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'205': {
'condition': 'Heavy Thunderstorm',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'206': {
'condition': 'Ragged Thunderstorm.',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'207': {
'condition': 'Thunderstorm with Light Drizzle.',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'208': {
'condition': 'Thunderstorm with Drizzle.',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'209': {
'condition': 'Thunderstorm with Heavy Drizzle.',
'css_class': 'thunderstorm',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'300': {
'condition': 'Light intensity Drizzle.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png'
}
},
'301': {
'condition': 'Drizzle.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png'
}
},
'302': {
'condition': 'Heavy intensity Drizzle.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png'
}
},
'310': {
'condition': 'Light intensity Drizzle Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png'
}
},
'311': {
'condition': 'Drizzle Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png'
}
},
'312': {
'condition': 'Heavy intensity Drizzle Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png'
}
},
'313': {
'condition': 'Shower Rain and Drizzle.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png'
}
},
'314': {
'condition': 'Heavy Shower Rain and Drizzle.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png'
}
},
'321': {
'condition': 'Shower Drizzle.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/9.png'
}
},
'500': {
'condition': 'Light Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/11.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/11.png'
}
},
'501': {
'condition': 'Moderate Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/11.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/11.png'
}
},
'502': {
'condition': 'Heavy Intensity Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png'
}
},
'503': {
'condition': 'Very Heavy Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png'
}
},
'504': {
'condition': 'Extreme Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png'
}
},
'511': {
'condition': 'Freezing Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/08.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/08.png'
}
},
'520': {
'condition': 'Light Intensity Shower Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/11.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/11.png'
}
},
'521': {
'condition': 'Shower Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/11.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/11.png'
}
},
'522': {
'condition': 'Heavy Intensity Shower Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png'
}
},
'531': {
'condition': 'Ragged Shower Rain.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png'
}
},
'600': {
'condition': 'Light Snow.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/13.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/13.png'
}
},
'601': {
'condition': 'Snow.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/14.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/14.png'
}
},
'602': {
'condition': 'Heavy Snow.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/18.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/18.png'
}
},
'611': {
'condition': 'Sleet.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/25.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/25.png'
}
},
'612': {
'condition': 'Shower Sleet.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/8.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/8.png'
}
},
'615': {
'condition': 'Light Rain and Snow.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/5.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/5.png'
}
},
'616': {
'condition': 'Rain and Snow.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/6.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/6.png'
}
},
'620': {
'condition': 'Light Shower Snow.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/14.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/14.png'
}
},
'621': {
'condition': 'Shower Snow.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/14.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/14.png'
}
},
'622': {
'condition': 'Heavy Shower Snow.',
'css_class': 'snowy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/18.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/18.png'
}
},
'701': {
'condition': 'Mist.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'711': {
'condition': 'Smoke.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'721': {
'condition': 'Haze.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'731': {
'condition': 'Sand, Dust Whirls.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'741': {
'condition': 'Fog.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'751': {
'condition': 'Sand.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'761': {
'condition': 'Dust.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'762': {
'condition': 'Volcanic Ash.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'771': {
'condition': 'Squalls.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'781': {
'condition': 'Tornado.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/01.png'
}
},
'800': {
'condition': 'Clear Sky.',
'css_class': 'clear',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
}
},
'801': {
'condition': 'Few Clouds.',
'css_class': 'clear',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/34.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/33.png'
}
},
'802': {
'condition': 'Scattered Clouds.',
'css_class': 'clear',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/30.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/29.png'
}
},
'803': {
'condition': 'Broken Clouds.',
'css_class': 'clear',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/28.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/27.png'
}
},
'804': {
'condition': 'Overcast Clouds.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'900': {
'condition': 'Tornado.',
'css_class': 'cloudy',
'icons' : {
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
}
},
'901': {
'condition': 'Tropical Storm.',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'css_class': 'cloudy'
},
'902': {
'condition': 'Hurricane.',
'css_class': 'cloudy',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/26.png'
},
'903': {
'condition': 'Cold.',
'css_class': 'cloudy',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'904': {
'condition': 'Hot.',
'css_class': 'clear',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'905': {
'condition': 'Windy.',
'css_class': 'clear',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'906': {
'condition': 'Hail.',
'css_class': 'cloudy',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'951': {
'condition': 'Calm.',
'css_class': 'clear',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'952': {
'condition': 'Light Breeze.',
'css_class': 'clear',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'953': {
'condition': 'Gentle Breeze.',
'css_class': 'clear',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'954': {
'condition': 'Moderate Breeze.',
'css_class': 'clear',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'955': {
'condition': 'Fresh Breeze.',
'css_class': 'clear',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'956': {
'condition': 'Strong Breeze.',
'css_class': 'clear',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'957': {
'condition': 'High Wind, Near Gale.',
'css_class': 'cloudy',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'958': {
'condition': 'Gale.',
'css_class': 'cloudy',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'959': {
'condition': 'Severe Gale.',
'css_class': 'cloudy',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/32.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/31.png'
},
'960': {
'condition': 'Storm.',
'css_class': 'cloudy',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png'
},
'961': {
'condition': 'Violent Storm.',
'css_class': 'cloudy',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png'
},
'962': {
'condition': 'Hurricane.',
'css_class': 'cloudy',
'day' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png',
'night' : 'http://www.michealhallphotography.com/mystuff/fcc/weatherapp/images/icons/12.png'
}
},
'gallery_cities': {
"left": [
{
"_id": 5368361,
"name": "Los Angeles",
"images": {
"day": 'https://www.dropbox.com/s/6ozv286lh0ri4bz/losangeles-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/0krb9opwcna7bnu/losangeles-night.jpg?dl=1'
},
"country": "US",
"coord": {
"lon": -118.243683,
"lat": 34.052231
}
},
{
"_id": 5128581,
"name": "New York",
"images": {
"day": 'https://www.dropbox.com/s/g1ot02pkeyl6ihq/newyork-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/092i9ppilhaej7z/newyork-night.jpg?dl=1'
},
"country": "US",
"coord": {
"lon": -74.005966,
"lat": 40.714272
}
},
{
"_id": 2643741,
"name": "London",
"images": {
"day": 'https://www.dropbox.com/s/0r0lbqoi5tywm7a/london-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/rgw1ku6pcag261p/london-night.jpg?dl=1'
},
"country": "GB",
"coord": {
"lon": -0.09184,
"lat": 51.512791
}
},
{
"_id": 756135,
"name": "Warsaw",
"images": {
"day": 'https://www.dropbox.com/s/ll5g0slpgleniqy/warsaw-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/8jw0tstuclspfes/warsaw-night.jpg?dl=1'
},
"country": "PL",
"coord": {
"lon": 21.01178,
"lat": 52.229771
}
},
{
"_id": 703448,
"name": "Kiev",
"images": {
"day": 'https://www.dropbox.com/s/823795b15fqgcij/kiev-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/h6een3uv709cu0o/kiev-night.jpg?dl=0'
},
"country": "UA",
"coord": {
"lon": 30.516666,
"lat": 50.433334
}
},
],
"right": [
{
"_id": 524901,
"name": "Moscow",
"images": {
"day": 'https://www.dropbox.com/s/wuptt82lc45x1ct/moscow-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/skuwlbhv3n1350z/moscow-night.jpg?dl=1'
},
"country": "RU",
"coord": {
"lon": 37.615555,
"lat": 55.75222
}
},
{
"_id": 1496153,
"name": "Omsk",
"images": {
"day": 'https://www.dropbox.com/s/sawe9lohmr3rp26/omsk-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/cjmhqahcuv880oo/omsk-night.jpg?dl=1'
},
"country": "RU",
"coord": {
"lon": 73.400002,
"lat": 55
}
},
{
"_id": 1816670,
"name": "Beijing",
"images": {
"day": 'https://www.dropbox.com/s/aac8s0wd2adhjps/beijing-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/x2367kka1551mgu/beijing-night2.jpg?dl=1'
},
"country": "CN",
"coord": {
"lon": 116.397232,
"lat": 39.907501
}
},
{
"_id": 1850147,
"name": "Tokyo",
"images": {
"day": 'https://www.dropbox.com/s/1ofl9ij8gvq9vb0/tokyo-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/mu0xboclmy3d7yq/tokyo-night.jpg?dl=1'
},
"country": "JP",
"coord": {
"lon": 139.691711,
"lat": 35.689499
}
},
{
"_id": 5856195,
"name": "Honolulu",
"images": {
"day": 'https://www.dropbox.com/s/vdd0cmnifog95o2/honolulu-day.jpg?dl=1',
"night": 'https://www.dropbox.com/s/hbjr806gzumyqdk/honolulu-night.jpg?dl=1'
},
"country": "US",
"coord": {
"lon": -157.858337,
"lat": 21.30694
}
}
]
},
'other_queries': {
'alternate_location': 'http://ipinfo.io',
'sunrise': 'https://api.sunrise-sunset.org/json?',
'geocode': 'https://maps.googleapis.com/maps/api/geocode/json?address=',
'locationinfo': 'http://api.geonames.org/findNearbyWikipediaJSON?',
'googlemaps': 'https://www.google.com/maps/place/',
'googletimezone': 'https://maps.googleapis.com/maps/api/timezone/json?'
},
'keys' :{
'weather': '&APPID=5d378b44b8f7ee222ef047c6a8346be5',
'geocode': '&key=AIzaSyDFFp6_TdGTAsKIErvMWihBbTCRaCApw18',
'geonames': '&username=michealhall',
'timezone': '&key=AIzaSyDfde92MVuy_GyuFC9Qf6x4CarZl3CEh9Q'
},
'temp_scale': 'F',
'weather_queries': {
'forecastbycity' : 'https://api.openweathermap.org/data/2.5/forecast?id=',
'forecast_daily' : 'https://api.openweathermap.org/data/2.5/forecast/daily?',
'forecast' : 'https://api.openweathermap.org/data/2.5/forecast?',
'latlong': 'https://api.openweathermap.org/data/2.5/weather?',
'postalcode': 'https://api.openweathermap.org/data/2.5/weather?zip=',
'city': 'https://api.openweathermap.org/data/2.5/weather?q=',
'citygroup': 'https://api.openweathermap.org/data/2.5/group?id='
},
'compass_sectors' : [
"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW", "N"
]
};
/* CONVERTERS */
function convert_degree_to_compass( degree ){
// https://www.campbellsci.com/blog/convert-wind-directions
return config.compass_sectors[Math.round( ( degree % 360 ) / 22.5 )];
}
function convert_k_to_f( kelvin ){
//http://www.metric-conversions.org/temperature/kelvin-to-fahrenheit.htm
return ( ( kelvin - 273.15 ) * 1.8000 + 32.00 ).toFixed( 2 );
}
function convert_k_to_c( kelvin ){
//http://www.metric-conversions.org/temperature/kelvin-to-celsius.htm
return ( kelvin - 273.15 ).toFixed( 2 );
}
/* TIME FUNCTIONS */
function hours_to_milliseconds( hours ){
return hours * 60 * 60000;
}
function min_to_milliseconds( minutes ){
return minutes * 60000;
}
function sec_to_milliseconds( seconds ){
return seconds * 1000;
}
function time_to_milliseconds( time_string ){
const time_array = time_string.split(':');
return hours_to_milliseconds( time_array[ 0 ] ) + min_to_milliseconds( time_array[ 1 ] + sec_to_milliseconds( time_array[ 2 ] ) );
}
function is_same_day( now, then ){
// TAKES TWO DATES,COMPARES YYYY:MM:DD
return ( now.getFullyear() === then.getFullYear() &&
now.getMonth() === then.getMonth() &&
now.getDate() === then.getDate() );
}
function is_it_daylight( now, sunrise, sunset ){
// RETURN A BOOLEAN - IF CURRENT TIME IS WITHIN AN HOUR OF SUNRISE OR SUNSET
const one_hour = time_to_milliseconds( '01:00:00' );
const now_in_m = now.getTime();
const rise_in_m = sunrise.getTime();
const set_in_m = sunset.getTime();
return ( now_in_m > ( rise_in_m - one_hour ) && ( now_in_m < set_in_m + one_hour ));
}
function is_within_time_range( start, end, compare ){
// WITHIN AN ARBITRARY WINDOW OF TIME - EITHER SIDE
return ( start > end - compare && start < end + compare );
}
function get_date_from_forecast_string( str ){
// EXPECTING FORMAT STRING: 2016-10-20 00:00:00
return str.split( ' ' )[ 0 ];
}
function get_day_from_forecast_string( str, asInt ){
// EXPECTING FORMAT STRING: 2016-10-20 00:00:00
return ( asInt ) ?
parseInt( str.split( ' ' )[ 0 ].split( '-' )[ 2 ], 10 ) :
str.split( ' ' )[ 0 ].split( '-' )[ 2 ];
}
function get_days_in_month( month, year ){
// http://stackoverflow.com/questions/1184334/get-number-days-in-a-specified-month-using-javascript
return new Date( year, month, 0 ).getDate();
}
function get_offset_date( date, offset ){
return new Date( date.getTime() + offset );
}
function get_time_from_forecast_string( str ){
// EXPECTING FORMAT STRING: 2016-10-20 00:00:00
return str.split( ' ' )[ 1 ];
}
function get_time_offset( date, rawOffset, dstOffset ){
// CALCULATE DATE OFFSET IN MILLISECONDS AND RETURN NEW DATE
const our_offset = date.getTimezoneOffset() * 60000;
const their_offset = ( rawOffset + dstOffset ) * 1000;
return our_offset + their_offset;
}
/* QUERIES */
function do_alternate_location_query( callback ){
$.getJSON( config.other_queries.alternate_location, ( data ) => {
const coords_array = data.loc.split( ',' );
(typeof callback === 'function') &&
callback({
'coords': {
'latitude' : coords_array[0],
'longitude': coords_array[1]
}
});
});
}
function do_geocode_lookup( location, callback ){
$.ajax({
'url': config.other_queries.geocode + location + config.keys.geocode,
'type': 'GET',
'success': (data, status, xhr) => {
if ( !data || !data.results )
return;
const location = data.results[ 0 ].geometry.location;
const coords = { 'coords': { 'latitude': location.lat, 'longitude': location.lng } };
(typeof callback === 'function') &&
callback( coords );
}
});
}
function do_location_query( callback ) {
// THIS DOESN'T WORK IN CHROME OVER HTTP ANY MORE, SO I'M USING A FALLBACK
// HOWEVER THE FALL BACK DOES WORK IN FF! SO I TRY THE FF VERSION, IF IT
// FAILS I FALLBACK TO THE ALTERNATE VERSION THAT WORKS IN CHROME
if ( !config.do_location_query )
return;
if ( !navigator.geolocation )
return do_alternate_location_query( callback );
return navigator.geolocation.getCurrentPosition( callback, ( err ) => {
do_alternate_location_query( callback );
return;
});
}
function do_sunrise_query( position, callback ){
$.ajax({
'url': config.other_queries.sunrise + position + '&date=today&formatted=0',
'type': 'GET',
'success': ( data, status, xhr ) => {
(typeof callback === 'function') &&
callback( data );
}
});
}
function do_timezone_query( location, callback ){
// GOOGLE'S TIMEZONE API WANTS A LOCATION AND A TIMESTAMP
// TIMESTAMP IN SECONDS.
return $.ajax({
'url': config.other_queries.googletimezone + 'location=' + location.coords.latitude + ',' + location.coords.longitude + '×tamp=' + ( now.getTime() / 1000 ) + config.keys.timezone,
'type': 'GET'
});
}
function do_weather_query(options) {
$.ajax({
'url': config.weather_queries[options.query_type] + options.parameters + config.keys.weather,
'type': 'GET',
'success': (data, status, xhr) => {
(typeof options.callback === 'function') &&
options.callback(data);
}
});
}
function get_sunrise_and_load( location ){
const sunrise_pos = 'lat=' + location.coords.latitude + '&lng=' + location.coords.longitude;
do_sunrise_query( sunrise_pos, ( sunrise_data ) => {
sunrise_data.sunrise = new Date( sunrise_data.results.sunrise );
sunrise_data.sunset = new Date( sunrise_data.results.sunset );
get_weather_and_forecast( location, sunrise_data );
});
}
function get_weather_and_forecast( location, sunrise_data, is_daylight ){
const $body = $( 'body' );
const lat_long = 'lat=' + location.coords.latitude + '&lon=' + location.coords.longitude;
// LOAD CURRENT WEATHER
do_weather_query({
'query_type': 'latlong',
'parameters': lat_long,
'callback': ( data ) => {
data.sunrise_data = sunrise_data;
cache_weather_data( data );
do_timezone_query( location )
.then( ( data ) => {
if ( !data )
return;
ui_update_for_timezone( location, data );
});
ui_insert_current_conditions( $body, config.current_conditions, is_daylight );
}
});
// LOAD FORECAST WEATHER
do_weather_query({
'query_type': 'forecast',
'parameters': lat_long,
'callback': ( data ) => {
cache_forecast_data( data );
ui_insert_forecasts( $( 'div.forecast' ), config.templates.forecast_item.clone(), data.list );
}
});
}
/* CACHE DATA */
function cache_forecast_data( data ){
config.forecast_conditions = data;
}
function cache_weather_data(data) {
config.current_conditions = data;
}
/* EVENT HANDLERS */
const handle_clicks = (() => {
now = new Date();
const $location_input = $( 'input.location' );
const $temperature_container = $( '.info.temperature' );
const click_handlers = {
'display_map' : ( e, $clicked ) => {
const options = config.current_conditions.name + '/@' + config.current_conditions.coord.lon + ',' + config.current_conditions.coord.lat;
window.open( config.other_queries.googlemaps + options, 'location');
},
'load_city' : ( e, $clicked ) => {
const val = $location_input.val();
if ( !val )
return false
ui_remove_forecasts( () => do_geocode_lookup( val.split( ' ' ).join('+'), () => get_sunrise_and_load( now ) ) );
return false;
},
'load_gallery_city' : ( e, $clicked ) => {
const city = $clicked.data( 'city' );
$('input.location').val( city.name );
ui_remove_forecasts( () => get_sunrise_and_load({ 'coords': { 'latitude': city.coord.lat, 'longitude': city.coord.lon }}) );
},
'show_author_info' : ( e, $clicked ) => {
const $author_info = $( '#author_info' );
if ( $author_info.length )
return ui_remove_author_info( $author_info );
ui_show_author_info();
},
'temperature' : ( e, $clicked ) => {
ui_insert_temperature( $temperature_container, config.current_conditions, ( config.temp_scale === 'F' ) ? 'C' : 'F' );
}
};
return function(){
$body
.off( '.weather_app' )
.on( 'click.weather_app', '.info, .gallery_item, button, .show_author_info', ( e ) => {
const $clicked = $( e.currentTarget );
const click_handler = $clicked.data( 'clickhandler' );
if ( !click_handler )
return;
( typeof click_handlers[ click_handler ] === 'function' ) &&
click_handlers[ click_handler ]( e, $clicked );
});
};
})();
function handle_submit( $form ){
$form.on( 'submit', () => {
ui_remove_forecasts( ()=> do_geocode_lookup( $form.find( 'input' ).val().split( ' ' ).join('+'), get_sunrise_and_load ) );
return false;
});
}
function pad_string( length, padding, side, string ){
if ( string.length >= length )
return string;
const pad_array = [];
pad_array.length = ( length - string.length ) + 1;
return ( side === 'left' ) ?
pad_array.join( padding ) + string :
string + pad_array.join( padding );
}
/* UI FUNCTIONS */
function ui_build_city_gallery( $item_container, $item_template, city_list ){
city_list.forEach( ( city ) => {
const $city = $item_template.clone();
$city
.data( 'city', city )
.find( '.city_name' )
.text( city.name )
.end()
.find( 'img' )
.attr( 'src', city.images.day )
.end();
$item_container.append( $city );
});
return $item_container;
}
function ui_build_forecast_box( condition, $item ){
// GIVEN A PASSED CONDITION, FORMAT AND RETURN A CONDITION UI ITEM
const f_conditions = config.weather_conditions[ condition.weather[ 0 ].id ];
const date_string = get_date_from_forecast_string( condition.dt_txt );
$item
.find( '.date' )
.text( date_string )
.end()
.find( '.min_f' )
.text( convert_k_to_f( condition.main.temp_min ) )
.end()
.find( '.max_f' )
.text( convert_k_to_f( condition.main.temp_max ) )
.end()
.find( '.min_c' )
.text( convert_k_to_c( condition.main.temp_min ) )
.end()
.find( '.max_c' )
.text( convert_k_to_c( condition.main.temp_max ) )
.end()
.find( '.conditions' )
.text( f_conditions.condition )
.end()
.find( '.forecast_icon' )
.attr( 'src', f_conditions.icons.day )
.end();
return $item;
}
function ui_insert_city_gallery(){
ui_build_city_gallery( $( 'div.left' ), config.templates.gallery_item.clone(), config.gallery_cities.left );
ui_build_city_gallery( $( 'div.right' ), config.templates.gallery_item.clone(), config.gallery_cities.right );
}
function ui_insert_content(){
// CACHE PAGE INFO TEMPLATE AND REMOVE FROM VISIBLE UI
config.templates.author_info = $( '#author_info' ).clone();
$( '#author_info' ).remove();
ui_insert_city_gallery();
handle_clicks();
handle_submit( $body.find( 'form.find_city' ) );
do_location_query( get_sunrise_and_load );
}
function ui_insert_current_conditions( $body, conditions ){
const weather_condition = config.weather_conditions[ conditions.weather[ 0 ].id ];
const $container = $body.find( 'div.middle' );
const classes_to_add = [];
const icons = weather_condition.icons;
classes_to_add.push( weather_condition.css_class );
$container
.find( 'h1.location_name' )
.text( conditions.name )
.end()
.find( 'h3.current_conditions' )
.text( weather_condition.condition )
.end()
.find( 'div.weather_icon img.day' )
.attr( 'src', ( icons ) ? icons.day : '' )
.end()
.find( 'div.weather_icon img.night' )
.attr( 'src', ( icons ) ? icons.night : '' )
.end();
ui_insert_temperature( $container.find( 'div.info.temperature' ), conditions, 'F' );
ui_insert_wind( $container.find( 'div.info.wind'), conditions );
ui_insert_location_data( $container.find( 'div.info.latlong' ), conditions.coord );
$container.find( '.info' ).removeClass( 'hidden' );
$body
.removeClass( config.condition_classes )
.addClass( classes_to_add.join( ' ' ) );
}
function ui_insert_forecasts( $container, $item_template, conditions ){
// REMOVE EXISTING FORECAST BOXES AND FILL WITH NEW
$container.find( '.forecast_box' ).remove();
if ( !conditions || !conditions.length )
return;
// FILL FORECAST BOXES WITH FOUR DAY FORECAST, NOON
const target_time = config.forecast_time;
let target_day = get_day_from_forecast_string( conditions[ 0 ].dt_txt, true );
const days_in_mo = get_days_in_month( now.getMonth() + 1, now.getFullYear() )
let found = 0;
let target_str = pad_string( 2, '0', 'left', target_day + '' );
const f_limit = Math.min( config.forecast_limit, conditions.length );
let c_counter = 0;
while ( found < f_limit ){
// GET LIST OF FORECAST DAYS MATCHING DATE AND TIME
let day_list = conditions
.filter(( forecast ) => get_day_from_forecast_string( forecast.dt_txt ) === target_str )
.filter(( forecast ) => get_time_from_forecast_string( forecast.dt_txt ) === target_time );
// INSERT FORECAST UI
if ( day_list.length ){
let $forecast_ui = ui_build_forecast_box( day_list[0], $item_template.clone() );
$forecast_ui.addClass( '_' + found );
$container.append( $forecast_ui );
found++;
setTimeout( () => $forecast_ui.removeClass( 'hidden_bottom' ), 5 );
}
target_day++;
c_counter++;
if ( target_day > days_in_mo )
{
target_day = 1;
}
target_str = pad_string( 2, '0', 'left', target_day + '' );;
// MAKE SURE WE DON'T WIND UP IN AN INFINITE LOOP BASED ON WONKY DATA
if ( c_counter > conditions.length )
break;
};
}
function ui_insert_location_data( $container, coord ){
$container
.find( '.lat' )
.text( coord.lat.toFixed( 2 ) )
.end()
.find( '.lng' )
.text( coord.lon.toFixed( 2 ) )
.end();
}
function ui_insert_sunrise_data( $container, sunrise, sunset ){
$container
.find( '.sunrise' )
.text( sunrise )
.end()
.find( '.sunset' )
.text( sunset )
.end();
}
function ui_insert_temperature( $container, conditions, scale ){
let temp;
let scale_abbr;
if ( scale.toLowerCase() === 'f' ){
temp = convert_k_to_f( conditions.main.temp );
scale_abbr = 'F';
}
else
{
temp = convert_k_to_c( conditions.main.temp );
scale_abbr = 'C';
}
config.temp_scale = scale_abbr;
// SET BODY CLASSES TO CONTROL VISIBILITY OF PROPER TEMPS IN FORECAST
$body
.removeClass( config.temperature_classes )
.addClass( 'temp_scale_' + scale_abbr );
$container
.find( 'span.temp' )
.text( temp )
.end()
.find( 'span.scale' )
.text( scale_abbr )
.end();
}
function ui_insert_wind( $container, conditions ){
const wind = conditions.wind || {};
const wind_deg = ( conditions.wind.deg !== undefined ) ? wind.deg : '';
const compass_direction = ( wind.deg ) ? convert_degree_to_compass( wind.deg ) : '';
$container
.find( '.wind_speed' )
.text( wind.speed || '' )
.end()
.find( '.wind_direction' )
.text( ( wind_deg ) ? wind.deg.toFixed(1) : '' )
.end()
.find( '.wind_compass_direction' )
.text( compass_direction )
.end();
}
function ui_remove_author_info( $author_info ){
$author_info
.one( 'transitionend', ( e ) => $author_info.remove() )
.addClass( 'hidden_left');
}
function ui_remove_forecasts( fn_callback ){
const $forecasts = $( '.forecast_box' );
$forecasts
.last()
.on( 'transitionend', () => {
$forecasts.remove();
( typeof fn_callback === 'function' ) &&
fn_callback();
})
.end()
.each( ( f, forecast ) => $( forecast ).addClass( 'hidden_bottom' ) );
}
function ui_show_author_info(){
const $author_info = config.templates.author_info.clone();
$author_info.addClass( 'hidden_left' );
$body.append( $author_info );
setTimeout( () => $author_info.removeClass( 'hidden_left' ), 25 );
$author_info
.one( 'click', ( e ) => {
ui_remove_author_info( $author_info );
});
}
function ui_update_for_timezone( location, data ){
const classes_to_add = [];
// CALCULATE MILLISECOND DATE OFFSET BASED ON LAT/LONG DATA
const offset = get_time_offset( now, data.rawOffset, data.dstOffset );
// CREATE NEW DATE USING CURRENT TIME AND CALCULATED OFFSET
// DO SAME FOR SUNRISE AND SUNSET TIMES
// THIS GIVES US DATES WITH TIMES CORRECT FOR THE LOCATION WE ARE
// INTERESTED IN
const their_date = get_offset_date( now, offset );
const sunrise_data = config.current_conditions.sunrise_data;
const sunrise = get_offset_date( sunrise_data.sunrise, offset );
const sunset = get_offset_date( sunrise_data.sunset, offset );
const is_daylight = is_it_daylight( their_date, sunrise, sunset );
ui_insert_sunrise_data( $time, sunrise.toLocaleString( 'en-us',{ 'timezone': data.timeZoneId }).split( ', ')[1], sunset.toLocaleString( 'en-us',{ 'timezone': data.timeZoneId }).split( ', ')[1] );
const is_dawn = is_within_time_range( their_date.getTime(), sunrise.getTime(), time_to_milliseconds( '01:00:00' ) );
const is_dusk = is_within_time_range( their_date.getTime(), sunset.getTime(), time_to_milliseconds( '01:00:00' ) );
( is_daylight ) ?
classes_to_add.push( 'day' ) :
classes_to_add.push( 'night' );
( is_dawn ) &&
classes_to_add.push( 'dawn' );
( is_dusk ) &&
classes_to_add.push( 'dusk' );
$body.addClass( classes_to_add.join( ' ') );
}
// START!
ui_insert_content();
})();
Also see: Tab Triggers