Electronでデスクトップいっぱいに雪を降らせるアプリを作る

メリークリスマス！
Electronでデスクトップ全画面に表示させるアプリを作ってみたいなぁと思い、時期が時期なので全画面に雪降るアプリを作成してみました。

環境：OS X EL Capitan(10.11.2)、electron-prebuilt v0.36.1、node v5.1.0、TypeScript v1.7.3

[![https://gyazo.com/ca936dd27cb778c6e8fced57d49c1722](https://i.gyazo.com/ca936dd27cb778c6e8fced57d49c1722.gif)](https://gyazo.com/ca936dd27cb778c6e8fced57d49c1722)

# ソースコード
[nyamogera/electron-christmas - GitHub](https://github.com/nyamogera/electron-christmas)

# 実装内容
画面全体に透明なウィンドウを表示して、Canvasを使用して丸い白い円を上から下に向かって左右に揺らしながら動かしました。

# 抑えておくコード
## Macで透明な部分のマウスのクリックを検知させないようにするコード

BrowserWindowの`setIgnoreMouseEvents()`関数を使用して、レンダラー上の透明部分のクリックイベントを発生させないようにします。こうすることで画面の一番上に表示させても背部に回ったウィンドウをクリックさせることが出来ます。

> mainWindow.setIgnoreMouseEvents(true);

```index.js
"use strict";
var electron = require("electron");
var app = electron.app;
var BrowserWindow = electron.BrowserWindow;
app.on('ready', function () {
    var Screen = require('screen');
    var size = Screen.getPrimaryDisplay().size; // ディスプレイのサイズを取得する
    var mainWindow = new BrowserWindow({
        left: 0,
        top: 0,
        width: size.width,   // 最大サイズで表示する
        height: size.height, // 最大サイズで表示する
        frame: false,      // ウィンドウフレームを非表示に
        show: true,
        transparent: true, // 背景を透明に
        resizable: false,
        'always-on-top': true // 一番手前に表示する
    });
    // 透明な部分のマウスのクリックを検知させない
    mainWindow.setIgnoreMouseEvents(true);
    mainWindow.maximize();
    mainWindow.loadURL('file://' + __dirname + '/index.html');

    mainWindow.on('closed', function () {
        mainWindow = null;
    });
});
```


## 背景を透明にするCSS
HTML上の背景を透明にして、Canvasを画面いっぱいに配置します。

> background-color: rgba(0, 0, 0, 0.0);

```index.html.css
html {
    height: 100%;
    width: 100%
}
body {
    margin: 0;
    height: 100%;
    width: 100%;
    background-color: rgba(0, 0, 0, 0.0);
}

canvas {
    height: 100%;
    width: 100%;
}
```

## 雪を降らせる
画面の上からゆらゆらと落ちてくるコードです。

``` Main.ts

// 雪を新規で作成する
private createSnow = () => {
    for (var i = 0; i < 100; i++) {
        var snow = new Snow();
        this.snowList.push(snow);
        // 画面の横いっぱいに雪を降らせる
        snow.baseX = this.myCanvas.width * Math.random();
        // 初期の雪の位置は、画面内から表示させるのではなく、画面の上部から発生させる
        snow.y = this.myCanvas.height * Math.random() - this.myCanvas.height;
    }
}
// ブラウザの更新タイミングで呼ばれる(更新)
public update = () => {
    let snowListLength = this.snowList.length;
    for (var i = 0; i < snowListLength; i++) {
        var snow:Snow = this.snowList[i];
        // 一定のスピードで下に落ちる
        snow.y += snow.dy;
        // 左右に揺らすために雪に時間を与える
        if (snow.y >= -snow.size) {
            snow.frame += 0.1;
        }
        // 画面外に移動したら、一番上に移動する
        if (snow.y >= this.myCanvas.height + snow.size) {
            snow.y -= this.myCanvas.height - snow.size;
            snow.baseX = this.myCanvas.width * Math.random();
        }
    }
}
// ブラウザの更新タイミングで呼ばれる(描画)
public draw = () => {

    this.context2d.clearRect(0, 0, this.myCanvas.width, this.myCanvas.height);
    this.context2d.fillStyle = "rgb(255,255,255)";

    let snowListLength = this.snowList.length;
    for (var i = 0; i < snowListLength; i++) {
        var snow:Snow = this.snowList[i];
        this.context2d.beginPath();
        this.context2d.arc(snow.x, snow.y, snow.size, 0, Math.PI * 2, false);
        this.context2d.fill();
        this.context2d.closePath();
    }
}
```

# もともと作りたかったもの
本当はもうちょっと凝った作りにしたくて、ウィンドウの上に雪を積もらせるようなコードを書いてみたかったのだけれども、どうも他のプロセスで動いているウィンドウの位置を取得するようなAPIが見つからず断念した。

## ウィンドウの位置を取得したくて探したところ
- [electron/api - GitHub](https://github.com/atom/electron/tree/master/docs/api) 

- [electron/desktop-capture.md - GitHub](https://github.com/atom/electron/blob/master/docs/api/desktop-capturer.md)
 ウィンドウのサイズ取得できているのを見て、これで位置取れないかな？と思ったけれど、ウィンドウサイズや名前などは取得できるものの、残念ながら位置は取れないようでした。

- 「electron other process window」とか「node.js window process」とかでGoogle検索

- 「[TooTallNate/NodObjC - GitHub](https://github.com/TooTallNate/NodObjC)」とかで直接叩けばいけるかも？

# 参考
[Electron on Macでclick-thruを実現する - Qiita](http://qiita.com/erukiti/items/b1b90b948c0981539849)
[ElectronでGyazoっぽいUIを実現する - Qiita](http://qiita.com/uiureo/items/0353e37bcffe94731c6b)