CSS
JavaScript
JSON
WeatherUnderground

弊社エントランスのサイネージにお天気予報を表示させる


はじめに

この記事はウェブクルー Advent Calendar 2018の21日目の記事です。

昨日は@wc-keisuke_tokunagaさんの「ホラクラシーとブロックチェーン」でした。


2019/03/12追記

下記記事内で紹介している「WEATHER UNDERGROUND」のAPIによる天気情報提供サービスがいつの間にか終了していました。

jsonからcssに置き換えてアイコンを表示する方法はどのサービスを使ってもあまり変わりはないかとは思います。

代替サービスを探して実装してみてください。←いいサービスあったら教えてくださいw


概要

弊社エントランスには壁に大きなモニターが埋め込まれています。

当初は完全に作られた動画をループで再生させていたのですが、いちいち情報の更新が手間でWEBで作りなおすことになりました。

スライドショーのjQueryプラグインを使って各サービスの紹介などをちりばめつつ、来社された方にお天気予報も見せちゃおうということで、デザイナーさんにデザインを作ってもらい、イイ感じのお天気予報画面を実装しました。

出来上がったデザインがこちら(9枚合わせてます)。

total.png

うん…いろいろと要求レベルが高いですな。。まずこのデザインから読み取れるのは…


  • 今のタイミングのお天気・気温がわかる

  • お天気の状況によって色やオカズが変わる

  • 時間帯によって色が変わる

  • 今日の9:00、12:00、15:00、18:00、21:00のお天気・気温がわかる


1. お天気データを取得する

さて、お天気を表示させるといってもいろいろお天気情報を配信しているところがありますので、うまく選定しないといけないですな。


「国土交通省 気象データ高度利用ポータルサイト」

https://www.data.jma.go.jp/developer/index.html

さすが国土交通省。カジュアルさが一切なくてよくわからなかった。


「Yahoo!気象情報API」

https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/weather.html

利用する場所(URL)を指定しないといけなかった。

今回は社内環境(公開されていない)だったので使えず。


「openweathermap」

https://openweathermap.org/api

凄い使いやすかったんだけど、実際のお天気と比べてみたらわりと違った…。

そのタイミングだけだったのかもしれませんが、「晴れ」って出てるのに外見たらガンガン雨降ってる時があったので落選。


今回選んだのがこちら「WEATHER UNDERGROUND」。←APIによる天気情報提供サービスは終了していました…(2018/03/12追記)

https://www.wunderground.com/

アカウントを作ってAPIキーを取得するかたち。

利用するURLは「http://」だけで他は特に入れなくても通る。



2. 今のタイミングのお天気・気温がわかる

jsonから情報を取得してお天気アイコンに置き換えます。

まずjsonの中身(一部)。


/conditions/weather.json

current_observation

temp_f:55.6
temp_c:13.1
relative_humidity:"59%"
icon:"clear"

ふむ、なるほど。

お天気のアイコンのパスまで送ってくれている。

http://icons.wxug.com/i/c/k/clear.gif

が、基本洋モノなので日本人のお天気予報の感覚と少し違ったアイコンが多いですよね。

なじみのないやつとか。(下記、大げさな例)

weather_icon02.png

「晴れ」は焼けるような灼熱だし、「雨」とかも劇画調で「モーセがヘブライ人を連れて海を渡る時」みたいなやつ。

そういうんじゃないんだよ、日本の天気は。四季とかあって、春は「うらら」だし。みたいな。

なので、下のようにWEBフォントとjsでいろいろ置き換えちゃいます。


weather.js

function getWeather() {

$.ajax({
url: "http://api.wunderground.com/api/apiKEYapiKEYapiKEY/conditions/lang:JP/q/Japan/Shibuya.json",
cache: false,
success:function (weatherdata){
document.getElementById('icon01').innerHTML = '<span class="icon-'+weatherdata.current_observation.icon+'"></span>';
document.getElementById('tmp01').innerHTML = Math.floor(weatherdata.current_observation.temp_c) + '°';
}
});
}

CSSはこんな感じ。

まずは私たちにもわかりやすい「ソフトなお天気アイコン」を呼び出す。

デザイナーさんが「これがええ!」言うたやつですけど。


weather.css

@font-face {

font-family: 'weather';
src: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/93/artill_clean_icons-webfont.eot');
src: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/93/artill_clean_icons-webfont.eot?#iefix') format('embedded-opentype'),
url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/93/artill_clean_icons-webfont.woff') format('woff'),
url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/93/artill_clean_icons-webfont.ttf') format('truetype'),
url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/93/artill_clean_icons-webfont.svg#artill_clean_weather_iconsRg') format('svg');
font-weight: normal;
font-style: normal;
}

お天気アイコンはこんな感じ(一部)。

weather_icon.png

はい、ここから気をしっかり持ってください。超めんどくさいです。

上記jsonの「icon」の中身がid=icon01のクラス名の一部になります。

CSSでそのクラス名の::beforeのcontentにアルファベット(お天気アイコン)をあてがって表示させるわけです。

表記されるお天気のバリエーションを調べて、それに置き換えられるアイコンをフォントから選んで。。。

とっても手間なので、私がまとめたやつを下に列挙します。


weather.css

p span.icon-chanceflurries::before { content: "I"; }

p span.icon-nt_chanceflurries::before { content: "I"; }
p span.icon-chancerain::before { content: "K"; }
p span.icon-nt_chancerain::before { content: "K"; }
p span.icon-chancesleet::before { content: "N"; }
p span.icon-nt_chancesleet::before { content: "N"; }
p span.icon-chancesnow::before { content: "I"; }
p span.icon-nt_chancesnow::before { content: "I"; }
p span.icon-chancetstorms::before { content: "Y"; }
p span.icon-nt_chancetstorms::before { content: "Y"; }
p span.icon-cloudy::before { content: "3"; }
p span.icon-nt_cloudy::before { content: "3"; }
p span.icon-flurries::before { content: "I"; }
p span.icon-nt_flurries::before { content: "I"; }
p span.icon-fog::before { content: "Z"; }
p span.icon-nt_fog::before { content: "Z"; }
p span.icon-hazy::before { content: "Z"; }
p span.icon-nt_hazy::before { content: "Z"; }
p span.icon-mostlycloudy::before { content: "A"; }
p span.icon-nt_mostlycloudy::before { content: "a"; }
.night p span.icon-mostlycloudy::before { content: "a"; }
.night p span.icon-nt_mostlycloudy::before { content: "a"; }
p span.icon-mostlysunny::before { content: "2"; }
p span.icon-nt_mostlysunny::before { content: "a"; }
.night p span.icon-mostlysunny::before { content: "a"; }
.night p span.icon-nt_mostlysunny::before { content: "a"; }
p span.icon-partlycloudy::before { content: "2"; }
p span.icon-nt_partlycloudy::before { content: "a"; }
.night p span.icon-partlycloudy::before { content: "a"; }
.night p span.icon-nt_partlycloudy::before { content: "a"; }
p span.icon-partlysunny::before { content: "A"; }
p span.icon-nt_partlysunny::before { content: "a"; }
.night p span.icon-partlysunny::before { content: "a"; }
.night p span.icon-nt_partlysunny::before { content: "a"; }
p span.icon-rain::before { content: "K"; }
p span.icon-nt_rain::before { content: "K"; }
p span.icon-sleet::before { content: "N"; }
p span.icon-nt_sleet::before { content: "N"; }
p span.icon-snow::before { content: "I"; }
p span.icon-nt_snow::before { content: "I"; }
p span.icon-clear::before { content: "1"; }
p span.icon-nt_clear::before { content: "6"; }
.night p span.icon-clear::before { content: "6"; }
.night p span.icon-nt_clear::before { content: "6"; }
p span.icon-sunny::before { content: "1"; }
p span.icon-nt_sunny::before { content: "6"; }
.night p span.icon-sunny::before { content: "6"; }
.night p span.icon-nt_sunny::before { content: "6"; }
p span.icon-tstorms::before { content: "Y"; }
p span.icon-nt_tstorms::before { content: "Y"; }

ご利用は計画的に&自己責任で。

「この天気アイコンちげーじゃん!」ていうのが見つかったら、勝手に改変してください。

ちなみにたまに.nightとか入ってるのは、夜の時間帯になったらアイコンが変わるやつです。

時間によって大枠に.nightを付与するようになっていて、それが付いている時は夜のアイコンになる。

昼間の「晴れ」は太陽だけど、夜の「晴れ」はお月さまだったり。


3. お天気の状況によって色やオカズが変わる

先ほどのjsに記述を少し追加します。


weather.js

function getWeather() {

$.ajax({
url: "http://api.wunderground.com/api/apiKEYapiKEYapiKEY/conditions/lang:JP/q/Japan/Shibuya.json",
cache: false,
success:function (weatherdata){
document.getElementById('icon01').innerHTML = '<span class="icon-'+weatherdata.current_observation.icon+'"></span>';
document.getElementById('tmp01').innerHTML = Math.floor(weatherdata.current_observation.temp_c) + '°';

var wData = weatherdata.current_observation.icon
var weatherClass;
if(wData == 'sunny' || wData =='nt_sunny' || wData == 'mostlysunny' || wData =='nt_mostlysunny' || wData =='partlycloudy' || wData =='nt_partlycloudy' || wData =='clear' || wData =='nt_clear'){
var weatherClass = 'fine'
} else if(wData == 'partlysunny' || wData == 'nt_partlysunny' || wData == 'mostlycloudy' || wData == 'nt_mostlycloudy' || wData == 'cloudy' || wData == 'nt_cloudy' || wData == 'flurries' || wData == 'nt_flurries' || wData == 'fog' || wData == 'nt_fog' || wData == 'hazy' || wData == 'nt_hazy' || wData == 'snow' || wData == 'nt_snow' || wData == 'chancetstorms' || wData == 'nt_chancetstorms' || wData == 'chancesnow' || wData == 'nt_chancesnow' || wData == 'chanceflurries' || wData == 'nt_chanceflurries' || wData == 'tstorms' || wData == 'nt_tstorms'){
var weatherClass = 'cloudy'
} else {
var weatherClass = 'rainy'
}
document.getElementById('wrapper').className = weatherClass;
}
});
}
setInterval('getWeather()',3600000);


デザインデータが晴れ、曇り、雨の分け方で作られてきたので、先ほどの「icon」のデータから「fine」「cloudy」「rainy」に分類して大枠にクラス名を付与する。

あと、最後の1行で1時間ごと(3600000msc)のデータ更新で、なんとなく現在の天気を取得しています。

晴れの日は飛行機がブーンと横切り、曇りの日は雲がいくつかプカプカ浮いていて、雨の日は雨が斜めにザーッと降ります。

それぞれ画像にCSSでアニメーションをつけて、大枠の「fine」「cloudy」などに連動させて表示させることにしています。


4. 時間帯によって色が変わる

少し出てきた時間によってのクラス名付与も3通り「morning」「day」「night」あるので、それらを駆使して背景画像を入れ替える。

.fine.morning から .rainy.night まで9通りのスタイルの指定をしてやれば時間別・お天気別の背景のセットが完成。

時間を取得した後、こんな感じで設定してあります。


weather.js

    if( nowHour >= 06 && nowHour <= 12) {

document.getElementById('wrapper').classList.add('morning')
}
else if( nowHour >= 12 && nowHour <= 17) {
document.getElementById('wrapper').classList.add('day')
}
else {
document.getElementById('wrapper').classList.add('night')
}

※1 最近になって「冬の16時ってもう暗いよな…」と思ってここに「季節」の概念を追加してさらにカオス化しましたがw


5. 今日の9:00、12:00、15:00、18:00、21:00のお天気・気温がわかる

ここまで来たら、もうそれぞれの時間のお天気を同じように取得してアイコンに置き換えるだけで完成~

で、「本日の3時間ごとのお天気」は…。どこだ??

少なくとも先ほどのjsonは「現在のお天気」。これだけじゃ「予報」じゃないし。と思っていたら下のようなデータもありました。

http://api.wunderground.com/api/apiKEYapiKEYapiKEY/hourly/lang:JP/q/Japan/Shibuya.json

ふむ。hourlyだから時間帯ごとというか、1時間ごとというか。

中身を見てみるとこんな感じ。(今が16時台とすると、の一部)


/hourly/weather.json

hourly_forecast

0
FCTTIME
hour:"17"
temp
metric:"9"
icon:"partlycloudy"

1
FCTTIME
hour:"18"
temp
metric:"7"
icon:"cloudy"


お…おう。。。

「今日の1時間ごとのお天気の推移」じゃなくて「今から1時間ごとのお天気の予測」なのね。

0に入るやつがどんどん上書きされていくのか。なるほど。

ということで、jsに追記したのは以下です。


weather.js

function getWeather02() {

$.ajax({
url: "http://api.wunderground.com/api/apiKEYapiKEYapiKEY/hourly/lang:JP/q/Japan/Shibuya.json",
cache: false,
success:function (weatherdata){
document.getElementById('icon02').innerHTML = '<span class="icon-'+weatherdata.hourly_forecast[0].dewpoint.icon+'"></span>';
document.getElementById('icon03').innerHTML = '<span class="icon-'+weatherdata.hourly_forecast[3].dewpoint.icon+'"></span>';
document.getElementById('icon04').innerHTML = '<span class="icon-'+weatherdata.hourly_forecast[6].dewpoint.icon+'"></span>';
document.getElementById('icon05').innerHTML = '<span class="icon-'+weatherdata.hourly_forecast[9].dewpoint.icon+'"></span>';
document.getElementById('icon06').innerHTML = '<span class="icon-'+weatherdata.hourly_forecast[12].dewpoint.icon+'"></span>';
document.getElementById('tmp02').innerHTML = Math.floor(weatherdata.hourly_forecast[0].temp.metric) + '°';
document.getElementById('tmp03').innerHTML = Math.floor(weatherdata.hourly_forecast[3].temp.metric) + '°';
document.getElementById('tmp04').innerHTML = Math.floor(weatherdata.hourly_forecast[6].temp.metric) + '°';
document.getElementById('tmp05').innerHTML = Math.floor(weatherdata.hourly_forecast[9].temp.metric) + '°';
document.getElementById('tmp06').innerHTML = Math.floor(weatherdata.hourly_forecast[12].temp.metric) + '°';
}
});
}
setInterval('getWeather02()',86400000);

ひとつめの枠が「9:00」、次が「12:00」のようにして3時間ごとのお天気をそれぞれに振り込む。

そして最後の行で24時間(86400000msc)ごとに更新をかける。

だいぶ疲れてきましたが、最後に「時間の起点」を作ったります。

時間を制御する先ほどのjsの記述の部分に下記を追記して毎朝8時59分に全体的にリロードさせれば完成です。


weather.js

    if (refleshTime == 085900) {

location.reload(true);
}
else {}

これ、通常のリロードに(true)をつけると(Ctrl + F5)のスーパーリロードになります。

お天気情報以外のスライドの更新が入った時も、前日に用意してアップロードしておけば次の日の朝に確実にリロードされて、

新しいコンテンツが読み込まれることになります。便利。

ということで、デザインデータから表示したい情報を分別、お天気データを取得して、アイコンに置き換える。時間帯とお天気の状況によって表示も変える。

の一連の流れが上記で完成しました。

疲れましたが、面白かった。いろいろ勉強になりました。


最後に

弊社ではデザイナーさんが完全に分業で存在します。

なんなら、コーディングの難易度とかあまり考えずにデザインを作ってくれます。

そういうのって、とっても大事。

「難しいだろうから…」と思われたら、何も工夫しなくなります。何も生まれません。

だからこそ、「こんなのどうだ!できるもんならやってみろ。」的なデザイナーさんがいてくれるのはとってもありがたいですし、これからもそういう方たちと一緒に働いていきたいと思っています。

※1 この記事を書いていて、いろいろ再確認する過程で、冬の16時ってめっちゃ暗いやん…青空出してる場合ちゃうやん。。。

と思い、大枠に「時間」の概念と「季節」の概念を追加しました。


weather.js

    document.getElementById('wrapper').setAttribute('data-time', 'time' + nowHour);



weather.js

    if( month[mon] >= 3 && month[mon] <= 6) {

document.getElementById('wrapper').classList.add('spring')
}
else if( month[mon] >= 7 && month[mon] <= 9) {
document.getElementById('wrapper').classList.add('summer')
}
else if( month[mon] >= 10 && month[mon] <= 11) {
document.getElementById('wrapper').classList.add('autumn')
}
else if( month[mon] == 12) {
document.getElementById('wrapper').classList.add('winter','xmas')
}
else {
document.getElementById('wrapper').classList.add('winter')
}

最終的には大枠のid="wrapper"は、こんな感じになりました。


weather.html

<div id="wrapper" class="fine winter xmas" data-time="time16">


12月の夜だけサンタクロースを飛ばしたくなったので .xmas を付与して、記事公開記念に追加しておきました。

ご覧になりたい方は弊社エントランスまでお越しください。

santa.png

自らカオスを生むのは、再来年ぐらいでやめようと思います。

ちなみにスライドショーに使ったプラグインはこちら。

https://github.com/pixedelic/Camera

((((;゚Д゚)))) オフィシャルサイトがなくなっている…


ウェブクルーでは一緒に働いていただける方を随時募集しております。

お気軽にエントリーくださいませ。

開発エンジニアの募集

フロントエンドエンジニアの募集