アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

透過がサポートされたnode-webkit(NW.js)でガジェットを作ろう

こんにちは、古見澤(コミザワ)です。
今回は、前回記事にした node-webkit が透過をサポートし始めたので、HTML5JavascriptCSSなどのWeb系の言語でガジェットのようなモノを作ってみようという内容となります。

ツイッターから情報を取得して表示するだけの単純なものですが、こんな感じのものを作れます。

動画


node-webkitって何?という方は、前回の記事も合わせてお読みください。

HTML5+CSS3+JSでネイティブGUIアプリが作れる、node-webkitを触ってみる

※本エントリーはWindows環境(Win7 Professional x64)での話になります。
(透過機能はMacLinuxでも使えます、後述するマニュアルを参照ください。)
また、Windows環境では、デスクトップウィンドウマネージャーが有効である必要があるため、
Aero機能が使えない(もしくは無効化にしている)環境ではお試しいただくことができません。


準備



まずは試してみましょう。
前回Blog執筆時の最新バージョンは 0.10.3 でしたが、ウィンドウ透過は去年11月26日にリリースされた 0.11.2 でサポートされました。
起動の仕方などは前回の記事にも書いてありますので、初めて触る人はそちらもご参照ください。

node-webkit配布元Downloadsから目的の環境に合わせたファイルをダウンロードします。
私の場合はWindowsの64bitですね。
「v0.11.5」と「0.8.6」がありますが、後者はまだ透過をサポートしていないため、試す場合は前者をダウンロードするようにしてください。

【補足】1月15日に node-webkit は Node.js から io.js にマイグレートし、NW.jsという名称に変更されました。
公式サイト
それに伴い、最新版の v0.12.0 が公開されていますが、まだalphaなので今回は v0.11.5 を使います。
昨年末くらいから一部で話題になっているNode.jsとio.jsの問題に対応しただけで、基本的に中身は変わらないみたいです。


ダウンロードが終わったら解凍し、適当なパスに配置します。
わかりやすくフォルダ名を「node-webkit-v0.11.5-win-x64」から「node-webkit」にしておきます。

動作確認用に、シンプルに最小限のファイルを準備します。
node-webkitフォルダの中に資源を格納するために、適当な名前のフォルダを作ります。
ここでは「app」にしていますが何でも構いません。別の名前にした方は適宜読み替えて下さい。

作成したappフォルダの中に「index.html」と「package.json」の2ファイルを作成します。
それぞれのファイルの中身は以下の通りです。文字コードは「UTF-8」で保存します。

index.html



<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>透過テスト</title>
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    .box {
      width: 100px;
      height: 100px;
      background-color: red;
    }
  </style>
</head>
<body>
  <div class="box">
    透過テスト
  </div>
</body>
</html>


package.json



{
  "name": "透過アプリ",
  "main": "index.html"
}


ここまで終了すると、ファイル構成は以下のような感じになります。



node-webkit
│  credits.html
│  d3dcompiler_46.dll
│  ffmpegsumo.dll
│  icudtl.dat
│  libEGL.dll
│  libGLESv2.dll
│  nw.exe
│  nw.pak
│  nwsnapshot.exe
│  pdf.dll
│
├─app
│      index.html
│      package.json
│  
└─locales
        am.pak
        ar.pak
         :
         :


では一旦ここでアプリを起動します。
appフォルダをnw.exeにドラッグ&ドロップしてもいいのですが、今回は実行時にパラメータを追加する必要が出てくるので、ショートカットを作成してそこから実行することにします。

nw.exeを右クリックして「ショートカットの作成」を選択。
更に作成したショートカットを右クリックして「プロパティ」を選択。
リンク先の内容の最後に、半角スペースで間を開けて先ほど作ったフォルダ名を追加。
(ショートカットの名前は何でも構いません、最悪そのままでも。ここではtransparentとします。)



ショートカットの準備ができたら実行します。
透過アプリという名前の、赤い正方形が描かれた白いウィンドウが出てくれば、まずは動作テスト完了です。



ウィンドウを透過させてみよう



ウィンドウを透過させる方法は、設定ファイルに記述するか、プログラムで動的に変えるかの二通りがありますが、今回は前者の紹介です。
package.jsonを、以下のように変更します。

package.json



{
  "name": "透過アプリ",
  "main": "index.html",
  "window": {
    "transparent": true
  }
}


透過設定(transparent)は、windowサブフィールドの項目の一つとして実装されています。
値はbooleanで、デフォルトは false(無効)なので true(有効)に設定します。
ファイル保存後、先ほどのテスト動作させたウィンドウが残っているなら閉じて、改めて起動してください。
赤い部分やタイトルバー、アドレス欄以外が透けたアプリが起動すれば成功です。

構文エラーに注意してください。
間違ったまま起動するとエラー画面が表示されるので、エラーメッセージを読んでカンマの有無やtypo等、確認してみてください。

透過させるには、デスクトップウィンドウマネージャー(DWM)が有効になっている必要があります。
ここで最初のテスト動作と同じウィンドウが表示される場合は、OSの設定を確認してください。

よくわかんなければ、デスクトップを右クリックし「個人設定」を選ぶとテーマの一覧が出てくるので、Aeroテーマ(のどれか)を選択すると改善される場合があります。
Aeroは重くなるから普段は切っている、という方はまず間違いなくこれに該当すると思いますので、一時的にAeroテーマに切り替えてテストしてみてください。
なお、この辺りのOS設定に関するご質問は受けられませんのでご了承ください。

ウィンドウの余計な部分を削除する



さて、背景は透明になったものの、タイトルバーやウィンドウの枠が邪魔なので消しましょう。
ついでにリサイズを出来なくして、常に最前列に表示するようにします。
package.jsonに更に記述を追加します。

package.json



{
  "name": "透過アプリ",
  "main": "index.html",
  "window": {
    "transparent": true,
    "toolbar": false,       //ツールバーを非表示に
    "frame": false,         //フレームを非表示に
    "resizable": false,     //ウィンドウのリサイズを無効化
    "always-on-top": true   //常に最前列に表示させる
  }
}


この他の記述項目についても知りたい方はマニュアルをどうぞ。

そして起動する前にもう一つ。
ツールバーを消すと、そのままではウィンドウの移動が出来なくなってしまうので、
赤い四角をドラッグしてウィンドウ自体を動かせるよう、CSSに一行追加します。

index.html



<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>透過テスト</title>
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    .box {
      width: 100px;
      height: 100px;
      background-color: red;
      -webkit-app-region: drag;  /* 追加 */
    }
  </style>
</head>
<body>
  <div class="box">
    透過テスト
  </div>
</body>
</html>


それでは起動してみましょう。
フレームやツールバー部分が消えて、ポツンと赤い四角だけ表示された状態になると思います。
そしてこの赤い四角をドラッグすることで動かせるようになっています。
-webkit-app-regionを設定する場所を考えれば、ウィンドウを動かすための「ツマミ」の実装もできます。

また、常に最前列で表示する設定にしたので、他のウィンドウを選択してもその上に表示されるようになったかと思います。

最初のサンプル動画では、透過色を設定したPNGを表示させています。
また、CSSで背景色を rgba(255, 0, 0, .5) のように指定すると半透明にも出来ます。

透過部分の背後にクリックが伝達するようにする



さて、ここまででもアレコレ作れそうな気もしますが、まだ行っていない大事なことがあります。
上のサンプルだとわかりにくいですが、実はウィンドウ自体が透明になっていても、透けて見える後ろ側をクリックすることが出来ません。
せっかく透明にしても、クリックできない領域が広がっていては使い勝手悪いですよね。

そんな透過部分のクリックを背後に伝達できる設定(click-through)が、去年の12/24にリリースされたバージョン 0.11.4 で可能となりました。
但し、この記事を書いている時点でサポートしているのはWindowsmacのみで、Linuxについては完全にサポートはされていません。

さて肝心のclick-throughのやり方ですが、これまでの設定ファイルに記述するものとは違い、今回は実行時にパラメータを指定します。



 --disable-gpu --force-cpu-draw


冒頭の方で作ったショートカットを編集すると、こんな感じになります。



また、click-throughは「フレーム無し」で「リサイズ不可」なウィンドウのみ、サポートしています。
また先ほど書きましたが、「現時点ではOSXWindowsのみ」のサポートとなっています。
Linux環境は、「環境や設定によっては動くかも知れない」としており、issueでディスカッションされています。
透過についてはここ数ヶ月の間に次々と対応されていることもあり、今後の動きに期待です。

冒頭のサンプル



ここまでの設定で、ガジェットのようなものを作る土台は大体揃ったのではないかと思います。
まずは透過設定を一度オフにして、ウィンドウの大きさを確認しながら作るとやりやすいかもしれません。

以下、Blog用に何か動くものをと、急ごしらえしたソースです。稚拙なコードですが、参考にどうぞ。
キャラクター表示しているdivを1個、吹き出し用のdivを1個置いただけのシンプルな内容です。

せっかくnodeが使えるので、twitをインストールして、TwitterのStreamingAPIを利用してみました。
単に文字が表示されるだけでは面白くないので、動きを出すためにキャラクターに喋らせてみました。
(キャラクター画像はキャラクターなんとか機をお借りしました。)
某デスクトップマスコットみたいですが、まぁこんなのも作れますよということで一つ。

index.html



<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>sample app for node-webkit</title>
  <script src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
  <style>
    body {
      overflow  : hidden;
      margin  : 0;
      padding  : 0;
      height  : 100%;
    }
    #character {
      -webkit-app-region: drag;
      position  : absolute;
      right  : 0;
      top  : 0;
      width  : 300px;
      height  : 400px;
    }
    .default {
      background  : url(character/default.png) no-repeat right bottom;
    }
    .angry {
      background  : url(character/angry.png) no-repeat right bottom;
    }
    .talk {
      background  : url(character/talk.png) no-repeat right bottom;
    }
    #comment {
      font-family  : "メイリオ";
      position  : absolute;
      left  : 10px;
      top  : 100px;
      width  : 300px;
      padding  : 10px;
      background-color  : rgba(255,255,200,1);
      border  : solid 2px #660000;
      border-radius: 10px;
    }
    #comment:before {
      content: '';
      position: absolute;
      border-left: solid 20px #660000;
      border-top: solid 13px transparent;
      border-right: solid 10px transparent;
      border-bottom: solid 7px transparent;
      top: 20px;
      right: -30px;
    }
    #comment:after {
      content: '';
      position: absolute;
      border-left: solid 18px rgba(255,255,200,1);
      border-top: solid 11px transparent;
      border-right: solid 8px transparent;
      border-bottom: solid 5px transparent;
      top: 22px;
      right: -26px;
    }
  </style>
  
  <script>
    //ウィンドウを右下に配置(マルチディスプレイは今回考慮せず)
    var gui = require('nw.gui');
    var win = gui.Window.get();
    win.moveTo(
      window.screen.availWidth - win.width,
      window.screen.availHeight - win.height
    );
    
    var commentTimer = null;
    
    // TwitterのStreamingAPIの利用部分。
    var Twit = require('twit');
    var T = new Twit({
        consumer_key:         '(この部分はご自分のアプリケーション設定に置き換えます)'
      , consumer_secret:      '(この部分はご自分のアプリケーション設定に置き換えます)'
      , access_token:         '(この部分はご自分のアプリケーション設定に置き換えます)'
      , access_token_secret:  '(この部分はご自分のアプリケーション設定に置き換えます)'
    });
    var stream = T.stream('statuses/filter', { track: 'ニュース' }); //ひとまず「ニュース」をキーワードに設定
    
    stream.on('tweet', function (tweet) {
      var data = tweet.text;
      $('#character').attr('class', 'talk');
      $('#comment').text(data).fadeIn();
      
      if (commentTimer) {
        clearTimeout(commentTimer);
        commentTimer = null;
      }
      commentTimer = setTimeout(function(){
        $('#comment').fadeOut();
        $('#character').attr('class', 'default');
      }, 3000);
    });
  </script>
</head>
<body>
  <div id="character" class="default"></div>
  <div id="comment" style="display:none;"></div>
</body>
</html>


package.json



{
  "name": "sample-app",
  "main": "index.html",
  "single-instance": true,
  "window": {
    "transparent": true,
    "toolbar": false,
    "frame": false,
    "resizable": false,
    "always-on-top": true,
    "width": 600,
    "height": 400
  }
}


フォルダ構成はこんな感じになってます。



node-webkit
│  index.html
│  package.json
│  
├─character (キャラ毎にフォルダ作ればスキン変更ができそう)
│      angry.png
│      default.png
│      talk.png
│      
└─node_modules
    └─twit
        │
         :(以下、twitインストールで格納されるファイル)


なお、画像等の素材や、npmでインストールするファイルはご自分でご用意ください。

HTMLやJavascriptは知ってるけどnodeとか触った事ない……という人がこのサンプルでつまづきそうな事を列挙しておきます。
長くなってしまうのでここでは詳しく解説しませんが、どういう事柄を調べればいいのか参考にしてください。

・node.jsやnpmの導入のやり方、npm installのやり方 等
・TwitterAPIを使うための、Twitter Developersへの登録 トークンの作成等
・twitの使い方
・サーバサイドスクリプトの書き方

最後に



今回の透過に関する設定などは、公式のドキュメントからでも見る事ができます。
最近よく更新されているみたいなので、時々目を通すといいかもしれません。

node-webkitでは、HTMLやJavascriptといったWeb開発の技術がそのまま使える事に加え、node.jsで割と突っ込んだコードを書けるため、アイデア次第でとてもいいものが作れるのではないかと思っています。
特に今回紹介した、透過に関する機能がサポートされてグンと化けた感じがします。
特別なアプリをインストールする必要も無く、作り終えたアプリもソースを圧縮すれば簡単に手渡せる気楽さもあるので、意欲がある方は自作アプリを作って公開などしてみてはいかがでしょうか。

HTML5+CSS3+JSでネイティブGUIアプリが作れる、node-webkitを触ってみる

こんにちは、古見澤です。
アルバイト時代以来となるので、実に7年ぶりの投稿となります。今後共よろしくお願いします。
久しぶりに技術畑に帰ってきたためブランクを取り戻すのに苦労していますが、鉄板の技術から胡散臭い(褒め言葉)新技術まで、色々なことが体験できる環境は楽しいですね。

さて、今回はプライベートで少し node-webkit を触る機会があったので、その紹介記事となります。

node-webkitとは



node-webkitChromium と node.js ベースで作られた、GUIアプリを動作させるランタイムです。
アプリはHTMLやJavascriptで記述を行い、作ったアプリはLinuxMac OS XWindowsで動作が可能です。

配布元:https://github.com/rogerwang/node-webkit

node-webkitを利用したアプリケーションのリストを見ると、どんなものが作れるかが伝わると思います。
他のWebアプリとのマッシュアップに利用したり、ローカルファイルを編集・管理するために利用したり、音楽プレイヤーを作ったりと、利用用途は様々です。

まずは動かしてみよう



※ここからはPCの都合上、Windows環境(Win7 x64)の話になります。他の環境ではアプリ実行方法が若干異なります。詳しくは How to run apps をご参照ください。作成するhtml等の資源は同じです。


まずは配布元にもあるクイックスタートを動かしてみましょう。
githubにアクセスし、少し下がった所にあるDownloadsを確認します。



目的やご自分の環境に応じたファイルをダウンロードします。私は新機能を試す目的もあったので v0.10.3をダウンロードしました。
ダウンロードしたら解凍して、出てきたフォルダを適当なパスに配置します。
フォルダ構成は以下のようになっているはずです。(解凍してできたフォルダはnode-webkitにリネームしました)



node-webkit
│  credits.html
│  ffmpegsumo.dll
│  icudtl.dat
│  libEGL.dll
│  libGLESv2.dll
│  nw.exe
│  nw.pak
│  nwsnapshot.exe
│  
└─locales
        ○○.pak
        :
        :

(※0.8.6をダウンロードした場合、localesフォルダが無かったりicudtlがbatではなくdllだったりしますが、今回は気にしないで大丈夫です。)

さて、アプリを動作させるために、これから2つのファイルを作成します。
ですがその前に、それらを格納するためのフォルダを準備しておきましょう。

node-webkit直下に「app」というフォルダを作ります。(フォルダ名は何でも構いません。)
そしてそのフォルダの中に「index.html」と「package.json」の2ファイルを作成します。
それぞれのファイルの中身は以下の通りです。

index.html



<!DOCTYPE html>
<html>
<head>
  <title>Hello World!</title>
</head>
<body>
  <h1>Hello World!</h1>
  We are using node.js <script>document.write(process.version)</script>.
</body>
</html>


package.json



{
  "name": "nw-demo",
  "main": "index.html"
}


ここまで終了すると、フォルダ構成は以下のようになっているはずです。



node-webkit
│  credits.html
│  ffmpegsumo.dll
│  icudtl.dat
│  libEGL.dll
│  libGLESv2.dll
│  nw.exe
│  nw.pak
│  nwsnapshot.exe
│  
├─app              ←追加したフォルダ
│      index.html   ←追加したファイル
│      package.json ←追加したファイル
│  
└─locales
        ○○.pak
        :
        :


これでアプリケーション実行の準備ができました。簡単ですね。

さて次はアプリケーションを実行します。
実行のやり方はいくつかあるのですが、わかりやすいやり方としては以下の通り。
エクスプローラーでnode-webkit直下を開く
・「appフォルダ」をドラッグ&ドロップで「nw.exe」に落とす



アプリケーションが起動し、HelloWorld の文字とバージョンが表示されると思います。
これで基本サンプルが動作しました。



(補足)コマンドラインからappフォルダをパラメータにnw.exeを実行でも構いません。


~~\node-webkit>nw.exe app





node.jsが使える



index.htmlの中にある


<script>document.write(process.version)</script>

の記述に「おや?」と思われた方がいるかもしれませんが、node-webkitではこの process.version のように
htmlのscript要素にnode.jsを利用したプログラムを書く事ができます。

試しに index.html を以下のように変更(文字コードUTF-8)してから、アプリを起動してみましょう。

index.html



<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>node-webkitを試す</title>
  </head>
  <body>
  <script>
    var fs = require('fs');
    
    fs.readFile('package.json', function (err, data) {
      if (err) throw err;
      document.write(data);
    });
  </script>
  </body>
</html>

(起動したアプリケーションがまだ開いている場合は、一度閉じてから再度起動させてください。)
起動は先ほどと同じく、「appフォルダ」を「nw.exe」にドラッグ&ドロップです。



node.jsのFile Systemを利用して、同階層においてあるpackage.jsonの中身をそのまま表示しています。
サーバサイドで書くJavascriptのような記述をhtmlのscript内に書くのは違和感があるかもしれませんね。

またこのpackage.jsonですが、このファイルの記述を変えることで起動するアプリの外観やサイズなどを制御することもできます。
どのような項目があるかはwikiManifest format をご参照ください。




さてもう一例、今度はHTTPサーバを立ててみましょう。index.htmlを以下のように変更します。

index.html



<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>node-webkitを試す</title>
  </head>
  <body>
  <script>
    var http = require('http');
    var server = http.createServer();

    server.on('request', function(req, res) {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end("connect");
      new Notification("リクエストがありました。");
    });

    server.listen(8888);
  </script>
  </body>
</html>

変更が終わったら、またいつものようにappフォルダをnw.exeにドラッグ&ドロップです。
(ドラッグ&ドロップが面倒だったらコマンドを書いたbatを作成し、実行してもいいですね)

アプリケーションが起動している間、8888ポートで要求を受け付けた状態となります。
適当なブラウザからアクセスしてみましょう。
ブラウザにはconnectという文字が表示され、「リクエストがありました。」というデスクトップ通知が現れると思います。
※デスクトップ通知は、node-webkit v0.10.1 からサポートされました



この他、npmでインストールした追加モジュールも使用することができます。




Native UI APIを試す



node-webkitには、Native UI APIというものが用意されています。
その名の通り、ネイティブに動作するUIコントロールを操作するためのもので、これらのAPIを通してアプリ上にメニューを作成したり、クリップボードを利用したり、シェルを実行できたりします。
以下は、APIを使った一例です。

index.html



<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>node-webkitを試す</title>
</head>
<body style="background-color:#fa5;">
  <h1>Native UI APIを使う</h1>
  <script>
    var gui = require('nw.gui');
    var win = gui.Window.get();

    var menu = new gui.Menu();
    var mSubMenu = new gui.Menu();

    //サブメニュー1
    mSubMenu.append(
      new gui.MenuItem({
        label: "sample 1",
        click: function() {
          gui.Shell.openItem('C:/Users/Public/Music/Sample Music/Sleep Away.mp3');
        }
      })
    );
    //サブメニュー2
    mSubMenu.append(
      new gui.MenuItem({
        label: "sample 2",
        click: function() {
          gui.Shell.openItem('C:/Users/Public/Music/Sample Music/Kalimba.mp3');
        }
      })
    );

    //メインメニュー(大きく3つ。1個目と2個目の間にセパレータを挿入)
    menu.append(new gui.MenuItem({ label: '音楽', submenu: mSubMenu}));
    menu.append(new gui.MenuItem({ type: 'separator' }));
    menu.append(
      new gui.MenuItem({
        label: "キャプチャ(別窓)",
        click: function() {
          takeSnapshot();
        }
      })
    );
    menu.append(
      new gui.MenuItem({
        label: "キャプチャ(出力)",
        click: function() {
          saveSnapshot();
        }
      })
    );

    //メニュー表示
    function popMenu() {
        menu.popup(70, 80);
    }

    //スナップショットを別ウィンドウで表示
    function takeSnapshot() {
      win.capturePage(function(img) {
        var popWindow = gui.Window.open('popup.html', { width: 480, height: 270 });
        popWindow.on('loaded', function() {
          var image = popWindow.window.document.getElementById('image');
          image.src = img;
        });
      }, { format : 'png' });
    }

    //スナップショットをファイルとしてサーバ上に保存
    function saveSnapshot() {
      win.capturePage(function(img) {
        require("fs").writeFile("out.png", img, 'base64', function(err) {
          console.log(err);
        });
      }, { format : 'png', datatype : 'raw' });
    }
  </script>

  <button onclick="popMenu()">menu</button>
</body>
</html>


そしてindex.htmlと同じ階層に、popup.htmlを以下の内容で作成します。

popup.html



<html>
  <head>
    <title>Popup window</title>
  </head>
  <body>
    <img id="image" alt="snapshot"/>
  </body>
</html>


一気にコード量が多くなりましたが、ほとんどがメニュー作成部分で中身は大した事はやってません。ゆっくり見て行きましょう。

この画面から使える機能は大きく2つ、「曲の再生」と「スクリーンショットの撮影」です。



21行目と30行目、openItemは引数のファイルを開くShellのメソッドです。
ここではWindowsに入っていたサンプルの音楽ファイルを指定しています。
拡張子に紐付けられているプログラムで実行されるため、起動するアプリケーションは環境によって異なります。また、txtファイルを指定したらメモ帳やエディタが開いたり、xlsxファイルを指定したらExcelが起動したりします。

62~68行目と72~78行目、capturePageはウィンドウ上の可視範囲をキャプチャするメソッドです。
キャプチャした画像フォーマットはjpegpngを選択でき、そのファイルをrawデータとして利用したり、保存場所のURIを使ってimg要素のsrcに利用が可能です。
今回のサンプルプログラムでは、メニューから「キャプチャ(別窓)」を選ぶと別ウィンドウがポップアップし、そこにメインウィンドウのスクリーンショットが埋め込まれて表示されます。
また「キャプチャ(出力)」を選ぶと、画面上では何も起こらないのでわかりにくいですが、メインウィンドウのスクリーンショットが、index.htmlと同じ階層に「out.png」というファイルが作成されます。



このサンプルでは、以下のAPIを利用しています。横の補足はこのプログラム内での用途です。

  • Menu ボタン押下後に表示されるメニュー

  • MenuItem メニューの見た目やクリック時の動作等

  • Window 画面キャプチャー、別窓の表示

  • Shell ファイル実行(音楽再生)


それぞれ色々な機能があるので、おもちゃの如く色々触りたくなってしまいますね。




アプリを配布する



作ったアプリを配布する時は、フォルダ構成そのままを受け渡す方法もありますが、一つの実行ファイルにまとめてしまうやり方もあります。この場合は
・必要な資源をzip圧縮して1つにする。
・node-webkitフォルダの直下にあった「nw.exe」と、↑で圧縮したファイルを結合する。
となります。

今回の例で言うと、まず「app」フォルダの中身を1個のzipに固め、拡張子を「.nw」にします。
(解凍時にpackage.jsonがルートに来るように圧縮する必要があるため、appフォルダ自体をzip化してはダメです。)

次に、コマンドプロンプトからcopyコマンドを使い、node-webkitフォルダの直下にあった「nw.exe」と、今作った「.nwファイル」を、バイナリファイルとして(/bをつけて)結合します。
これで完成です。




OS環境や作成したプログラムの内容に応じて、実行ファイルと一緒にnode-webkitフォルダの中のファイルを同梱する必要があります。
どのファイルを同梱する必要があるかは、配布元の解説を参照してください。





最後に



いかがだったでしょうか。
今回は紹介ということで動作は単純・見た目も地味なアプリでしたが、導入から動作、配布への流れくらいは伝えられたなら幸いです。

開発をやっているとわかるのですが、DevToolが普通に備えられているのはなかなか便利です。デバッグのやり方を重要視する方にとっては朗報かもしれません。

jsファイルの呼び出しが、HTMLからなのかnode.jsからなのかがわかりにくい点が少し開発をやっていてつまづきましたが、Webサイトを作るような感じで自分好みのツールが作れるのはなかなか新鮮でした。
特別に何かをインストールしたりすること無く動作するのも魅力的です。

ここに載せられなかった細かい決まり事や注意点、API情報などは配布元のwikiをご参照ください。

【ほぼ網羅】CSS3だけでアニメーションを実装する方法のまとめ

こんにちは、橋本です。

今日は備忘録がてら、CSS3のアニメーションについてまとめていきたいと思います。
iOS端末でFlashが動作しないことから、今後CSS3でアニメーションを実装する場面は増えてくると思います。
そんなときにこの記事を参考にしてもらえると幸いです。

今回の記事に記載されているサンプルですが、Safari、もしくはChromeで動作するようになっています。
IEFirefoxOperaなどの他のブラウザは対象外です。
(なぜなら、ベンダプレフィックスを書くのがめんどくさかったからです。)


早速ですが、CSS3でアニメーションを実装するためには、以下の2つの方法があります。

  1. 1. transitionプロパティでアニメーションを定義する

  2. 2. animationプロパティでアニメーションを定義する


また、アニメーションを定義する際には、通常のプロパティに加えてtransformプロパティを定義することによって、
より動きのあるアニメーションを定義することも可能です。
今回は、上記の2つのアニメーションの定義の方法に加えて、transformプロパティの使用方法についても見ていきたいと思います。


transitionプロパティでアニメーションを定義する


まずは、transitionプロパティでアニメーションを定義する方法です。

transitionプロパティは、開始時の状態と、終了時の状態を定義して使用します。
開始時と終了時を定義する方法には、以下の二種類があります。

  1. 1. hoverなどの擬似クラスを使用する方法

  2. 2. javascriptを使用して、CSSのプロパティを変更する方法


transitionでアニメーションを定義する際に、以下の4つの項目を指定することができます。

  1. 1. アニメーションにかかる時間

  2. 2. 対象のプロパティ

  3. 3. イージング

  4. 4. 遅延時間


この4つのプロパティはtransitionプロパティでまとめて定義することも出来ますし、個別に設定することも可能です。

まず、transitionプロパティを用いて、まとめて指定する方法ですが、以下の形式で設定を行います。

transition: アニメーションにかかる時間 対象のプロパティ イージング 遅延時間;

例:


transtion: 0.5s background-color linear 1s;

各プロパティは順不同で記載することが可能ですが、アニメーションにかかる時間と遅延時間の順序だけは逆にすることができません。
また、各プロパティは省略可能で、省略した場合の初期値は以下のとおりとなります。

  • ・アニメーションにかかる時間: 0s

  • ・対象のプロパティ: all

  • ・イージング: ease

  • ・遅延時間: 0s


transitionについては、複数の設定をカンマ区切りで同時に指定することも可能です。
また、後で出てくる個別に項目を設定するプロパティについても、カンマ区切りで複数同時に指定することが可能です。

例:


transtion: 0.5s background-color linear 1s, 1s height linear;
transtion-duration: 0.5s, 1s;


では、各項目について詳しく見ていきたいと思います。

まずはアニメーションにかかる時間ですが、秒単位(s)、もしくはミリ秒単位(ms)で指定します。
例えば、1秒だと1sもしくは1000ms、0.5秒だと0.5sもしくは500msといった風に設定します。

例:


transiton: 0.5s;

アニメーションにかかる時間はtransition-durationプロパティで個別に設定することが可能です。

例:


transition-duration: 0.5s;


次に対象のプロパティですが、このプロパティは特定の要素にのみtransitionを適用したいときに指定します。
指定しない場合には、all(すべての要素を対象とする)を指定したのと同様に扱われます。

例:


transtion: 0.5s background-color;

対象のプロパティはtransition-propertyプロパティで個別に設定することが可能です。

例:


transition-property: background-color;

ちなみに、特定のプロパティをtransitionで指定した場合、指定されていないプロパティにはアニメーションが適用されず、
瞬時に変更後の値が適用されます。

例えば、以下の例の場合、background-colorは1秒間のアニメーションで色が変化しますが、
heightとwidthは一瞬で変化します。


div {
    height: 50px;
    width: 50px;
    background-color: #000;
    -webkit-transition: 1s background-color;
}

div::hover {
    height: 100px;
    width: 100px;
    background-color: #fff;
}


次にイージングですが、イージングはアニメーションの変化のパターンのこと言います。
具体的には以下の値を設定することが可能です。

  • ・ease(開始時点と終了時点を滑らかに再生する)

  • ・linear(一定の間隔で再生する)

  • ・ease-in(開始時点をゆっくり再生する)

  • ・ease-out(終了時点をゆっくり再生する)

  • ・ease-in-out(開始時点と終了時点をゆっくり再生する)


この他に、cubic-bezier関数を使って、イージングを独自に設定することも可能です。
以下の例はeaseと同じイージングをcubic-bezier関数を使って設定する例です。

例:


transition: 1s cubic-bezier(0.25, 0.1, 0.25, 1.0);

cubic-bezierについては、以下のリンクが参考になるかと思います。
Cubic Bezier timing function compatible with -webkit-transition-timing-function

イージングはtransiton-timing-functionプロパティで個別に設定することが可能です。

例:


transition-timing-function: linear;


最後に遅延時間です。
遅延時間を設定すると、設定した時間分アニメーションの開始を遅らせることができます。
遅延時間にはアニメーションにかかる時間と同様に、秒単位(s)もしくはミリ秒単位(ms)で時間を設定します。

遅延時間はtransiton-delayプロパティで個別に設定することが可能です。

例:


transition-delay: 1s;


簡単なtransitionのサンプルです。
実際に動きを確認してみてください。
サンプル

animationプロパティでアニメーションを定義する


次に、animationプロパティでアニメーションを定義する方法を見ていきたいと思います。

animationでアニメーションを定義する際に、以下の6つの項目を指定することができます。

  1. 1. キーフレーム名

  2. 2. アニメーションにかかる時間

  3. 3. イージング

  4. 4. 遅延時間

  5. 5. 繰り返しの回数

  6. 6. 再生方向


animationプロパティは以下の形式で指定します。

animation: キーフレーム名 アニメーションにかかる時間 イージング 遅延時間 繰り返しの回数 再生方向;

animationプロパティではキーフレーム名が必須の設定項目となります。
キーフレーム名には、@keyframes文で定義したキーフレームアニメーションのキーフレーム名を指定します。

@keyframes文は以下の形式で定義します。



@keyframes キーフレーム名 {
    0% {
        background-color: #f00;    
    }
    50% {
        background-color: #0f0;
    }
    100% {
        background-color: #00f;
    }
}


{}の中身ですが、開始時点の状態を0%{~}、終了時点の状態を100%{~}に指定し、途中の状態を数字+%の形式で指定していきます。
開始時点の状態は0%{~}ではなくfrom{~}、終了時点の状態は100%{~}ではなくto{~}とすることも可能です。

animetionのキーフレーム名は、animation-nameプロパティで個別に設定することも可能です。

例:


animation-name: anime;

@keyframes 'anime' {
    0% {
        background-color: #000;    
    }
    100% {
        background-color: #fff;    
    }
};


アニメーションにかかる時間、イージング、遅延時間についてはtransitionと同様の設定になります。
それぞれ、以下のプロパティで個別に設定することが可能です。

  • animation-duration... アニメーションにかかる時間

  • animation-timing-function ... イージング

  • animation-delay... 遅延時間


繰り返しの回数は、アニメーションを繰り返す回数です。
デフォルトではアニメーションの再生は一回となりますが、繰り返しの回数を指定することでアニメーションを繰り返し実行することが可能です。
また、回数の代わりにinfiniteという値を設定することで、無限にアニメーションを繰り返すことも可能です。
個別に繰り返しの回数を設定したい場合には、animation-iteration-countプロパティで指定します。

例:


animation-iteration-count: infinite;

再生方向は2回以上の繰り返しのアニメーションを実行した際の2度目にあたるアニメーションの実行方向になります。
normalを指定した場合には、開始時点の状態から終了時点の状態へのアニメーションを繰り返しますが、
alternateを指定した場合には、通常の方向のアニメーションと逆再生の状態のアニメーションを繰り返し行うようになります。

再生方向を個別に指定したい場合には、animation-directionプロパティに値を設定します。

例:


animation-direction: alternate;

この他に、アニメーションの再生と一時停止を行うanimation-play-stateプロパティと遅延時間と再生後の表示状態を指定するanimation-fill-modeプロパティがあります。

animation-play-stateプロパティには、runningとpausedという値を設定することが可能です。
runningはアニメーションが実行されている状態です。pausedはアニメーションが一時停止している状態となります。
animation-play-stateがrunningに設定されている状態から、pausedに変更した場合、pausedに変更された時点の状態でアニメーションが一時停止することになります。
また、この状態でanimation-play-stateをrunningに変更すると、pausedが設定される直前の状態からアニメーションが再開されることになります。

例:


// マウスオーバー時のみアニメーションを止める場合
a::hover {
  animation-play-state: paused;
}


animation-fill-modeには、none,forwards, backwards, bothのいずれかを指定することが可能です。
noneを指定すると、遅延時間とアニメーション再生後の状態はアニメーション開始前の状態となります。
forwardsを指定すると、再生後の状態がアニメーション終了時の状態となります。
backwardsを指定すると、遅延時間の状態が、アニメーション開始時の状態となります。
bothを指定すると、遅延時間の状態がアニメーション開始時の状態、再生後の状態がアニメーション終了時の状態となります。

例:


animation-fill-mode: both;


簡単なanimationのサンプルです。
実際に動きを確認してみてください。
サンプル

transformプロパティの使い方


最後にtransformプロパティの使い方を見ていきたいと思います。

transitionプロパティの開始時と終了時の状態や、@keyframesのキーフレームの状態を定義する際に、
通常のCSSのプロパティ(height, width, background-colorなど)に加えて、transformプロパティによる変形処理を適応することで、
より高度なアニメーションを実装することが可能になります。

transformプロパティの定義方法は、以下の形式となっています。

transform: 変形処理(transform関数);

transform関数には、以下のものがあります。

  • ・座標移動(translate, translate3d, translateX, translateY, translateZ)

  • ・拡大縮小(scale, scale3d, scaleX, scaleY, scaleZ)

  • ・回転(rotate, rotate3d, rotateX, rotateY, rotateZ)

  • ・スキュー(skew, skewX, skewY)

  • ・マトリクス処理(matrix, matrix3d)

  • ・透視投影(perspective)



transformには、2D処理と3D処理があり、上記のリストで強調されている関数が3D処理の関数となっています。

では。具体的に使い方を見て行きましょう。
今回は、上記リストの上から4つの基本的なtransform関数の使い方について見ていきたいと思います。

座標移動(translate, translate3d, translateX, translateY, translateZ)


translate関数は座標移動を行うための関数です。
translate関数は引数として、X軸の移動距離、Y軸の移動距離を指定します。

例:


transform: translate(100px, 100px);


translate3d関数は、translate関数にZ軸の移動距離を加えたものです。

例:


transform: translate3d(100px; 100px; 100px);


translateX, translateY, translateZは、それぞれ、X軸、Y軸、Z軸の移動に特化した関数です。

例:


transform: translateX(100px);
transform: translateY(100px);
transform: translateZ(100px);


簡単な座標移動のサンプルです。
サンプル

拡大縮小(scale, scale3d, scaleX, scaleY, scaleZ)


scale関数は拡大縮小を行うための関数です。
scale関数は引数として、X軸の拡大縮小の倍率、Y軸の拡大縮小の倍率を指定します。

例:


transform: scale(2.0, 2.0);


scale3d関数は、scale関数にZ軸の拡大縮小の倍率を加えたものです。

例:


transform: scale3d(2.0; 2.0; 2.0);


scaleX, scaleY, scaleZは、それぞれ、X軸、Y軸、Z軸の移動に特化した関数です。

例:


transform: scaleX(2.0);
transform: scaleY(2.0);
transform: scaleZ(2.0);


簡単な拡大縮小のサンプルです。
サンプル

回転(rotate, rotate3d, rotateX, rotateY, rotateZ)


rotate関数は2D空間で時計回りに回転を行うための関数です。
rotate関数は引数として、回転する角度を指定します。
角度を指定する際にはdegという単位で指定します。

例:


transform: rotate(90deg);


rotate3d関数は、4つの引数を設定します。
最初の3つの引数で[x, y ,z]の方向ベクトルを定義し、
その方向ベクトルを元に4つめの引数で指定した角度分の回転を時計周りに行うための関数です。

例:


transform: rotate3d(1, 1, 0, 180deg);


rotateX, rotateY, rotateZは、それぞれ、X軸、Y軸、Z軸を元に回転処理を行う関数です。
引数には、回転する角度を指定します。

例:


transform: rotateX(90deg);
transform: rotateY(90deg);
transform: rotateZ(90deg);


簡単な回転のサンプルです。
サンプル

スキュー(skew, skewX, skewY)


skew関数は対象の要素の座標を歪ませる関数です。
skew関数は引数として、X軸の傾斜角度、Y軸の傾斜角度を指定します。

例:


transform: skew(90deg, 90deg);

上記の例では、対象の要素の座標軸が、X軸方向に90度、Y軸方向に90度の傾いた状態になります。
実際に適用した状態は、後で記載するサンプルで確認してもらえるとわかりやすいかもしれません。

skewX, skewYは、それぞれ、X軸、Y軸の座標の歪みに特化した関数です。
例:


transform: skewX(90deg);
transform: skewY(90deg);


簡単なスキューのサンプルです。
サンプル

transformの原点について


transform関数で指定した変形処理は、対象の要素の中心座標を原点として適用されます。
具体的には、X軸が50%、Y軸が50%、Z軸が0の位置が初期値となっています。

transform-originプロパティを用いることで、この中心座標を変更することが可能です。
transform-originプロパティには、X座標の位置、Y座標の位置、Z座標の位置を引数として渡すことができます。
引数は、%で指定することも可能ですし、px単位で指定することも可能です。
また、以下のキーワードで指定することも可能です。

  1. ・left(X座標の位置に0%を指定するのと同じ)

  2. ・right(X座標の位置に100%を指定するのと同じ)

  3. ・center(X座標、もしくはY座標の位置に50%を指定するのと同じ)

  4. ・top(Y座標の位置に0%を指定するのと同じ)

  5. ・bottom(Y座標の位置に100%を指定するのと同じ)


例:


transform-origin: 10% 10% 0;


簡単な原点変更のサンプルです。
サンプル

iOS端末上でのtransform処理について


iOS上でtransform処理を使ってアニメーションを実装する際には、2D処理を実装する場合でも3D処理の関数を使うようにします。
なぜかといいますと、iOS端末では、3D処理の関数を使う場合のみ、GPUアクセラーレーションが効くようになっているためです。
GPUアクセラレーションが効く場合と効かない場合では、アニメーションの滑らかさに天と地ほどの差が出ますので、必ず3D処理の関数を使うようにしてください。

例:


    // Z軸の処理に0を入れて2Dの処理にする
    -webkit-transform: translate3d(10px, 10px, 0); 


また、iOS端末ではアニメーションを実行した際に画面にチラつきが出る場合があります。
このチラつきをなくすためには、以下のようにアニメーションに関する項目全てに3D処理を入れてGPUアクセラレーションを効かせることで解決します。

例:


.animation {
    -webkit-transform:translate3d(0,0,0);
}


上記の現象については、以下の記事が参考になるかと思います。
GPUアクセラレーターが使える環境で強制的に有効にできるCSSの指定方法


かなり長くなってしまいましたが、CSS3のアニメーションについてほぼ網羅できたのではないかと思います。
この記事を参考に、実際にCSS3アニメーションを使っていろいろと遊んでみてください!