HAVRMの空空活動誌

「空空」は「うつらうつら」と読むらしいです.まぁ常に寝不足なもんで...

Windyのスクリーンセイバーの製作 -1/4-

こんにちは
HAVRMです.


皆さん,スクリーンセイバーは利用していますか.
スクリーンセイバーはもともと同じ画面が出続けていると画面の画素がその色に固定されてしまうのを防ぐために使われたもののようです.現在ではあまり問題にならないもののやっぱりあるといいものです.


しかし,軽く見た感じではありますが,リアルタイムに情報を収集し,それを反映させるスクリーンセイバーはあまりないようです.
今回下のWindyというサイトのAPIを用いてリアルタイムの天気を表示させるスクリーンセイバーを作ってみようと思います.
www.windy.com


はじめに

Windyというのは気象のサイトの一つで風等の流れる方向や速度を粒子状に表示することできれいに見えるサイトです.昔スクリーンセイバーを出していたようですが,現在は公開をやめています.そのためWindy用のAPIを利用し,スクリーンセイバーを作ろうと考えました.
流れは次のような感じです.

  1. Windyを表示できるHTMLを作成する ←今ここ
  2. インターネットに接続していないときの処理を行う
  3. HTMLをEXE化する.この際全画面表示できるようにする
  4. スクリーンセイバーを設定する


Windy APIとは

詳細は省きますが,簡単に言えばAPI keyを獲得すればJavascriptとHTMLで簡単にWindyを表示できるというものです.GitHubにてサンプルコードが公開されています.
github.com

獲得する際はkey取得ページにアクセスして取得してください.

作りたいスクリーンセイバー

次にスクリーンセイバーのデザインです.
今回作るスクリーンセイバーは次のような機能を持つとします.

  • 画面いっぱいにWindyの画面を出す
  • 中心は東京あたりに設定し現在の状況を表示する
  • 表示するのは「雨・雷」「風」「気温」「湿度」「気圧」「海流」「波」の7つとし,表示は5秒ごとに自動で切り替わるようにする
  • どのAPIを使っているのかわかるようにする
  • Windyを動かせるようにスクリーンセイバーはボタンを押すことで終了する
  • オフラインの時はWindyが表示できないのでデモンストレーションの動画を再生する
  • 当然スクリーンセイバーなので全画面に表示する


今回は赤文字の実装を行います.

実際にプログラミング

画面いっぱいにWindyの画面を出す

これは簡単です.Windy APIサンプルコードを少し変えればいいだけです.変える点は以下の2点です

  • API keyの変更
  • 画面いっぱいの表示に変更する
  • Hello World”のポップアップはいらないから消す


まずAPI keyの変更ですが3つ目の<script>の中にある

key: 'PsLAtXpsPTZexBwUkO7Mx5I',

の ' ' の中を自分が取得したkeyに変更してください.
次に画面いっぱいに出すには<style>の中にある

height: 300px;

height: 100%;

に変えればいいです.
最後の”Hello World”のポップアップは最後のほうにある

        L.popup()
            .setLatLng([50.4, 14.3])
            .setContent("Hello World")
            .openOn( map );

を消せばいいです.ポップアップを出したいときはこの文法で表示できます.

中心は東京あたりに設定し現在の状況を表示する

これは先ほどのコードのうち3つ目の<script>の中にある

                // Optional: Initial state of the map
                lat: 50.4,
                lon: 14.3,
                zoom: 5,

を東京の座標に変えるだけです.日本列島全体を見たいので適切なズームに変えましょう.
東京の座標は次になります.ズームは自分のPCで見ながら調整してください

                lat: 35.6,
                lon: 139.6,

実は表示する時刻の設定もここでできます.

                lat: 35.6,
                lon: 139.6,
                timestamp: Date.now(),

このData.now()はJavascriptの関数で現在時刻を返します.この時間をいじることで表示する時刻を変更可能です.

表示するのは「雨・雷」「風」「気温」「湿度」「気圧」「海流」「波」の7 6つとし,表示は5秒ごとに自動で切り替わるようにする

とりあえずそれぞれの出し方を確認しましょう.フリーエディションだと限られたものしか表示できないようですが,これらは表示できます.

  • 雨・雷:rain
  • 風:wind
  • 気温:temp
  • 湿度:rh
  • 気圧:pressure
  • 海流:currents
  • 波:waves

(2018/12/30追記:)確認したところ,どうやら湿度のデータは表示できないようです.最初にこのコードを作成した当時はきちんと見れていたのですが,どっかのタイミングでフリーだと見れなくなったようです.下のコードは湿度を削除済みです.


また表示の入れかえは
https://api4.windy.com/examples/parameters/

github.com

で紹介されていますが,GitHubのほうが今回の目的に合っています.
下のコードを書くだけで一定時間ごとに設定を変更できます.

        setInterval( ()=> {
            i = ( i === 3 ? 0 : i + 1 )
            store.set('overlay', overlays[ i ] )
        }, time)

今回は7 6パターンの表示を5秒ごとに更新するので,時間の更新もしつつこのようなコードになります.

		var overlays = ['rain','wind','temp','pressure','currents','waves']
		, i = 0
		setInterval( ()=> {
			i = ( i === 5 ? 0 : i + 1)
			store.set('overlay', overlays[ i ])
			store.set('timestamp', Date.now())
		}, 5000)

またこの時設定しているstoreというのも設定しないといけないのでwindyInit内の定義に次のようにstoreを追加します.

        const { store, map } = windyAPI


どのAPIを使っているのかわかるようにする

APIのバージョンや使っているものを表示しましょう.
ここは普通にHTMLとして書くのでAPIはあまり関係ないです.
下の右端に何を使っているのか書くためにWindyを表示する範囲を狭くして文字列を表示しましょう.
サイズは

  			height: 94%;

として追加文字は右下に書くので<body>の一番最後に

	<p align="right">
	We are using Windy API v4, Leaflet v0.7.7.
	</p>

と入れましょう.

現在どの表記をしているのか表示する(2019/4/27追記)

ここまでで6パターンの表示を連続でできるようになりましたが,どのデータかぱっと見ではわからないです.
なのでさっきのAPI表示の前にどれを表示しているか表示します.同じフォントだとわかりにくいので太字フォントを利用します.
表示するだけではstrongタグ(強調フォーマット)だけでいいですが,パターンに合わせて変える必要があります.
そのためパターンを変えているjavascriptのsetInterval関数内で文字も同時に切り替えます.
やり方としては表示文字列を配列で宣言し,どれを表示するのかパターンと一緒に切り替えます.
ということで次のようなコードになります.なお文字数を調整するため適宜スペースを設けています.
Javascript部分

		var overlays = ['rain','wind','temp','pressure','currents','waves']
		, i = 0
                , laysname = ['雨・雷',' 風 ',' 気温 ',' 気圧 ',' 海流 ',' 波 ']
		setInterval( ()=> {
			i = ( i === 5 ? 0 : i + 1)
			store.set('overlay', overlays[ i ])
			store.set('timestamp', Date.now())
                        document.getElementById("lays").innerHTML=laysname[ i ];
		}, 5000)

HTML部分

	<p align="right">
	<strong id="lays"></strong>We are using Windy API v4, Leaflet v0.7.7.
	</p>


Windyを動かせるようにスクリーンセイバーはボタンを押すことで終了する

これも同様にHTMLとJavascriptで書きます.
先ほどどのAPIを使っているのか書いた後にボタンを挿入し,閉じればいいのです.ということで上のコードを書き換えて

	<p align="right">
	<strong id="lays"></strong>We are using Windy API v4, Leaflet v0.7.7. <input type="button" value="END" onClick="window.close()">
	</p>


背景を黒くし,文字を白くする(2019/9/6追記)

このままだと,背景はデフォルトの白色で文字は黒色です.このままでもいいのですが,スクリーンセイバーとして考えると背景を黒く,文字は白くしたほうがいい気もします.まず背景を黒くします.
黒くするのは簡単でbodyタグにbgcolorを追加するだけです.

  <body bgcolor="black">

文字を白くする場合は新たにfontタブを使って設定します.

        <p align="right">
	<font color="white"><strong id="lays"></strong>We are using Windy API v4, Leaflet v0.7.7. <input type="button" value="END" onClick="window.close()">
	</font></p>

まとめ

今回作ったコードはこのようになります.なお邪魔なコメントは消してあります.

<html>
  <head>
    <script src="https://unpkg.com/leaflet@0.7.7/dist/leaflet.js"></script>
    <script src="https://api4.windy.com/assets/libBoot.js"></script>
  	<style>
  		#windy {
  			width: 100%;
  			height: 94%;
  		}
  	</style>
  </head>
  <body bgcolor="black">
    <div id="windy"></div>
    <script>
    const options = {
                key: 'your_key',
                verbose: true,
                lat: 38,
                lon: 139.6,
                zoom: 5,
                timestamp: Date.now(),
        }
    windyInit( options, windyAPI => {
        const { store, map } = windyAPI

        var overlays = ['rain','wind','temp','pressure','currents','waves']
        , i = 0
        , laysname = ['雨・雷',' 風 ',' 気温 ',' 気圧 ',' 海流 ',' 波 ']
        setInterval( ()=> {
                i = ( i === 5 ? 0 : i + 1)
                store.set('overlay', overlays[ i ])
                store.set('timestamp', Date.now());
                document.getElementById("lays").innerHTML=laysname[ i ];
        }, 5000)
    })
    </script>
	<p align="right">
	<font color="white"><strong id="lays"></strong>We are using Windy API v4, Leaflet v0.7.7. <input type="button" value="END" onClick="window.close()">
	</font></p>
  </body>
</html>

実際に実行するとこうなります.なお表示のため高さは300pxにしています.またズームもそれに合わせて調整しています.ボタンも無効にしてあります.


(2019/4/27追記:ここでのデモは下の追記欄で表示するため削除しました.というのもAPIの適応は1サイトに1個までみたいです.)

次回に続く



~2019/4/27追記~
お久しぶりです,HAVRMです.
次のページを作る前にWindyのAPIの更新が来たのでそれに合わせてコードを改修します.
Leafletのバージョンが0.7.7から1.4.0に上がっただけみたいなのでそれについて変更します.
コード的にはインポートする部分と最後の説明部を更新します.

<html>
  <head>
    <script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"></script>
    <!--省略-->
  </head>
  <body bgcolor="black">
  <!--省略-->
	<p align="right">
	<font color="white"><strong id="lays"></strong>We are using Windy API v4, Leaflet v1.4.0. <input type="button" value="END">
	</font></p>
  </body>
</html>

コードの更新をしただけだとなんか「使用目的をAPIのkey生成サイトで書いてください」的な文言が出てきたので
key生成サイトにとんでみると
「URL of your project or name of your application」
が必須になっていたので「windy2.scr(windows screen saver)」と記入したら表示されなくなりました.
実際に実行するとこんな感じ









We are using Windy API v4, Leaflet v1.4.0.