Skip to content

Instantly share code, notes, and snippets.

@erik-sn
Created July 3, 2016 05:55
Show Gist options
  • Save erik-sn/c854a7e5d86b347f969b57e2e0004aef to your computer and use it in GitHub Desktop.
Save erik-sn/c854a7e5d86b347f969b57e2e0004aef to your computer and use it in GitHub Desktop.
Local Weather
<div id="loader" >Loading...</div>
<div id="page-container">
<div id="temp-toggle">Toggle &deg;C/&deg;F</div>
<div id="sky-container">
<div id="cloud-container"></div>
<div id="precipitation-container"></div>
<div id="sun-moon-container">
</div>
<div id="warning"></div>
<div id="main-container">
<div id="location" ></div>
<div id="main-icon-container"></div>
<div id="weather"></div>
<div id="tempF"></div>
<div id="tempC"></div>
<div id="humidity"></div>
</div>
</div>
<svg id="landscape-curve" viewBox="0 0 700 150" preserveAspectRatio="xMinYMin meet" style="background-color: green">
<defs>
<filter id="filter1" x="0" y="0">
<feOffset result="offOut" in="SourceGraphic" dx="-5" dy="0" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="5" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
<path filter="url(#filter1)" d="M0, 50 C150,200 0,0 700,100 L700,00 L0,0 Z" style="stroke: none;"></path>
</svg>
<div id="landscape-container">
<div class="container-fluid" id="hourly-container">
<div id="hourly-label">Hourly Forecast</div>
<div class="row row-centered">
<div class="col-xs-1 col-centered hour-container"></div>
<div class="col-xs-1 col-centered hour-container"></div>
<div class="col-xs-1 col-centered hour-container"></div>
<div class="col-xs-1 col-centered hour-container"></div>
<div class="col-xs-1 col-centered hour-container"></div>
<div class="col-xs-1 col-centered hour-container"></div>
<div class="col-xs-1 col-centered hour-container"></div>
<div class="col-xs-1 col-centered hour-container"></div>
<div class="col-xs-1 col-centered hour-container"></div>
<div class="col-xs-1 col-centered hour-container"></div>
</div>
</div>
</div>
</div>
var weatherState;
var tempState = 'F';
$('document').ready(function() {
showLoader();
$('#temp-toggle').click(function() {
if (tempState === 'F') {
tempState = 'C';
$('.farenheit').hide();
$('.celsius').show();
} else {
tempState = 'F';
$('.celsius').hide();
$('.farenheit').show();
}
});
$(window).resize(function() {
var width = $(window).width();
if (width > 600) {
// $('#sun-moon-container').fadeIn(1000);
$('.cloud').fadeIn(1000);
addPrecipitation(weatherState);
console.log(weatherState)
setWeather(weatherState);
} else {
$('#sun-moon-container').fadeOut(500);
$('.cloud').fadeOut(500);
$('.drop').fadeOut(500);
}
if (width < 600 && width > 450) {
$('#sky-container').height(200 + (600 - width) / 2 );
$('#landscape-container').css('margin-top', (500 - width) /2 );
}
});
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var weatherUrl = generateWeatherUrl(position);
var locationUrl = generateLocationUrl(position);
getData(weatherUrl, 'jsonp', function(weatherData) {
getData(locationUrl, 'json', function(locationData) {
if (weatherData && locationData) {
hideLoader();
$('#main-icon-container').html('<i class="wi ' + getWeatherIcon(weatherData.currently.icon) + ' main-icon"></i>');
$('#location').html(retrieveLocation(locationData.results));
$('#weather').html(weatherData.currently.summary);
var temperature = weatherData.currently.temperature;
$('#tempC').html('<div class="celsius">Temp: ' + fToC(temperature) + '&deg;C</div>');
$('#tempF').html('<div class="farenheit">Temp: ' + Math.round(temperature) + '&deg;F</div>');
$('#humidity').html('Humidity: ' + Math.round(weatherData.currently.humidity * 100) + '%');
setHourlyData(weatherData.hourly.data);
setWeather(weatherData.currently.icon);
} else {
$('#page-container').hide();
$('#warning').html('Could not load data, please try to refresh the page.');
}
});
});
}, function(error) {
$('#page-container').hide();
$('#warning').html('Geolocation only works over HTTPS, please make sure you are using it!');
});
}
});
function showLoader() {
$('#page-container').hide();
$('#loader').show();
}
function hideLoader() {
$('#loader').hide();
$('#page-container').show();
}
function generateWeatherUrl(position) {
var weatherUrl = 'https://api.forecast.io/forecast/5a271ab011ef2106cf601442dc3a7694/'
return weatherUrl + position.coords.latitude + ',' + position.coords.longitude + '/';
}
function generateLocationUrl(position) {
var base = 'https://maps.googleapis.com/maps/api/geocode/json?latlng='
return base + position.coords.latitude + ',' + position.coords.longitude;
}
function getData(url, dataType, returnData) {
$.ajax({
url: url,
type: 'GET',
dataType: dataType,
success: function(data) {
returnData(data)
},
error: function() {
returnData(undefined);
}
});
}
/**
Sift through geolocation data, find only locations that have a single
'political' address and return the formatted address.
**/
function retrieveLocation(data) {
if (data.length === 0) {
return '';
}
var matches = data.filter(function(result) {
if (result.types.length === 1 && result.types[0] === 'political') {
return true;
}
});
return matches[0].formatted_address;
}
function setHourlyData(hourly) {
var hours = hourly.slice(0, 10);
for (var i = 0; i < hours.length; i++) {
var time = '<div class="hourly-time">' + unixToTimestamp(hours[i].time) + '</div>';
weatherState = hours[i].icon;
var icon = '<i class="hourly-icon wi ' + getWeatherIcon(hours[i].icon) + '" />';
var summary = '<div>' + hours[i].summary + '</div>';
var tempF = '<div class="farenheit">' + Math.round(hours[i].temperature) + '&deg;F</div>';
var tempC = '<div class="celsius">' + fToC(hours[i].temperature) + '&deg;C</div>';
var humidity = '<div>' + Math.round(100 * hours[i].humidity) + '%</div>';
$('.hour-container:nth-child(' + (i + 1) + ')').html(time + icon + summary + tempF + tempC + humidity);
}
}
function unixToTimestamp(unix) {
var date = new Date(unix * 1000);
var hours = date.getHours();
var minutes = "0" + date.getMinutes();
return hours + ':' + minutes.substr(-2);
}
function fToC(temp) {
return Math.round((temp - 32) * (5 / 9));
}
function setWeather(icon) {
var hour = new Date().getHours();
if (hour < 7 || hour > 19) {
showNight();
} else {
showDay();
}
weatherState = icon;
addPrecipitation(icon);
switch(icon) {
case 'clear-day':
$('#sun-moon-container').fadeIn(500);
break;
case 'clear-night':
$('#sun-moon-container').fadeIn(500);
break;
case 'rain':
addClouds(10, 9);
setCloudColor('#999')
$('#sun-moon-container').hide();
break;
case 'snow':
addClouds(10, 9);
setCloudColor('#999')
$('#sun-moon-container').hide();
break;
case 'sleet':
addClouds(10, 9);
setCloudColor('#999')
$('#sun-moon-container').hide();
break;
case 'cloudy':
addClouds(10, 9);
setCloudColor('#FFF');
break;
case 'partly-cloudy-day':
addClouds(3, 30);
setCloudColor('#FFF');
$('#sun-moon-container').fadeIn(500);
break;
case 'partly-cloudy-night':
addClouds(3, 30);
setCloudColor('#555')
$('#sun-moon-container').hide();
break;
default:
$('#sun-moon-container').hide();
break;
}
}
function getWeatherIcon(icon) {
switch(icon) {
case 'clear-day':
return 'wi-day-sunny';
case 'clear-night':
return 'wi-night-clear';
case 'rain':
return 'wi-rain';
case 'snow':
return 'wi-snow';
case 'sleet':
return 'wi-sleet';
case 'wind':
return 'wi-windy';
case 'cloudy':
return 'wi-cloudy';
case 'fog':
return 'wi-fog';
case 'partly-cloudy-day':
return 'wi-day-cloudy';
case 'partly-cloudy-night':
return 'wi-night-alt-cloudy';
default:
return '';
}
}
function showDay() {
$('body').css('color', '#333')
$('body').css('background-color', 'green')
$('#sun-moon-container').html('<img src="https://res.cloudinary.com/dvr87tqip/image/upload/v1466806859/sun.svg" height=300px />')
$('#sun-moon-container').css('right', '-100px')
$('#sun-moon-container').css('top', '-100px')
$('#sky-container').css('background', '#c9dbe9')
$('#sky-container').css('background', '-webkit-linear-gradient(top, #c9dbe9 20%, #fff 100%)')
$('#sky-container').css('background', '-linear-gradient(top, #c9dbe9 20%, #fff 100%)')
$('#sky-container').css('background', '-moz-linear-gradient(top, #c9dbe9 20%, #fff 100%)')
$('#landscape-curve > path').css('fill', '#fff')
$('#page-container').css('background-color', 'green')
$('#landscape-container').css('background-color', 'green')
$('#landscape-curve').css('background-color', 'green')
}
function showNight() {
$('.cloud').css('color', '#888');
$('body').css('color', '#FEFEFA')
$('body').css('background-color', '#2F4F4F')
$('#sun-moon-container').html('<img src="https://res.cloudinary.com/dvr87tqip/image/upload/v1466773790/moon_ck199s.svg" height=300px />');
$('#sun-moon-container').css('right', '-100px');
$('#sun-moon-container').css('top', '-100px') ;
$('#sky-container').css('background-color', '#0D0D2A');
$('#landscape-curve > path').css('fill', '#0D0D2A');
$('#page-container').css('background-color', '#2F4F4F');
$('#landscape-container').css('background-color', '#2F4F4F');
$('#landscape-curve').css('background-color', '#2F4F4F');
}
function addPrecipitation(icon) {
switch(icon) {
case 'rain':
createRain(200);
break;
case 'snow':
createRain(100);
break;
case 'sleet':
createRain(100);
break;
default:
$('.drop').remove();
break;
}
}
function addClouds(count, spacing) {
$('.cloud').remove();
for (var i = 0; i < count; i++) {
var id = 'cloud-' + i;
var cloud = '<div id="' + id + '" class="cloud" ></div>'
$('#cloud-container').append(cloud);
var num = Math.floor(Math.random() * 10) + 1;
num *= Math.floor(Math.random() * 2) == 1 ? 1 : -1;
$('#' + id).css('right', i * spacing + (num / 5) + '%');
$('#' + id).css('top', 2 * num);
test = 5;
}
}
function setCloudColor(color) {
$('.cloud').css('background', color);
$('.cloud').append('<style>.cloud:after{background: ' + color + ';}</style>');
$('.cloud').append('<style>.cloud:before{background: ' + color + ';}</style>');
}
// function to generate a random number range.
function randRange( minNum, maxNum) {
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
// function to generate drops
// rain inspired by https://codepen.io/alemesre/pen/hAxGg
function createRain(drops) {
$('.drop').remove();
var width = $('body').width();
var height = $('#sky-container').height() + 100;
for( i = 1; i <= drops; i++) {
var dropLeft = randRange(0, width);
var dropTop = randRange(0, height);
$('#precipitation-container').append('<div class="drop" id="drop'+i+'"></div>');
$('#drop'+i).css('left',dropLeft);
$('#drop'+i).css('top',dropTop);
}
}
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
#page-container {
display: none;
}
#location {
font-size: 25px;
text-align: center;
}
#loader {
width: 100%;
text-align: center;
margin-top: 20%;
font-size: 40px;
}
#warning {
color: red;
font-size: 28px;
text-align: center;
}
#main-container {
z-index: 2;
position: absolute;
width: 100%;
font-size: 24px;
text-align: center;
}
.main-icon {
margin-top: 5px;
height: 25px;
zoom: 2.5;
-moz-transform: scale(2.5);
-webkit-transition: -webkit-transform .8s ease-in-out;
transition: transform .8s ease-in-out;
}
.main-icon:hover {
-webkit-transform: rotate(30deg);
transform: rotate(30deg);
}
#temp-toggle {
z-index: 3;
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Chrome/Safari/Opera */
-khtml-user-select: none; /* Konqueror */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
-webkit-box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75);
-moz-box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75);
box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75);
padding-top: 2px;
color: #333333;
text-align: center;
font-size: 20px;
font-weight: bold;
border: 4px solid #333333;
position: absolute;
margin: 10px 0px 0px 10px;
height: 40px;
width: 135px;
border-radius: 2px;
transition: background-color 1.5s;
transition: color 1s;
}
#temp-toggle:hover {
background-color: #333333;
color: white;
transition: background-color 1s;
transition: color 0.75s;
}
.celsius {
display: none;
}
#hourly-label {
font-size: 24px;
width: 100%;
text-align: center;
margin-bottom: 5px;
}
.hour-container {
text-align: center;
width: 150px;
}
.hourly-time {
margin-top: 4px;
font-weight: bold;
font-size: 18px;
}
.hourly-icon {
margin: 5px 0px 5px 0px;
zoom: 2.5;
-moz-transform: scale(2.5);
-webkit-transition: -webkit-transform .8s ease-in-out;
transition: transform .8s ease-in-out;
}
.hourly-icon:hover {
-webkit-transform: rotate(30deg);
transform: rotate(30deg);
}
.row-centered {
text-align:center;
}
.col-centered {
display:inline-block;
float:none;
margin-right:-4px;
}
/** Weather Visualization **/
body {
height: 100vh;
}
#sun-moon-container {
z-index: 0;
position: fixed;
}
#preciptiation-container {
z-index: 1;
position: absolute;
height: 400px;
width: 100%;
}
/**
Rain inspired by https://codepen.io/alemesre/pen/hAxGg
*/
.drop {
background: -webkit-gradient(linear,0% 0%,0% 100%, from(rgba(13,52,58,1) ), to(rgba(255,255,255,0.6)) );
background: -moz-linear-gradient(top, rgba(13,52,58,1) 0%, rgba(255,255,255,.6) 100%);
width:1px;
height:20px;
position: absolute;
bottom:200px;
-webkit-animation: fall .85s ease-out infinite;
-moz-animation: fall .85s ease-out infinite;
}
#cloud-container {
z-index: 1;
position: fixed;
}
.cloud {
width: 200px;
height: 60px;
background: #fff;
border-radius: 200px;
-moz-border-radius: 200px;
-webkit-border-radius: 200px;
position: fixed;
}
.cloud:before, .cloud:after {
content: '';
position: absolute;
background: #fff;
width: 100px; height: 80px;
position: absolute; top: -15px; left: 10px;
border-radius: 100px;
-moz-border-radius: 100px;
-webkit-border-radius: 100px;
-webkit-transform: rotate(30deg);
transform: rotate(30deg);
-moz-transform: rotate(30deg);
}
.cloud:after {
width: 120px; height: 120px;
top: -55px; left: auto; right: 15px;
}
#sky-container {
min-height: 185px;
padding-top: 50px;
}
#landscape-container {
margin-top: -50px;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/css/weather-icons-wind.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/css/weather-icons.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment