Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save diego-roberto/c282a96d67c3258873c4fd3adf8dd916 to your computer and use it in GitHub Desktop.
Save diego-roberto/c282a96d67c3258873c4fd3adf8dd916 to your computer and use it in GitHub Desktop.
Animated Weather Cards (Enhanced w/Yahoo Weather)

Animated Weather Cards (Enhanced w/Yahoo Weather)

I just forked this pen from @steveg3003's Animated Weather Cards. I thought it would be neat to try and tie this to real weather data and turn it into a date picker. Should be fun to work on!

A Pen by Kenneth Moore on CodePen.

License.

<div class="background">
<div class="container">
<svg id="back">
<radialGradient id="SVGID_1_" cx="0" cy="0" r="320.8304" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFDE17;stop-opacity:0.7"/>
<stop offset="1" style="stop-color:#FFF200;stop-opacity:0"/>
</radialGradient>
<path id="sunburst" style="fill:url(#SVGID_1_); opacity: 0;" d="M0,319.7c-18.6,0-37.3-1.6-55.5-4.8L-7.8,41.4c5.1,0.9,10.6,0.9,15.7,0L56,314.8C37.6,318,18.8,319.7,0,319.7z
M-160.8,276.6c-32.5-18.8-61.3-42.9-85.5-71.6L-34,26.2c3.4,4.1,7.4,7.4,12,10.1L-160.8,276.6z M161.3,276.4L22.1,36.2
c4.5-2.6,8.6-6,12-10.1l212.6,178.5C222.5,233.4,193.8,257.6,161.3,276.4z M-302.5,108.3C-315.4,73-321.9,36-322-1.8l277.6-0.5
c0,5.3,0.9,10.4,2.7,15.2L-302.5,108.3z M302.6,107.8L41.8,12.8c1.7-4.7,2.6-9.7,2.6-14.9c0-0.3,0-0.6,0-1H322l0-1.3l0,1.9
C322,35.4,315.5,72.5,302.6,107.8z M-41.8-17.5l-261-94.5c12.8-35.4,31.6-68,55.8-96.9L-34.1-30.8C-37.5-26.8-40.1-22.3-41.8-17.5z
M41.7-17.7c-1.8-4.8-4.4-9.3-7.8-13.3l212-179.2c24.3,28.8,43.3,61.3,56.3,96.6L41.7-17.7z M-22.2-40.8l-139.6-240
c32.7-19,68.1-32,105.2-38.6L-8-46.1C-13-45.2-17.8-43.4-22.2-40.8z M22-40.9c-4.4-2.6-9.2-4.3-14.2-5.1l47.1-273.6
c37.2,6.4,72.7,19.2,105.4,38L22-40.9z"/>
</svg>
<div class="card-container">
<nav class="test-nav">
<ul>
<!-- ko foreach: weatherMap -->
<li>
<a data-bind="click: function(data, event){ $parent.changeWeather(data, event)}">
<i class="wi" data-bind="css: icon, attr: {title: name}"></i>
</a>
</li>
<!-- /ko -->
</ul>
</nav>
<div id="card" class="weather">
<svg id="inner">
<defs>
<path id="leaf" d="M41.9,56.3l0.1-2.5c0,0,4.6-1.2,5.6-2.2c1-1,3.6-13,12-15.6c9.7-3.1,19.9-2,26.1-2.1c2.7,0-10,23.9-20.5,25 c-7.5,0.8-17.2-5.1-17.2-5.1L41.9,56.3z"/>
</defs>
<circle id="sun" cx="0" cy="0" r="50" style="transform: matrix(1, 0, 0, 1, 150, -100);"/>
<g id="layer3"></g>
<g id="cloud3" class="cloud"></g>
<g id="fog3" class="fog"></g>
<g id="layer2"></g>
<g id="fog2" class="fog"></g>
<g id="cloud2" class="cloud"></g>
<g id="layer1"></g>
<g id="cloud1" class="cloud"></g>
<g id="fog1" class="fog"></g>
</svg>
<div class="details">
<div class="temp"><span id="temperature">20</span><span class="super" id="format">c</span></div>
<div class="right">
<div id="date">Monday 22 August</div>
<div id="summary"></div>
</div>
</div>
</div>
</div>
<svg id="outer"></svg>
</div>
</div>
// 📝 Fetch all DOM nodes in jQuery and Snap SVG
var container = $('.container');
var card = $('#card');
var innerSVG = Snap('#inner');
var outerSVG = Snap('#outer');
var backSVG = Snap('#back');
var summary = $('#summary');
var date = $('#date');
var temp = $('#temperature');
var tempFormat = $('#format');
var weatherContainer1 = Snap.select('#layer1');
var weatherContainer2 = Snap.select('#layer2');
var weatherContainer3 = Snap.select('#layer3');
var innerRainHolder1 = weatherContainer1.group();
var innerRainHolder2 = weatherContainer2.group();
var innerRainHolder3 = weatherContainer3.group();
var innerLeafHolder = weatherContainer1.group();
var innerSnowHolder = weatherContainer1.group();
var innerHailHolder = weatherContainer2.group();
//var innerCloudHolder = weatherContainer1.group();
var innerLightningHolder = weatherContainer1.group();
var leafMask = outerSVG.rect();
var leaf = Snap.select('#leaf');
var sun = Snap.select('#sun');
var sunburst = Snap.select('#sunburst');
var outerSplashHolder = outerSVG.group();
var outerLeafHolder = outerSVG.group();
var outerSnowHolder = outerSVG.group();
var outerHailHolder = weatherContainer3.group();
var cloudsChanged= false;
var lightningTimeout;
// Set mask for leaf holder
outerLeafHolder.attr({
'clip-path': leafMask
});
// create sizes object, we update this later
var sizes = {
container: {width: 0, height: 0},
card: {width: 0, height: 0}
}
// grab cloud groups
var clouds = [
{group: Snap.select('#cloud1')},
{group: Snap.select('#cloud2')},
{group: Snap.select('#cloud3')}
]
var fog = [
{group: Snap.select('#fog1')},
{group: Snap.select('#fog2')},
{group: Snap.select('#fog3')}
]
var classes = ['night', 'day', 'hot', 'cold']
// set weather types ☁️ 🌬 🌧 ⛈ ☀️
var weather = [
{ type: 'snow', class: '', intensity: 1, name: 'Snow'},
{ type: 'mix', class: '', intensity: 1, name: 'Winter Mix'},
{ type: 'mix-rain-sleet', class: '', intensity: 1, name: 'Winter Mix'},
{ type: 'mix-rain-snow', class: '', intensity: 1, name: 'Winter Mix'},
{ type: 'mix-snow-sleet', class: '', intensity: 1, name: 'Winter Mix'},
{ type: 'sleet', class: '', intensity: 1, name: 'Sleet'},
{ type: 'wind', class: '', intensity: 1, name: 'Windy'},
{ type: 'rain', class: '', intensity: 1, name: 'Rain'},
{ type: 'hail', class: '', intensity: 2, name: 'Hail Storm'},
{ type: 'thunder', class: '', intensity: 1, name: 'Storms'},
{ type: 'severe', class: '', intensity: 2, name: 'T Storms'},
{ type: 'cloud', class: '', intensity: 1, name: 'Cloudy'},
{ type: 'sun', class: '', intensity: 1, name: 'Sunny'},
{ type: 'haze', class: '', intensity: 1, name: 'Foggy'},
{ type: 'smoke', class: '', intensity: 1, name: 'Smoke'}
];
var weatherMap = {
0: { type: 'severe', class: '', intensity: 5, icon: 'wi-tornado', name: 'Tornado'},
1: { type: 'severe', class: '', intensity: 2.5, icon: 'wi-thunderstorm', name: 'Tropical Storm'}, //tropical storm
2: { type: 'severe', class: '', intensity: 5, icon: 'wi-hurricane', name: 'Hurricane'}, //hurricane
3: { type: 'severe', class: '', intensity: 1.25, icon: 'wi-thunderstorm', name: 'Severe Thunderstorms'}, //severe thunderstorms
4: { type: 'thunder', class: '', intensity: 1, icon: 'wi-thunderstorm', name: 'Thunderstorms'}, //thunderstorms
5: { type: 'mix-rain-snow', class: 'cold', intensity: 1, icon: 'wi-rain-mix', name: 'Mixed Rain and Snow'}, //mixed rain and snow
6: { type: 'mix-rain-sleet', class: 'cold', intensity: 1, icon: 'wi-sleet', name: 'Mixed Rain and Sleet'}, //mixed rain and sleet
7: { type: 'mix-snow-sleet', class: 'cold', intensity: 1, icon: 'wi-sleet', name: 'Mixed Snow and Sleet'}, //mixed snow and sleet
8: { type: 'rain', class: 'cold', intensity: .5, icon: 'wi-rain-mix', name: 'Freezing Drizzle'}, //freezing drizzle
9: { type: 'rain', class: '', intensity: .5, icon: 'wi-sprinkle', name: 'Drizzle'}, //drizzle
10: { type: 'rain', class: 'cold', intensity: 1, icon: 'wi-rain-mix', name: 'Freezing Rain'}, //freezing rain
11: { type: 'rain', class: '', intensity: 1, icon: 'wi-rain', name: 'Showers'}, //showers
12: { type: 'rain', class: '', intensity: 1, icon: 'wi-rain', name: 'Showers'}, //showers
13: { type: 'snow', class: 'cold', intensity: .5, icon: 'wi-snow', name: 'Snow Flurries'}, //snow flurries
14: { type: 'snow', class: 'cold', intensity: .75, icon: 'wi-snow', name: 'Light Snow Showers'}, //light snow showers
15: { type: 'snow', class: 'cold', intensity: .5, icon: 'wi-snow', name: 'Blowing Snow'}, //blowing snow
16: { type: 'snow', class: 'cold', intensity: 1, icon: 'wi-snow', name: 'Snow'}, //snow
17: { type: 'hail', class: '', intensity: 1.5, icon: 'wi-hail', name: 'Hail'}, //hail
18: { type: 'sleet', class: 'cold', intensity: 1, icon: 'wi-sleet', name: 'Sleet'}, //sleet
19: { type: 'haze', class: 'hot', intensity: .5, icon: 'wi-sandstorm', name: 'Dust'}, //dust
20: { type: 'haze', class: '', intensity: .5, icon: 'wi-fog', name: 'Foggy'}, //foggy
21: { type: 'haze', class: '', intensity: .5, icon: 'wi-fog', name: 'Haze'}, //haze
22: { type: 'smoke', class: '', intensity: .5, icon: 'wi-smoke', name: 'Smokey'}, //smoky
23: { type: 'wind', class: '', intensity: 3, icon: 'wi-cloudy-gusts', name: 'Blustery'}, //blustery
24: { type: 'wind', class: '', intensity: 1, icon: 'wi-strong-wind', name: 'Windy'}, //windy
25: { type: 'sun', class: 'cold', intensity: 1, icon: 'wi-snowflake-cold', name: 'Cold'}, //cold
26: { type: 'cloud', class: '', intensity: 1, icon: 'wi-cloudy', name: 'Cloudy'}, //cloudy
27: { type: 'cloud', class: 'night', intensity: .3, icon: 'wi-night-cloudy', name: 'Mosty Cloudy'}, //mostly cloudy (night)
28: { type: 'cloud', class: '', intensity: .3, icon: 'wi-day-cloudy', name: 'Mosty Cloudy'}, //mostly cloudy (day)
29: { type: 'cloud', class: 'night', intensity: .1, icon: 'wi-night-cloudy', name: 'Partly Cloudy'}, //partly cloudy (night)
30: { type: 'cloud', class: '', intensity: .1, icon: 'wi-day-cloudy', name: 'Partly Cloudy'}, //partly cloudy (day)
31: { type: 'sun', class: 'night', intensity: 1, icon: 'wi-night-clear', name: 'Clear'}, //clear (night)
32: { type: 'sun', class: '', intensity: 1, icon: 'wi-day-sunny', name: 'Sunny'}, //sunny
33: { type: 'sun', class: 'night', intensity: 1, icon: 'wi-night-clear', name: 'Fair'}, //fair (night)
34: { type: 'sun', class: '', intensity: 1, icon: 'wi-day-sunny', name: 'Fair'}, //fair (day)
35: { type: 'hail', class: '', intensity: 1, icon: 'wi-hail', name: 'Mixed Rain and Hail'}, //mixed rain and hail
36: { type: 'sun', class: 'hot', intensity: 1, icon: 'wi-day-sunny', name: 'Hot'}, //hot
37: { type: 'thunder', class: '', intensity: .25, icon: 'wi-storm-showers', name: 'Isolated Thunderstorms'}, //isolated thunderstorms
38: { type: 'thunder', class: '', intensity: .5, icon: 'wi-storm-showers', name: 'Scattered Thunderstorms'}, //scattered thunderstorms
39: { type: 'thunder', class: '', intensity: .5, icon: 'wi-storm-showers', name: 'Scattered Thunderstorms'}, //scattered thunderstorms
40: { type: 'rain', class: '', intensity: .75, icon: 'wi-showers', name: 'Scattered Showers'}, //scattered showers
41: { type: 'snow', class: 'cold', intensity: 1.75, icon: 'wi-snow', name: 'Heavy Snow'}, //heavy snow
42: { type: 'snow', class: 'cold', intensity: .5, icon: 'wi-snow', name: 'Scattered Snow Showers'}, //scattered snow showers
43: { type: 'snow', class: 'cold', intensity: 1.75, icon: 'wi-snow', name: 'Heavy Snow'}, //heavy snow
44: { type: 'cloud', class: '', intensity: .1, icon: 'wi-day-cloudy', name: 'Partly Cloudy'}, //partly cloudy
45: { type: 'thunder', class: '', intensity: .5, icon: 'wi-storm-showers', name: 'Thundershowers'}, //thundershowers
46: { type: 'snow', class: 'cold', intensity: .75, icon: 'wi-snow', name: 'Snow Showers'}, //snow showers
47: { type: 'thunder', class: '', intensity: .25, icon: 'wi-storm-showers', name: 'Isolated Thunderstorms'} //isolated thundershowers
};
// 🛠 app settings
// in an object so the values can be animated in tweenmax
var settings = {
windSpeed: 2,
rainCount: 0,
hailCount: 0,
leafCount: 0,
snowCount: 0,
fogCount: 0,
cloudHeight: 100,
cloudSpace: 30,
cloudArch: 50,
renewCheck: 10,
splashBounce: 80
};
var tickCount = 0;
var rain = [];
var leafs = [];
var snow = [];
var hail = [];
// ⚙ initialize app
init();
// 👁 watch for window resize
$(window).resize(onResize);
// 🏃 start animations
requestAnimationFrame(tick);
function init()
{
onResize();
updateDateText();
// 🖱 bind weather menu buttons
// ☁️ draw clouds
for(var i = 0; i < clouds.length; i++)
{
clouds[i].offset = Math.random() * sizes.card.width;
drawCloud(clouds[i], i);
}
for(var i = 0; i < fog.length; i++)
{
fog[i].offset = Math.random() * sizes.card.width;
drawFog(fog[i], i);
}
// ☀️ set initial sun attr
TweenMax.set(sun.node, {x: sizes.card.width / 2, y: -100});
TweenMax.set(sunburst.node, {opacity: 0});
changeWeather(weather[12]);
}
function onResize()
{
// 📏 grab window and card sizes
sizes.container.width = container.width();
sizes.container.height = container.height();
sizes.card.width = card.width();
sizes.card.height = card.height();
sizes.card.offset = card.offset();
// 📐 update svg sizes
innerSVG.attr({
width: sizes.card.width,
height: sizes.card.height
})
outerSVG.attr({
width: sizes.container.width,
height: sizes.container.height
})
backSVG.attr({
width: sizes.container.width,
height: sizes.container.height
})
TweenMax.set(sunburst.node, {transformOrigin:"50% 50%", x: (sizes.card.width/2) + sizes.card.offset.left, y: (sizes.card.height/2) + sizes.card.offset.top});
TweenMax.fromTo(sunburst.node, 20, {rotation: 0}, {rotation: 360, repeat: -1, ease: Power0.easeInOut})
// 🍃 The leaf mask is for the leafs that float out of the
// container, it is full window height and starts on the left
// inline with the card
leafMask.attr({x: sizes.card.offset.left, y: 0, width: sizes.container.width - sizes.card.offset.left, height: sizes.container.height});
}
function drawCloud(cloud, i)
{
/*
☁️ We want to create a shape thats loopable but that can also
be animated in and out. So we use Snap SVG to draw a shape
with 4 sections. The 2 ends and 2 arches the same width as
the card. So the final shape is about 4 x the width of the
card.
*/
var space = settings.cloudSpace * i;
var height = space + settings.cloudHeight;
var arch = height + settings.cloudArch + (Math.random() * settings.cloudArch);
var width = sizes.card.width;
var points = [];
points.push('M' + [-(width), 0].join(','));
points.push([width, 0].join(','));
points.push('Q' + [width * 2, height / 2].join(','));
points.push([width, height].join(','));
points.push('Q' + [width * 0.5, arch].join(','));
points.push([0, height].join(','));
points.push('Q' + [width * -0.5, arch].join(','));
points.push([-width, height].join(','));
points.push('Q' + [- (width * 2), height/2].join(','));
points.push([-(width), 0].join(','));
var path = points.join(' ');
if(!cloud.path) cloud.path = cloud.group.path();
cloud.path.animate({
d: path
}, 0)
}
function drawFog(cloud, i)
{
/*
☁️ We want to create a shape thats loopable but that can also
be animated in and out. So we use Snap SVG to draw a shape
with 4 sections. The 2 ends and 2 arches the same width as
the card. So the final shape is about 4 x the width of the
card.
*/
var space = settings.cloudSpace * i;
var height = space + settings.cloudHeight;
var arch = height + settings.cloudArch + (Math.random() * settings.cloudArch);
var width = sizes.card.width;
var bottom = sizes.card.height;
var top = (sizes.card.height - height);
var half = (sizes.card.height - (height / 2));
var points = [];
points.push('M' + [-(width), height].join(','));
points.push([width, height].join(','));
points.push('Q' + [width * 2, height / 2].join(','));
points.push([width, 0].join(','));
points.push('Q' + [width * 0.5, -arch + height].join(','));
points.push([0, 0].join(','));
points.push('Q' + [width * -0.5, -arch + height].join(','));
points.push([-width, 0].join(','));
points.push('Q' + [- (width * 2), height/2].join(','));
points.push([-(width), height].join(','));
var path = points.join(' ');
if(!cloud.path) cloud.path = cloud.group.path();
cloud.path.animate({
d: path
}, 0)
}
function makeRain()
{
// 💧 This is where we draw one drop of rain
// first we set the line width of the line, we use this
// to dictate which svg group it'll be added to and
// whether it'll generate a splash
var lineWidth = Math.random() * 3;
// ⛈ line length is made longer for stormy weather
var lineLength = (currentWeather.type == 'thunder' || currentWeather.type == 'severe' || currentWeather.type == 'hail') ? 35 : 14;
// Start the drop at a random point at the top but leaving
// a 20px margin
var x = Math.random() * (sizes.card.width - 40) + 20;
// Draw the line
var line = this['innerRainHolder' + (3 - Math.floor(lineWidth))].path('M0,0 0,' + lineLength).attr({
fill: 'none',
stroke: (currentWeather.type == 'thunder' || currentWeather.type == 'severe' || currentWeather.type == 'hail') ? '#777' : '#86a3f9',
strokeWidth: lineWidth
});
// add the line to an array to we can keep track of how
// many there are.
rain.push(line);
// Start the falling animation, calls onRainEnd when the
// animation finishes.
var windOffset = settings.windSpeed * 10;
TweenMax.fromTo(line.node, 1, {x: x - windOffset, y: 0- lineLength}, {delay: Math.random(), y: sizes.card.height, x: x, ease: Power2.easeIn, onComplete: onRainEnd, onCompleteParams: [line, lineWidth, x, currentWeather.type]});
}
function onRainEnd(line, width, x, type)
{
// first lets get rid of the drop of rain 💧
line.remove();
line = null;
// We also remove it from the array
for(var i in rain)
{
if(!rain[i].paper) rain.splice(i, 1);
}
// If there is less rain than the rainCount we should
// make more.
if(rain.length < settings.rainCount)
{
makeRain();
// 💦 If the line width was more than 2 we also create a
// splash. This way it looks like the closer (bigger)
// drops hit the the edge of the card
if(width > 2) makeSplash(x, type);
}
}
function makeSplash(x, type)
{
// 💦 The splash is a single line added to the outer svg.
// The splashLength is how long the animated line will be
var splashLength = (type == 'thunder' || type == 'severe' || type == 'hail') ? 30 : 20;
// splashBounce is the max height the line will curve up
// before falling
var splashBounce = (type == 'thunder' || type == 'severe' || type == 'hail') ? 120 : 100;
// this sets how far down the line can fall
var splashDistance = 80;
// because the storm rain is longer we want the animation
// to last slighly longer so the overall speed is roughly
// the same for both
var speed = (type == 'thunder' || type == 'severe' || type == 'hail') ? 0.7 : 0.5;
// Set a random splash up amount based on the max splash bounce
var splashUp = 0 - (Math.random() * splashBounce);
// Sets the end x position, and in turn defines the splash direction
var randomX = ((Math.random() * splashDistance) - (splashDistance / 2));
// Now we put the 3 line coordinates into an array.
var points = [];
points.push('M' + 0 + ',' + 0);
points.push('Q' + randomX + ',' + splashUp);
points.push((randomX * 2) + ',' + splashDistance);
// Draw the line with Snap SVG
var splash = outerSplashHolder.path(points.join(' ')).attr({
fill: "none",
stroke: (type == 'thunder' || type == 'severe' || type == 'hail') ? '#777' : '#86a3f9',
strokeWidth: 1
});
// We animate the dasharray to have the line travel along the path
var pathLength = Snap.path.getTotalLength(splash);
var xOffset = sizes.card.offset.left;//(sizes.container.width - sizes.card.width) / 2
var yOffset = sizes.card.offset.top + sizes.card.height;
splash.node.style.strokeDasharray = splashLength + ' ' + pathLength;
// Start the splash animation, calling onSplashComplete when finished
TweenMax.fromTo(splash.node, speed, {strokeWidth: 2, y: yOffset, x: xOffset + 20 + x, opacity: 1, strokeDashoffset: splashLength}, {strokeWidth: 0, strokeDashoffset: - pathLength, opacity: 1, onComplete: onSplashComplete, onCompleteParams: [splash], ease: SlowMo.ease.config(0.4, 0.1, false)})
}
function onSplashComplete(splash)
{
// 💦 The splash has finished animating, we need to get rid of it
splash.remove();
splash = null;
}
function makeLeaf()
{
var scale = 0.5 + (Math.random() * 0.5);
var newLeaf;
var areaY = sizes.card.height/2;
var y = areaY + (Math.random() * areaY);
var endY = y - ((Math.random() * (areaY * 2)) - areaY)
var x;
var endX;
var colors = ['#76993E', '#4A5E23', '#6D632F'];
var color = colors[Math.floor(Math.random() * colors.length)];
var xBezier;
if(scale > 0.8)
{
newLeaf = leaf.clone().appendTo(outerLeafHolder)
.attr({
fill: color
})
y = y + sizes.card.offset.top / 2;
endY = endY + sizes.card.offset.top / 2;
x = sizes.card.offset.left - 100;
xBezier = x + (sizes.container.width - sizes.card.offset.left) / 2;
endX = sizes.container.width + 50;
}
else
{
newLeaf = leaf.clone().appendTo(innerLeafHolder)
.attr({
fill: color
})
x = -100;
xBezier = sizes.card.width / 2;
endX = sizes.card.width + 50;
}
leafs.push(newLeaf);
var bezier = [{x:x, y:y}, {x: xBezier, y:(Math.random() * endY) + (endY / 3)}, {x: endX, y:endY}]
TweenMax.fromTo(newLeaf.node, 2, {rotation: Math.random()* 180, x: x, y: y, scale:scale}, {rotation: Math.random()* 360, bezier: bezier, onComplete: onLeafEnd, onCompleteParams: [newLeaf], ease: Power0.easeIn})
}
function onLeafEnd(leaf)
{
leaf.remove();
leaf = null;
for(var i in leafs)
{
if(!leafs[i].paper) leafs.splice(i, 1);
}
if(leafs.length < settings.leafCount)
{
makeLeaf();
}
}
function makeHail()
{
var windOffset = settings.windSpeed * 10;
var offset = 0.25 * currentWeather.intensity;
var scale = offset + (Math.random() * offset);
var newHail;
var x;
var endX; // = x - ((Math.random() * (areaX * 2)) - areaX)
var y = -10;
var endY;
var size = 5 * scale;
if(size > 4)
{
x = 20 + (Math.random() * ((sizes.card.width) - 40)) + windOffset;
newHail = outerHailHolder.circle(0, 0, size)
.attr({
fill: (currentWeather.type == 'sleet' || currentWeather.type.indexOf('mix') > -1) ? '#86a3f9' : '#FFF',
})
endY = sizes.container.height + 10;
//y = sizes.card.offset.top + settings.cloudHeight;
x = x + sizes.card.offset.left;
//xBezier = x + (sizes.container.width - sizes.card.offset.left) / 2;
//endX = sizes.container.width + 50;
}
else
{
x = 20 + (Math.random() * ((sizes.card.width + windOffset) - 20));
newHail = innerHailHolder.circle(0, 0 , size)
.attr({
fill: (currentWeather.type == 'sleet' || currentWeather.type.indexOf('mix') > -1) ? '#86a3f9' : '#FFF',
});
endY = sizes.card.height + 10;
//x = -100;
//xBezier = sizes.card.width / 2;
//endX = sizes.card.width + 50;
}
hail.push(newHail);
// Start the falling animation, calls onHailEnd when the
// animation finishes.
TweenMax.fromTo(newHail.node, 1, {x: x - windOffset, y: y}, {delay: Math.random(), y: endY, x: x, ease: Power2.easeIn, onComplete: onHailEnd, onCompleteParams: [newHail, size, x, currentWeather.type]});
//TweenMax.fromTo(newHail.node, 3 + (Math.random() * 5), {x: x, y: y}, {y: endY, onComplete: onHailEnd, onCompleteParams: [newHail, size, x, currentWeather.type], ease: Power2.easeIn})
}
function onHailEnd(stone, size, x, type)
{
// first lets get rid of the hail stone 🌩️
stone.remove();
stone = null;
// We also remove it from the array
for(var i in hail)
{
if(!hail[i].paper) hail.splice(i, 1);
}
// If there is less rain than the rainCount we should
// make more.
if(hail.length < settings.hailCount)
{
makeHail();
}
}
function makeSnow()
{
var offset = 0.5 * currentWeather.intensity;
var scale = offset + (Math.random() * offset);
var newSnow;
var x = 20 + (Math.random() * (sizes.card.width - 40));
var endX; // = x - ((Math.random() * (areaX * 2)) - areaX)
var y = -10;
var endY;
if(scale > 0.8)
{
newSnow = outerSnowHolder.circle(0, 0, 5)
.attr({
fill: 'white'
})
endY = sizes.container.height + 10;
y = sizes.card.offset.top + settings.cloudHeight;
x = x + sizes.card.offset.left;
//xBezier = x + (sizes.container.width - sizes.card.offset.left) / 2;
//endX = sizes.container.width + 50;
}
else
{
newSnow = innerSnowHolder.circle(0, 0 ,5)
.attr({
fill: 'white'
})
endY = sizes.card.height + 10;
//x = -100;
//xBezier = sizes.card.width / 2;
//endX = sizes.card.width + 50;
}
snow.push(newSnow);
TweenMax.fromTo(newSnow.node, 3 + (Math.random() * 5), {x: x, y: y}, {y: endY, onComplete: onSnowEnd, onCompleteParams: [newSnow], ease: Power0.easeIn})
TweenMax.fromTo(newSnow.node, 1,{scale: 0}, {scale: scale, ease: Power1.easeInOut})
TweenMax.to(newSnow.node, 3, {x: x+((Math.random() * 150)-75), repeat: -1, yoyo: true, ease: Power1.easeInOut})
}
function onSnowEnd(flake)
{
flake.remove();
flake = null;
for(var i in snow)
{
if(!snow[i].paper) snow.splice(i, 1);
}
if(snow.length < settings.snowCount)
{
makeSnow();
}
}
function tick()
{
tickCount++;
var check = tickCount % settings.renewCheck;
if(check)
{
if(rain.length < settings.rainCount) makeRain();
if(leafs.length < settings.leafCount) makeLeaf();
if(snow.length < settings.snowCount) makeSnow();
if(hail.length < settings.hailCount) makeHail();
}
for(var i = 0; i < clouds.length; i++)
{
if(currentWeather.type == 'sun')
{
if(clouds[i].offset > -(sizes.card.width * 1.5)) clouds[i].offset += settings.windSpeed / (i + 1);
if(clouds[i].offset > sizes.card.width * 2.5) clouds[i].offset = -(sizes.card.width * 1.5);
clouds[i].group.transform('t' + clouds[i].offset + ',' + 0);
}
else
{
clouds[i].offset += settings.windSpeed / (i + 1);
if(clouds[i].offset > sizes.card.width) clouds[i].offset = 0 + (clouds[i].offset - sizes.card.width);
clouds[i].group.transform('t' + clouds[i].offset + ',' + 0);
}
}
for(var i = 0; i < fog.length; i++)
{
if(currentWeather.type == 'haze' || currentWeather.type == 'smoke')
{
fog[i].offset += settings.windSpeed / (i + 1);
if(fog[i].offset > sizes.card.width) fog[i].offset = 0 + (fog[i].offset - sizes.card.width);
fog[i].group.transform('t' + fog[i].offset + ',' + (sizes.card.height- settings.cloudHeight - (settings.cloudSpace * i)));
}
else
{
if(fog[i].offset > -(sizes.card.width * 1.5)) fog[i].offset += settings.windSpeed / (i + 1);
if(fog[i].offset > sizes.card.width * 2.5) fog[i].offset = -(sizes.card.width * 1.5);
fog[i].group.transform('t' + fog[i].offset + ',' + (sizes.card.height - settings.cloudHeight - (settings.cloudSpace * i)));
}
}
requestAnimationFrame(tick);
}
function reset()
{
for(var i = 0; i < weather.length; i++)
{
container.removeClass(weather[i].type);
if (weather[i].button) weather[i].button.removeClass('active');
}
for(var j = 0; j < classes.length; j++)
{
container.removeClass(classes[j]);
}
}
function updateTempText(newTemp, newFormat)
{
temp.html(newTemp);
tempFormat.html(newFormat);
TweenMax.fromTo(temp, 1.5, {x: 30}, {opacity: 1, x: 0, ease: Power4.easeOut});
TweenMax.fromTo(tempFormat, 1.5, {x: 30}, {opacity: 1, x: 0, ease: Power4.easeOut});
}
function updateDateText()
{
var d = new Date();
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
date.html(days[d.getDay()] + " " + d.getDate() + " " + months[d.getMonth()]);
TweenMax.fromTo(date, 1.5, {x: 30}, {opacity: 1, x: 0, ease: Power4.easeOut});
}
function updateSummaryText()
{
summary.html(currentWeather.name);
TweenMax.fromTo(summary, 1.5, {x: 30}, {opacity: 1, x: 0, ease: Power4.easeOut});
}
function startLightningTimer()
{
if(lightningTimeout) clearTimeout(lightningTimeout);
if(currentWeather.type == 'thunder' || currentWeather.type == 'severe' || currentWeather.type == 'hail')
{
lightningTimeout = setTimeout(lightning, Math.random()*6000);
}
}
function lightning()
{
startLightningTimer();
TweenMax.fromTo(card, 0.75, {y: -30}, {y:0, ease:Elastic.easeOut});
var pathX = 30 + Math.random() * (sizes.card.width - 60);
var yOffset = 20;
var steps = 20;
var points = [pathX + ',0'];
for(var i = 0; i < steps; i++)
{
var x = pathX + (Math.random() * yOffset - (yOffset / 2));
var y = (sizes.card.height / steps) * (i + 1)
points.push(x + ',' + y);
}
var strike = weatherContainer1.path('M' + points.join(' '))
.attr({
fill: 'none',
stroke: 'white',
strokeWidth: 2 + Math.random()
})
TweenMax.to(strike.node, 1, {opacity: 0, ease:Power4.easeOut, onComplete: function(){ strike.remove(); strike = null}})
}
function changeWeather(weather)
{
if(weather.data) weather = weather.data;
reset();
currentWeather = weather;
TweenMax.killTweensOf(summary);
TweenMax.to(summary, 1, {opacity: 0, x: -30, onComplete: updateSummaryText, ease: Power4.easeIn})
container.addClass(weather.type);
container.addClass(weather.class);
if (weather.button) weather.button.addClass('active');
// windSpeed
switch(weather.type)
{
case 'severe':
case 'wind':
case 'smoke':
TweenMax.to(settings, 3, {windSpeed: 3 * weather.intensity, ease: Power2.easeInOut});
break;
case 'sun':
TweenMax.to(settings, 3, {windSpeed: 20, ease: Power2.easeInOut});
break;
case 'haze':
case 'cloud':
TweenMax.to(settings, 3, {windSpeed: 1, ease: Power2.easeInOut});
break;
default:
TweenMax.to(settings, 3, {windSpeed: 0.5, ease: Power2.easeOut});
break;
}
// rainCount
switch(weather.type)
{
case 'mix':
case 'mix-rain-snow':
case 'mix-rain-sleet':
case 'rain':
TweenMax.to(settings, 3, {rainCount: 20 * weather.intensity, ease: Power2.easeInOut});
break;
case 'hail':
TweenMax.to(settings, 3, {rainCount: 5 * weather.intensity, ease: Power2.easeInOut});
break;
case 'severe':
case 'thunder':
TweenMax.to(settings, 3, {rainCount: 30 * weather.intensity, ease: Power2.easeInOut});
break;
default:
TweenMax.to(settings, 1, {rainCount: 0, ease: Power2.easeOut});
break;
}
// hailCount
switch(weather.type)
{
case 'mix':
TweenMax.to(settings, 3, {hailCount: 3 * weather.intensity, ease: Power2.easeInOut});
break;
case 'mix-snow-sleet':
case 'mix-rain-sleet':
TweenMax.to(settings, 3, {hailCount: 10 * weather.intensity, ease: Power2.easeInOut});
break;
case 'sleet':
TweenMax.to(settings, 3, {hailCount: 20 * weather.intensity, ease: Power2.easeInOut});
break;
case 'severe':
TweenMax.to(settings, 3, {hailCount: 3 * weather.intensity, ease: Power2.easeInOut});
break;
case 'hail':
TweenMax.to(settings, 3, {hailCount: 20 * weather.intensity, ease: Power2.easeInOut});
break;
default:
TweenMax.to(settings, 1, {hailCount: 0, ease: Power2.easeOut});
break;
}
// leafCount
switch(weather.type)
{
case 'severe':
case 'wind':
TweenMax.to(settings, 3, {leafCount: 5 * weather.intensity, ease: Power2.easeInOut});
break;
default:
TweenMax.to(settings, 1, {leafCount: 0, ease: Power2.easeOut});
break;
}
// snowCount
switch(weather.type)
{
case 'mix':
case 'mix-rain-snow':
case 'mix-snow-sleet':
case 'snow':
TweenMax.to(settings, 3, {snowCount: 40 * weather.intensity, ease: Power2.easeInOut});
break;
default:
TweenMax.to(settings, 1, {snowCount: 0, ease: Power2.easeOut});
break;
}
// sun position
switch(weather.type)
{
case 'sun':
TweenMax.to(sun.node, 4, {x: sizes.card.width / 2, y: sizes.card.height / 2, ease: Power2.easeInOut});
TweenMax.to(sunburst.node, 4, {scale: 1, opacity: 0.8, x: sizes.card.offset.left + (sizes.card.width/2), y: (sizes.card.height/2) + (sizes.card.offset.top), ease: Power2.easeInOut});
break;
case 'cloud':
var ypos = (sizes.card.height/2) - ((sizes.card.height/2) * weather.intensity);
TweenMax.to(sun.node, 4, {x: sizes.card.width / 2, y: ypos, ease: Power2.easeInOut});
TweenMax.to(sunburst.node, 2, {scale: 0.1, opacity: 0, x: sizes.card.offset.left + (sizes.card.width/2), y: ypos + (sizes.card.offset.top), ease: Power2.easeInOut});
break;
default:
TweenMax.to(sun.node, 2, {x: sizes.card.width / 2, y: -100, leafCount: 0, ease: Power2.easeInOut});
TweenMax.to(sunburst.node, 2, {scale: 0.1, opacity: 0, x: sizes.card.offset.left + (sizes.card.width/2), y: (sizes.container.height/2)-100, ease: Power2.easeInOut});
break;
}
// lightning
startLightningTimer();
}
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
console.log("Geolocation is not supported by this browser.");
}
}
function showPosition(position) {
var location = "(" + position.coords.latitude + "," + position.coords.longitude + ")";
var searchtext = "select * from weather.forecast where woeid in (select woeid from geo.places(1) where text='" + location + "') and u='f'"
//change city variable dynamically as required
$.getJSON("https://query.yahooapis.com/v1/public/yql?q=" + searchtext + "&format=json").success(function(data){
//console.log(data);
var weather = data.query.results.channel.item;
setWeather(weather);
});
}
function setWeather(weather) {
var condition = weather.condition;
var forecast = weather.forecast[0];
//changeWeather(weatherMap[forecast.code]);
//updateTempText(forecast.high, "°F");
changeWeather(weatherMap[condition.code]);
updateTempText(condition.temp, "°F");
}
getLocation();
class ViewModel {
constructor(){
this.weatherMap = Object.values(weatherMap);
}
changeWeather(data, event) {
changeWeather(data);
}
}
ko.applyBindings(new ViewModel());
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://codepen.io/steveg3003/pen/zBVakw.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.js"></script>
@import 'https://fonts.googleapis.com/css?family=Lato:300';
@import 'https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/css/weather-icons.min.css';
$speed: 2s;
html, body, .background
{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
font-family: 'Lato', sans-serif;
}
html
{
background: #fff;
}
body
{
background: #eee;
background: linear-gradient(0deg, rgba(0, 0, 200, 0.2) , rgba(0, 0, 200, 0) );
}
.background
{
background: #eee;
background: linear-gradient(120deg, rgba(50, 150, 100, 0.2) , rgba(0, 0, 100, 0) );
}
.container
{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: auto;
position: relative;
background: #eee;
background: linear-gradient(240deg, rgba(150, 50, 50, 0.3) , rgba(0, 0, 200, 0) );
&.cloud
{
//background: linear-gradient(360deg, rgba(50, 50, 50, 0.5) , rgba(0, 0, 200, 0) );
}
&.wind
{
}
#sunburst {
//transform: scale(.1);
opacity: 0;
}
&.night {
#sunburst {
opacity: 0 !important;
}
}
}
.card-container {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: auto;
position: relative;
margin: 20px;
}
nav
{
height: 400px;
min-height: 300px;
max-height: 100%;
margin-right: 20px;
ul
{
list-style-type: none;
padding: 0;
display: flex;
flex-direction: column;
}
li a
{
display: block;
width: 50px;
text-align: center;
color: #aaa;
cursor: pointer;
&:hover
{
color: #444;
}
&.active
{
color: #4444ff;
}
}
}
.test-nav ul{
flex-wrap: wrap-reverse;
width: auto;
height: 100%;
margin: 0px;
li a
{
width: 25px;
height: 25px;
}
}
#card
{
//background: #fff;
box-shadow: 9px 7px 40px -6px rgba(0,0,0,0.25);
overflow: hidden;
width: 300px;
padding: 0;
height: 400px;
min-height: 300px;
max-height: 100%;
border-radius: 5px;
//border: solid 0px #fff;
position: relative;
.details
{
position: absolute;
top: 0;
left: 0;
right: 0;
padding: 16px 20px;
color: #888;
display: flex;
flex-direction: row;
justify-content: space-between;
transition: color $speed ease;
.night &,
.smoke &,
.hail &,
.severe &,
.thunder &
{
color: #ddd;
}
.right
{
text-align: right;
}
#date
{
margin: 4px 0;
}
#summary
{
font-weight: 600;
font-size: 22px;
}
.temp
{
font-size: 60px;
line-height: 60px;
.super
{
font-size: 18px;
line-height: 30px;
vertical-align: top;
margin-left: 5px;
}
}
}
}
.weather
{
background-color: #DAE3FD;
transition: background-color $speed ease;
.hail &,
.severe &,
.thunder &
{
background-color: #9FA4AD;
}
.rain &
{
background-color: #D8D8D8;
}
.haze &
{
background-color: #efefef;
}
.sun &
{
background-color: #ccccff;
}
.hot &,
.smoke & {
background-color: rgba(230, 179, 179, 0.8);
}
#inner
{
background-color: rgba(255,255,255,1);
background: linear-gradient(to bottom, rgba(255,255,255,0.5) 50%, rgba(255,255,255,0) 100%);
}
.cloud
{
transition: fill $speed ease;
}
.fog {
opacity: 0;
transition: opacity $speed ease, fill $speed ease;
.smoke &,
.haze & {
opacity: 1;
}
}
#sun {
fill: #F7ED47;
}
.cold &
{
background-color: #ccdffb;
}
.night & {
background-color: #060638;
#sun {
fill: #ccdbef;
}
}
#fog1
{
fill: #f5f5f5;
.night &,
.smoke &,
.hail &,
.severe &,
.thunder &
{
fill: #aFb4bD;
}
}
#fog2,
#cloud1
{
fill: #efefef;
.night &,
.smoke &,
.hail &,
.severe &,
.thunder &
{
fill: #9FA4AD;
}
}
#fog3,
#cloud2
{
fill: #E6E6E6;
.night &,
.smoke &,
.hail &,
.severe &,
.thunder &
{
fill: #8B8E98;
}
}
#cloud3
{
fill: #D5D5D5;
.night &,
.smoke &,
.hail &,
.severe &,
.thunder &
{
fill: #7B7988;
}
}
}
#outer, #back
{
position: fixed;
pointer-events: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment