こんにちは、ポキオ(@pokiiio)です。IoTLT Advent Calendar 2018の12日目を担当させていただきます。
tl;dr
京浜急行の運行情報を監視するアプリをElectronで書きました。Electronなので、macOSでもWindowsでもきっと動くはずです。Node環境(当方はv8)があればすぐに使えますので、ぜひお使いください。
上記リポジトリからソースをClone or Downloadして、
npm install
で必要なファイルをダウンロードし、
npm start
で起動します。また、パッケージ化したい場合は、
npm run build-macOS
で可能です。Windowsユーザーの方は、build-macOSの部分をbuild-windowsに変えて実行してみてください。
この期に及んでなぜElectron?
いままでIoTLTを中心に登壇させていただきましたが、それを同時に京急にまつわるガジェットをたくさん作成してまいりました。ご縁もありMakerFaireTokyo2018でも展示させていただきました。
ただ、物理的なガジェットの最大の欠点として、持ち歩くのが面倒という点が挙げられます。
そこで、今回は物理的なガジェットではなく、京急に関するデスクトップアプリを作りました。その実現方法として、いちばん最短ルートっぽかったのがElectronだったので、その紹介もさせてください。
勤務先のデスクには、過去作成したガジェットをいくつかおいてありますが、たとえばミーティングのために別の部屋に移動した際に、ガジェットを持っていくのは面倒です。でも、京急をつねに肌で感じていたい。そこでたどり着いたのがパソコン上で動作するデスクトップアプリでした。
Electronとは
ちょっと雑ですが、HTML+CSS+JSでクロスプラットフォームなデスクトップアプリが書ける仕組み、というふうに理解しています。豊富なnpmモジュールを使えるので便利な一方、BootstrapなどオサレなUIコンポネントも使えるので、ちゃちゃっとデスクトップアプリがかけてしまうのです。
つくったもの
これ。
(表示内容はダミーです)
京急の運行情報を定期的に取得し、遅延などが発生しているときはデスクトップ上部に情報を表示するというものです。普段はアプリを起動しっぱなしにしておくのですが、何も表示されません。
技術的なポイント
以下の3つです。
- 京急の運行情報取得方法
- 運行情報だけを表示させる
- マルチスクリーン対応
京急の運行情報取得方法
これに関しては、今までのガジェット作成のノウハウがふんだんに(?)使われています。基本的には京急の情報ページ( http://unkou.keikyu.co.jp/ )から取得してくるのですが、
<div class=unko-panel>
京急線は平常通り運転しています。
</div>
運行情報はunko-panelのdivで囲まれています。したがって、JSでこれをパースするには、よしなにrequest-promiseとかでbody全体を取得した後に、
let info = body;
info = info.split('<div class=unko-panel>')[1];
info = info.split('</div>')[0];
info = info.trim();
return info;
こんな感じでゴリゴリパースすると、簡単に運行情報が取得できます。
運行情報だけを表示させる
通常、Electronアプリを作成して実行すると、Windowとして表示されてしまうので(あたりまえですが)、Windowを透明にしたり、メニューバーなども非表示にしてあげることで、あたかも運行情報だけが表示されてるかのように表現することができます。
具体的には、BrowserWindowをnewするときに、オプションで以下のパラメータを与えてあげます。
width: size.width,
height: size.height,
// where size is display size.
frame: false,
transparent: true,
resizable: false,
alwaysOnTop: true,
-
width・heightには表示しようとしているディスプレイのサイズを与えて、全画面表示をする -
frameをfalseにしてウィンドウのタイトルバーを非表示する -
transparentをtrueにして、Windowを透明にする -
resizableをfalseにして、常に全画面表示とする -
alwaysOnTopをtrueにして、常に最前面に表示されるようする
ただし、最後のalwaysOnTopをtrueにしてしまうと、クリックイベントをすべてこのElectronアプリが奪ってしまうことになるので、下記のようにクリックイベントを下のレイヤーにスルーパスして上げる必要があります。
window.setIgnoreMouseEvents(true);
マルチスクリーン対応
仕事では、外部ディスプレイに接続してマルチスクリーンで仕事をすることも多いと思います。アプリでも、スクリーン数の変化を検知して、すべての画面に運行情報を表示できるようにしています。
electron.screen.on('display-added', function () {
...
});
electron.screen.on('display-removed', function () {
...
});
こんな感じでelectron.screenがEmitするイベントを受けるだけ。これをうけて、electron.screen.getAllDisplays()とかすると、接続中の画面がすべて取得できるので、それぞれの画面に対してBrowserWindowをnewして表示さればOK。
ただし「このDisplayに、このBrowserWindowを表示する!」みたいな便利なオプションはないので、画面の絶対座標を指定して、BrowserWindowをnewして上げる必要があります。
let window = new BrowserWindow({
x: display.bounds.x,
y: display.bounds.y,
...
});
サマリ
今回は、Electronでアプリを作ってみました。簡単にデスクトップアプリが作成できるので、みなさんもオレオレアプリを作ってはいかがでしょうか?