Skip to content

Instantly share code, notes, and snippets.

@atomaka
Last active August 29, 2015 14:08
Show Gist options
  • Save atomaka/1fa0a95c7a7c8702944c to your computer and use it in GitHub Desktop.
Save atomaka/1fa0a95c7a7c8702944c to your computer and use it in GitHub Desktop.
class Dashing.Verbinski extends Dashing.Widget
@accessor 'current_icon', ->
getIcon(@get('current.icon'))
@accessor 'day_icon', ->
getIcon(@get('today.icon'))
ready: ->
# This is fired when the widget is done being rendered
onData: (data) ->
# Handle incoming data
@currentBg(@get('current.temperature'))
@getWindDirection(@get('current.wind_bearing'))
@todayBg(@get('today.high'), @get('today.low'))
@thisWeekBg(@get('upcoming_week'))
@unpackWeek(@get('upcoming_week'))
@getTime()
# flash the html node of this widget each time data comes in
$(@node).fadeOut().fadeIn()
currentBg: (temp) ->
@set 'right_now', @getBackground(temp)
getWindDirection: (windBearing) ->
@set 'wind_bearing', getWindDirection(windBearing)
todayBg: (high, low) ->
averageRaw = (high + low) / 2
average = Math.round(averageRaw)
@set 'today_bg', @getBackground(average)
thisWeekBg: (weekRange) ->
averages = []
for day in weekRange
average = Math.round((day.max_temp + day.min_temp) / 2)
averages.push average
sum = 0
averages.forEach (a) -> sum += a
weekAverage = Math.round(sum / 7)
@set 'this_week_bg', @getBackground(weekAverage)
unpackWeek: (thisWeek) ->
# get max temp, min temp, icon for the next seven days
days = []
for day in thisWeek
dayObj = {
time: day['time'],
min_temp: "#{day['min_temp']}°",
max_temp: "#{day['max_temp']}°",
icon: getIcon(day['icon'])
}
days.push dayObj
@set 'this_week', days
getBackground: (temp) ->
range =
0: -20
1: [-19..-11]
2: [-10..-1]
3: [0..4]
4: [5..9]
5: [10..14]
6: [15..19]
7: [20..24]
8: 25
weather = "#4b4b4b"
switch
when temp <= range[0] then weather = 'cold5'
when temp in range[1] then weather = 'cold4'
when temp in range[2] then weather = 'cold3'
when temp in range[3] then weather = 'cold2'
when temp in range[4] then weather = 'cold1'
when temp in range[5] then weather = 'cool2'
when temp in range[6] then weather = 'cool1'
when temp in range[7] then weather = 'warm'
when temp >= range[8] then weather = 'hot'
weather
getTime: (now = new Date()) ->
hour = now.getHours()
minutes = now.getMinutes()
minutes = if minutes < 10 then "0#{minutes}" else minutes
ampm = if hour >= 12 then "pm" else "am"
hour12 = if hour % 12 then hour % 12 else 12
@set 'last_updated', "#{hour12}:#{minutes} #{ampm}"
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="3" data-sizey="1">
<div data-id="verbinski" data-view="Verbinski"></div>
</li>
</ul>
</div>
<div id="right-now" data-bind-class="right_now">
<div class="column-inner column-left">
<h3 class="title">Right now</h3>
<h2 class="temp" data-bind="current.temperature | append '&deg;' | raw"></h2>
<div class="summary-wrapper clearfix">
<img class="weather-icon-left" data-bind-src="current_icon" />
<p class="summary summary-right" data-bind="current.summary | raw"></p>
</div>
<div class="details-text-only">
<p>
<span>Humidity: </span>
<span data-bind="current.humidity | raw"></span>
</p>
<p>
<span>Wind: </span>
<span data-bind="wind_bearing"></span>
<span data-bind="current.wind_speed | raw"></span>
<span> km/h </span>
</p>
</div>
</div>
</div>
<div id="today" data-bind-class="today_bg">
<div class="column-inner column-middle">
<h3 class="title">Today</h3>
<div class="summary-wrapper clearfix">
<img class="weather-icon-left" data-bind-src="day_icon" />
<p class="summary summary-right" data-bind="today.summary"></p>
</div>
<div class="details-text-only">
<p>
<span>L&thinsp;: </span>
<span data-bind="today.low | append '&deg;C' | raw"></span>
<span> | </span>
<span>H&thinsp;: </span>
<span data-bind="today.high | append '&deg;C' | raw"></span>
</p>
</div>
<div class="details-text-only">
<p>
<span>Sunrise: </span><span data-bind="today.sunrise"></span>
</p>
<p>
<span>Sunset: </span><span data-bind="today.sunset"></span>
</p>
</div>
<p class="powered-by">Powered by Forecast.io</p>
<p class="last-updated">
<span>Last updated: </span>
<span data-bind="last_updated"></span>
</p>
</div>
</div>
<div id="this-week" data-bind-class="this_week_bg">
<div class="column-inner column-right">
<h3 class="title">This week</h3>
<div class="upcoming-week">
<p data-foreach-day="this_week">
<span data-bind="day.time"></span>:
<span data-bind="day.min_temp | raw"></span> -
<span data-bind="day.max_temp | raw"></span>
<img class="weather-icon-inline" data-bind-src="day.icon" />
</p>
</div>
</div>
</div>
console.log("Verbinski (the weather widget) has been loaded!");
function getIcon(iconKey) {
var prefix = "/assets/climacons/svg/";
var ext = ".svg";
if (!iconKey) {
return prefix + "Cloud-Refresh" + ext;
}
var key = iconKey.replace(/-/g, "_");
var iconMap = {
clear_day: "Sun",
clear_night: "Moon",
rain: "Cloud-Rain",
snow: "Snowflake",
sleet: "Cloud-Hail",
wind: "Wind",
fog: "Cloud-Fog-Alt",
cloudy: "Cloud",
partly_cloudy_day: "Cloud-Sun",
partly_cloudy_night: "Cloud-Moon"
}
var fullPath = prefix + iconMap[key] + ext;
return fullPath;
}
function getWindDirection(windBearing) {
// windBearing is where the wind is coming FROM
var direction;
if ((windBearing > 315) || (windBearing < 45)) {
direction = "S";
} else if ((windBearing >= 45) && (windBearing < 135)) {
direction = "W";
} else if ((windBearing >= 135) && (windBearing < 225)) {
direction = "N";
} else {
direction = "E";
}
return direction;
}

verbinski widget

Link to the full repo: https://github.com/ysim/verbinski

  1. Download the Climacons SVG files and add them to the folder assets/images/climacons/.

  2. Set the environment variables FORECAST_API_KEY, LATITUDE, and LONGITUDE. (You can get your latitude and longitude here).

  3. Copy the files to their respective locations:

     `verbinski.coffee` -> `widgets/verbinski/verbinski.coffee`
     `verbinski.html` -> `widgets/verbinski/verbinski.html`
     `verbinski.scss` -> `widgets/verbinski/verbinski.scss`
     `verbinski.js` -> `assets/javascripts/verbinski.js`
     `verbinski.rb` -> `jobs/verbinski.rb`
    
  4. Put the verbinski.erb snippet in one of your dashboards.

  5. Note that you'll have to comment out line 144 of assets/stylesheets/application.scss; this removes the padding from the widgets so that all the content can fit.

     // padding: 25px 12px;
    
require 'date'
require 'net/https'
require 'json'
# Forecast API Key from https://developer.forecast.io
forecast_api_key = ENV['FORECAST_API_KEY']
# Latitude, Longitude for location
forecast_location_lat = ENV['LATITUDE']
forecast_location_long = ENV['LONGITUDE']
# Unit Format
forecast_units = "ca" # like "si", except windSpeed is in kph
def time_to_str(time_obj)
""" format: 5 pm """
return Time.at(time_obj).strftime "%-l %P"
end
def time_to_str_minutes(time_obj)
""" format: 5:38 pm """
return Time.at(time_obj).strftime "%-l:%M %P"
end
def day_to_str(time_obj)
""" format: Sun """
return Time.at(time_obj).strftime "%a"
end
SCHEDULER.every '5m', :first_in => 0 do |job|
http = Net::HTTP.new("api.forecast.io", 443)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
response = http.request(Net::HTTP::Get.new("/forecast/#{forecast_api_key}/#{forecast_location_lat},#{forecast_location_long}?units=#{forecast_units}"))
forecast = JSON.parse(response.body)
currently = forecast["currently"]
current = {
temperature: currently["temperature"].round,
summary: currently["summary"],
humidity: "#{(currently["humidity"] * 100).round}&#37;",
wind_speed: currently["windSpeed"].round,
wind_bearing: currently["windSpeed"].round == 0 ? 0 : currently["windBearing"],
icon: currently["icon"]
}
daily = forecast["daily"]["data"][0]
today = {
summary: forecast["hourly"]["summary"],
high: daily["temperatureMax"].round,
low: daily["temperatureMin"].round,
sunrise: time_to_str_minutes(daily["sunriseTime"]),
sunset: time_to_str_minutes(daily["sunsetTime"]),
icon: daily["icon"]
}
this_week = []
for day in (1..7)
day = forecast["daily"]["data"][day]
this_day = {
max_temp: day["temperatureMax"].round,
min_temp: day["temperatureMin"].round,
time: day_to_str(day["time"]),
icon: day["icon"]
}
this_week.push(this_day)
end
send_event('verbinski', {
current: current,
today: today,
upcoming_week: this_week,
})
end
// ----------------------------------------------------------------------------
// Sass declarations
// ----------------------------------------------------------------------------
// text colour
$full-colour: rgba(255, 255, 255, 1);
$light-colour: rgba(255, 255, 255, 0.7);
$dark-colour: rgba(0, 0, 0, 0.3);
// text sizes
$info: 18px;
$info-small: 16px;
// column colours
$cold5: #173A7F; // -20 and under
$cold4: #1E4BA6; // -19 to -11
$cold3: #2358C2; // -10 to -1
$cold2: #2863DB; // 0 to 4
$cold1: #2F74FF; // 5 to 9
$cool2: #25D6A4; // 10 to 14
$cool1: #B9CC5A; // 15 to 19
$warm: #ff9d37;// 20 to 24
$hot: #ff5131; // 25 and above
// ----------------------------------------------------------------------------
// Widget-verbinski styles
// ----------------------------------------------------------------------------
.widget-verbinski {
.cold5 { background-color: $cold5; }
.cold4 { background-color: $cold4; }
.cold3 { background-color: $cold3; }
.cold2 { background-color: $cold2; }
.cold1 { background-color: $cold1; }
.cool2 { background-color: $cool2; }
.cool1 { background-color: $cool1; }
.warm { background-color: $warm; }
.hot { background-color: $hot; }
#right-now, #today, #this-week {
float: left;
width: 33%;
height: 100%;
.column-inner {
padding: 20px 30px;
.title {
color: $light-colour;
text-transform: uppercase;
}
.temp { color: $full-colour; }
.summary {
color: $full-colour;
text-align: left;
}
// icon + summary
.summary-wrapper {
display: table;
margin: 0 10px;
.weather-icon-left {
max-width: none;
padding: -10px;
}
.summary-right {
display: table-cell;
vertical-align: middle;
font-size: $info;
}
}
.details-text-only {
font-size: $info;
margin-top: 10px;
}
.upcoming-week {
margin: 15px 0 15px 50px;
text-align: left;
p {
font-size: $info;
margin: -5px 0;
.weather-icon-inline {
max-width: 50px;
margin: -5px;
}
.weather-icon-inline.large {
max-width: 60px;
margin: -10px;
}
}
}
.powered-by {
margin-top: 20px;
color: $light-colour;
font-size: $info-small;
}
.last-updated {
font-size: $info-small;
color: $dark-colour;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment