2015/07/31

[Electron] ElectronでHello,Worldアプリを書いてみる。

はじめに

ElectronっていうAtomエディタのベースを切り離してプラットフォーム化したものがある。コレを使うと、クラスプラットフォームなデスクトップアプリケーションが、HTML、CSS、Javacriptで書けるっていうんで、使っていこうかしらと思案しています。まずは、環境を作って、Hello,Worldでも。

ちなみに、環境は、

  • ubuntu 14.04 LTS(32bit)
  • node.js v0.12.6
です。

Electronのインストール

npmでインストールする。

npm i -g electron-prebuilt

プロジェクトの初期化

プロジェクトっていうか、アプリのルートディレクリを掘って、npmコマンドで初期化する。

mkdir hello-electron && cd hello-electron
npm init

コード書く

browser(main)プロセス用のjavascriptコードと、rendererプロセスによって画面に表示されるhtmlを書く。 本家にあるコードそのままを試す。

動かしてみる

electronコマンドで起動する。

electron .
すると、Developer Toolsが有効になったChromeっぽいものが起動します。
Developer Toolsを隠すと↓みたいな。

終わりに

とりあえずウチのへっぽこPCでも動いたので、いろいろ作ってみます。

2015/03/31

Epochでリアルタイムなチャートを表示する - Gauge編

前回の記事「Epochでリアルタイムなチャートを表示する。」の続き。前回は、D3.jsベースのチャート表示ライブラリ「Epoch」を使って、時系列なラインチャート、エリアチャート、バーチャートをリアルタイムに描画する方法について書いた。今回は、Gaugeと呼ばれるチャート?を描画する方法について。

Gauge?

gaugeは、カタカナで書くなら「ゲージ」で、「計器」を意味するらしい。実際、

みたいなのが描画される。

使い方

gaugeを表示するには、

var gauge = $('#gauge-chart').epoch({
    type: 'time.gauge',
    value: 0.1
  });
のように、epochのtypeにtime.gaugeを指定する。ライン、エリア、バーと異なり、gaugeは時系列なチャートではないので、時間を指定せず、値のみ指定する。

そして、値を更新するには、

gauge.push(値);
とするだけ。これで、gauge上の針がアニメーションしながら指定した値に落ち着いていく。ここにデモがあります。にしても簡単だわ〜。

終わりに

今回はEpochでGaugeチャートの書き方を書きました。後はHeatmapが残っているので、次回あるいはその次あたりに書きたいが・・・。

2015/03/19

Epochでリアルタイムなチャートを表示する。

html上のチャート、ラインチャートとかバーチャートとか、リアルタイムに更新したい、と思って調べていたら、Epochなるライブラリを発見したので、使い方を纏めておく。

Epoch

A general purpose real-time charting library for building beautiful, smooth, and high performance visualizations.
とのこと。 で、
  • javascriptライブラリ
  • d3.jsベース
  • Line, Area, Bar, Gauge, Heatmapの各チャートをリアルタイムに表示できる
  • リアルタイムでない通常のチャートもいける
という特徴がある。

導入

Epochはjavascriptファイルとcssファイルを提供しているので、そいつらをページに引きこむ。Epoch - Getting Startedにあるようにd3.jsも忘れずに。

LineChart, AreaChart, BarChart

これらはx軸が時間、y軸は任意というチャートを描画する。見た目が違うだけでデータの構造は同じ。データの構造は、

var data = [
  { label: 'Series1',
    values: [{ time: time, y: 100 }, { time: time + 1, y: 1000 }] },
  { label: 'Series2',
    values: [{ time: time, y: 200 }, { time: time + 1, y: 200 }] }
];
という形になる。系列ごとにlabelとデータを定義して、それを配列にする。で、valuesの中のtimeは、a unix timestampである必要がある(故にEpochなのかなぁ)。で、これをEpochに与えるとチャートを表示してくれる。
<div id="line-chart" class="epoch" style="height:160px"></div>
のようなhtmlを書き、
var lineChart = $('#line-chart').epoch({
    type: 'time.line',
    data: data,
    axes: ['left', 'bottom', 'right']
  });
とすると、ラインチャートが表示される。エリアチャート、バーチャートの場合もデータの構造は同じなので、epoch関数のパラメータのtypeを、エリアチャートの場合はtime.area、バーチャートの場合はtime.barとしてやればよい。

で、初期データを食わせたチャートに、後から時々刻々とデータを追加していくことでリアルタイムなチャートになるんだけど、追加するデータの形式は、

var current = [
  { time: time, y: Math.random() * 1000 },
  { time: time, y: Math.random() * 1000 }
];
という形式になる。初期データに比べてlabelが要らない。この追加データを、
lineChart.push(current);
とするだけで、チャートが更新される。なんて楽ちんな。タイマーを使って、周期的にバックエンドからデータを取得してpushしてやるとか、WebSocketを使って、バックエンドから送りつけられたデータをpushする、といった方法でリアルタイムなチャートが表示できる。

実際に表示すると↓のようなチャートが表示される。

で、このチャート表示が動いているのがこちらになります。

終わりに

Epochを使うと、他にもGaugeとかHeatmapもリアルタイムに描画できるけど、力尽きたので次回にまわします。それにしても、Epoch便利だわ。

2015/03/05

Animate.cssで簡単にDOM要素のアニメーションを実現する。

DOM要素にfadeとかslideとかのアニメーションをつけるのに、jQueryで書くのはまあ簡単ではあるけど、Animate.cssなるcss3のアニメーションライブラリを知ったので、使い方をメモっておく。シンプルなアニメーションがすごく簡単に実現できる。

Animate.css

githubのREADME.mdには、

animate.css is a bunch of cool, fun, and cross-browser animations for you to use in your projects.
とある、つまり、クロスブラウザに対応したクールで楽しいアニメーションの束、ってことっぽい。実際、cssを取り込むだけで、いろんな種類のアニメーションが簡単に実現できちゃう。

使い方

cssをダウンロードするなり、bower install animate.cssするなりして、HTMLにcssを埋め込む。

<head>
  <link rel="stylesheet" href="path/to/animate.min.css">
</head>

で、アニメーションさせたいDOM要素にclass属性を与えてやる。と。例えば、とあるh2要素に対して、rubberBand(ビヨーーンプルンプルンプン)みたいなアニメーションをつけるには、

<h2 class="animated rubberBand">rubberBand</h2>
のように書く。動的にアニメーションさせたい、例えばボタンクリック時とか、という場合は、
var target = $('h2');
var button = $('button#some-button');
button.on('click', function(ev) {
  target.addClass('animated').addClass('rubberBand');
});
となる。他にも無限にアニメーションさせるとか、アニメーション終了イベントをハンドリングするとかもできる。

アニメーションの種類

  • Attension Seekers
  • Bouncing
  • Fading
  • Flippers
  • Lightspeed
  • Rotating
  • Specials
  • Zoom
8つのカテゴリに分かれていて、それぞれいくつかのアニメーションを提供している。

当然本家のサイトでも試せるんだけど、ドロップダウンでいちいち選択するのが面倒に思って、これらを1つ1つ試すページをここに作ってみたので、よかったらどうぞ。

終わりに

animate.css、簡単に使えて効果でかいっていう感じがいいな、と思った。

2015/02/18

モックhtmlはyeoman+gulp-webappで。

2013年の8月に、「モックhtmlはJade+LESS+CoffeeScript+Grunt.jsで。」という記事をこのブログに書いた。あれから約1年半。Webアプリケーションの開発の仕方やツールなども変わってきて、当時やろうとしていたことが今では随分とスマートにできるようになったので、あらためてモックhtmlをさくさく作る環境について纏めておきます。

Yeoman

Yeomanを使う。Yeomanは「モダンなWebアプリのscaffoldingツール」。いろいろなWebアプリケーションの構成、例えばAngujarJS+Express.js+MongoDBとか、backborn.js+express.jsとか、に対するアプリケーションのscaffoldを作るツール。で、いろいろな構成に対するgeneratorが提供されていて、必要なgeneratorをインストールして使う、という寸法。

gulp-webapp

gulp-webappは、yeomanが提供する静的サイトのためのgenerator。モックHTMLを作るなら、ズバリこいつがよさげ。gulpのwatchタスクが動くから、コード書きながら結果を見ながらコード直しながら結果を見ながら、っていうのが簡単にできちゃう。

Jadeとless、あるいは。

gulp-webpp、ちょっとまって。Jadeとかlessを使いたい場合はどうすんのさ?って思ったんだけど、よくよくドキュメントを見ると、Recipesってのがあって、ここに色々書いてあった。Jadeもlessも使えるわ。他にもいろいろあるから読んでみたらいい。

終わりに

YeomanはGrunt+Bowerを全面に押し出してるはずなのに、gulp-webappって…と思わずにいられませんでした。とはいえ、便利ですね。

2015/01/22

AngularJSのDIについてDeveloper Guideを読んでみた。

を纏める時に、AngularJSのDeveloper Guideを読んだわけですが、AngularJSがどのようにDIを実現しているか、についても書かれています。興味あったんで纏めてみます(というか訳してみます、に近いか・・・)。

コンポーネント(objectやfunction)が依存するブツを得る方法は3つしかない。

  1. コンポーネントは依存するブツを生成することができ、一般的にはnew演算子を使う。
  2. コンポーネントはグローバル変数から依存するブツを探すことができる。
  3. コンポーネントはそれが必要となる場所で渡される。

最初の生成する、とか、探すっていう2つの選択肢は、コンポーネントに依存するブツをハードコードしなきゃいけなくなるので、最適とはいえない。依存するブツを変更することが面倒になってしまう。これは特にテスト用に分離したブツのモックを提供したいといった場面で問題になる。

3番目の選択肢は、コンポーネントから依存するブツの場所を知る責務を取り除くのでもっともよさそう。依存するブツは単純にそのコンポーネントに渡されるだけ。

function SomeClass(greeter) {
  this.greeter = greeter;
}

SomeClass.prototype.doSomething = function(name) {
  this.greeter.greet(name);
};

上の例のSomeClassはgreeterの生成や場所の特定などには関係していなくて、インスタンスが作成される際に、単純にgreeterを手渡されるだけ。 それはいいんだけど、SomeClassを生成するコード上に依存するブツを得るっていう責務を生んでる。

依存するブツを生成するっていう責務を管理するために、angularjsアプリケーションは”injector”を持ってる。injectorは、依存するブツの生成や検索を責務とするサービスロケータである。

injectorサービスを使った例を挙げる。

var myModule = angular.module('myModule', []);

injectorにどうやってgreeterサービスを組み立てるか教えてあげる。greeterは$windowサービスに依存していることに注目しよう。greeterサービスはgreetメソッドを持つオブジェクト。

myModule.factory('greeter', function($window) {
  return {
    greet: function(text) {
      $window.alert(text);
    }
  };
});

で、myModuleに定義されたコンポーネントを提供することができる新しいinjectorを生成して、 そいつにgreeterサービスをリクエストする。(これは通常angular bootstrapで自動的に行われる。)

var injector = angular.injector(['myModule', 'ng']);
var greeter = injector.get('greeter');

ハードコードの問題の解決を望んだら、今度はinjectorがアプリケーション全体を通じて存在する必要性が出ちゃった。injectorを渡すことが「デメテルの法則」を破ってしまう。これを救済するために、下の例のように、コンポーネントを生成する責務をinjectorに移譲するために、HTMLテンプレート上で宣言的な記法を使っている。

function MyController($scope, greeter) {
  $scope.sayHello = function() {
    greeter.greet('Hello World');
  };
}

AngularはHTMLをコンパイルする時、injectorに対してコントローラとそれが依存するブツのインスタンスを次々に生成するよう要求しながらng-controllerディレクティブを処理する。

injector.instantiate(MyController);

これは全て舞台裏で完了する。ng-controllerを使うってことは、これまでにinjectorを知っているコントローラなしで、injectorにそのクラスのインスタンスを生成するよう要求し、MyControllerの全ての依存性を満たすってことに注意しよう。

これがベストな結果。アプリケーションコードはinjectorを使ってどうこうするとかなしに、単純に必要な依存性を宣言するだけ。この仕組なら「デメテルの法則」を破らないですむ。

というようなことが書いてあって、訳しかたがうまくなくて、はっきりと理解できたわけではないが、とりあえずメモとして残しておきます。

2015/01/06

AngularJSのDIの定義の仕方

AngularJSはDI(Dependency Injection)の機構を提供してるっつーんで、AngularJS: Developer Guide: Dependency Injectionを読みつつ、使い方を纏めておくとしよう。

依存するコンポーネントをどう書くか

以下の3つの方法がある。

  • inline array annotation (最も好ましい方法)
  • $inject property annotation
  • 関数のパラメータ名から暗黙的に注入する方法(この方法は注意が必要)

inline array annotation

someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
  // do something.
}]);
と書くのがinline array annotationだと。この例で言うなら、'$scope'と'greeter'という名前で生成&登録されたオブジェクトが存在する前提で、MyControllerは$scopeとgreeterオブジェクトに依存している、ということを表現している。依存するコンポーネントの名称を文字列で並べつつ、関数のパラメータとして定義する。このとき、配列の要素の順番と関数の引数の順番が一致するよう注意する必要がある。

$inject array annotation

この方法は、仮にミニファイツールなどでコードがミニファイされて、関数のパラメータ名がツールに変更されてしまったとしても、正しく依存するオブジェクトが注入されるようにする方法、だと。

var MyController = function($scope, greeter) {
  // ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);
この例は、inline array annotationとよく似ているからわかりやすい。$injectに依存するオブジェクトの名前を設定する、ってことね。これもinline array annotationと同じく、$injectに指定する配列の要素と、関数のパラメータの順序を一致させないとダメよ。

関数のパラメータ名から暗黙的に注入する方法

で、この暗黙の注入が一番簡単なんだけど、問題も有る、と。 コードを書くとすると、

someModule.controller('MyController', function($scope, greeter) {
  // ...
});
みたいになって、配列の順序と関数の引数の順序を一致させるとかも気にしなくていい、というメリットはある。だけど、ミニファイツールで関数の引数名が変えられちゃったら、もうAngularは正しく注入できないから、この方法は使わない方がいいみたい。
However this method will not work with JavaScript minifiers/obfuscators because of how they rename parameters. Tools like ng-annotate let you use implicit dependency annotations in your app and automatically add inline array annotations prior to minifying. If you decide to take this approach, you probably want to use ng-strict-di. Because of these caveats, we recommend avoiding this style of annotation.

AngularJSのConceptual Overview

AngularJSの機能やコンセプトなどよくわかってないので、公式サイトのガイドを読んでいる。そこには、Conceptual Overviewなる一覧があり、例えばAngularJSのFilterとかわかっていない僕には嬉しい一覧であった。ので、自分の備忘録としてここに訳しつつ纏めておく。

Template
追加のマークアップを持つHTML
Directives
カスタム属性、カスタム要素を持つHTMLの拡張
Model
ユーザがView上で見たり操作するデータ
Scope
モデルが格納されるコンテキスト。controller、directive、expressionからアクセスできる。
Expressions
Scopeからアクセスする変数や関数を記述する式
Compiler
Templateを解析し、directiveやexpressionsをインスタンス化する。
Filter
式の値をユーザに見せるために整形する。
View
ユーザが目にするもの。
Data Binding
Model-View間でデータを同期する。
Controller
Viewの裏側のビジネスロジック。
Dependency Injection
オブジェクトと関数を生成し、結び付ける。
Injector
DIコンテナ
Module
Injectorを構成するcontroller、service、filter、directiveなどアプリの異なるパーツのためのコンテナ。
Service
Viewから独立した再利用可能なビジネスロジック

2015/01/04

YeomanのAngularJS Full-Stack generatorが提供するジェネレータ

AngularJS Full-Stack generatorは、アプリケーションのひな形だけでなく、アプリケーションの中身を開発する上で使えるジェネレータをいくつか提供しているってことに気づいたので纏めてみます。

angular-fullstack

アプリケーションそのものを作るジェネレータ。angular-fullstack:appのエイリアス。

$ yo angular-fullstack

これ以外のジェネレータには、サーバサイドの機能を作るためのジェネレータと、クライアントサイドの機能を作るためのジェネレータ、そしてデプロイのためのジェネレータがある。

サーバサイド

angular-fullstack:endpoint

REST APIのエンドポイントを生成するジェネレータ。例えば、issueというリソースに対するREST APIのエンドポイントを定義する場合は、

$ yo angular-fullstack:endpoint issue
を実行する。すると、
? What will the url of your endpoint to be? /api/v1/issues
   create server/api/issue/index.js
   create server/api/issue/issue.controller.js
   create server/api/issue/issue.model.js
   create server/api/issue/issue.socket.js
   create server/api/issue/issue.spec.js
となる。URLをどうするか聞かれるので、/api/v1/issuesと入力した。モデルやコントローラ、specファイルが生成される。

クライアントサイド

angular-fullstack:route

あるURLに対するクライアントサイドのリソース一式を生成するジェネレータ。例えば、/issuesというURLを有効にするために、

$ yo angular-fullstack:route issues
を実行すると、
? Where would you like to create this route? client/app/
? What will the url of your route be? /issues
   create client/app/issues/issues.js
   create client/app/issues/issues.controller.js
   create client/app/issues/issues.controller.spec.js
   create client/app/issues/issues.jade
   create client/app/issues/issues.less
が得られる。

angular-fullstack:controller

クライアントサイドのコントローラを生成する。

$ yo angular-fullstack:controller chat
を実行すると、
? Where would you like to create this controller? client/app/
   create client/app/chat/chat.controller.js
   create client/app/chat/chat.controller.spec.js
が得られる。

angular-fullstack:directive

AngularJSのdirectiveを生成する。何らかのチャートを表示するためのディレクティブを作るとして、

$ yo angular-fullstack:directive chart
を実行すると、
? Where would you like to create this directive? client/app/
? Does this directive need an external html file? Yes
   create client/app/chart/chart.directive.js
   create client/app/chart/chart.directive.spec.js
   create client/app/chart/chart.jade
   create client/app/chart/chart.less
が得られる。

angular-fullstack:filter

filterって何だろう。AngularJS初心者なのでまだ知りません。 でも、

$ yo angular-fullstack:filter someFilter
を実行すると、filterのためのファイルを生成してくれる、と。

angular-fullstack:service

AngularJSのserviceを生成する。 例えば、issueというリソースに関するAPIを提供するサービスを作るとして、

$ yo angular-fullstack:service issue
を実行すると、
? Where would you like to create this service? client/components
   create client/components/issue/issue.service.js
   create client/components/issue/issue.service.spec.js
が得られる。同様に、angular-fullstack:factoryangular-fullstack:providerというgeneratorも存在していて、それぞれ、
// yo angular-fullstack:service issue
'use strict';

angular.module('teamApp')
  .service('issue', function () {
    // AngularJS will instantiate a singleton by calling "new" on this function
  });
// yo angular-fullstack:factory issue
'use strict';

angular.module('teamApp')
  .factory('issue', function () {
    // Service logic
    // ...

    var meaningOfLife = 42;

    // Public API here
    return {
      someMethod: function () {
        return meaningOfLife;
      }
    };
  });
// yo angular-fullstack:provider issue
'use strict';

angular.module('teamApp')
  .provider('issue', function () {

    // Private variables
    var salutation = 'Hello';

    // Private constructor
    function Greeter() {
      this.greet = function () {
        return salutation;
      };
    }

    // Public API for configuration
    this.setSalutation = function (s) {
      salutation = s;
    };

    // Method for instantiating
    this.$get = function () {
      return new Greeter();
    };
  });
を生成する。

angular-fullstack:decorator

公式サイトには

Generates an AngularJS service decorator.
とあるが、これもよくわかっていない。が、
yo angular-fullstack:decorator issue
を実行すると、
? Where would you like to create this decorator? client/components
   create client/components/issue/issue.decorator.js
が得られ、
'use strict';

angular.module('teamApp')
  .config(function ($provide) {
    $provide.decorator('issue', function ($delegate) {
      // decorate the $delegate
      return $delegate;
    });
  });
が生成された。

デプロイ

デプロイのためのgeneratorとしては、

  • yo angular-fullstack:openshift
  • yo angular-fullstack:heroku
があって、それぞれOpenShift、Herokuへのデプロイを簡単に行うためのコマンドのようだが、今回は割愛。

終わりに

filterや、service decoratorなどAngularJSを理解していないと使い方がわからないものがあり、使いこなすにはもっと勉強しないと、と感じた。あとは、クライアントサイドのディレクトリ構成を意識するというか、戦略を持たないといけないな。

2015/01/01

YeomanでAngularJS、Express、MongoDB、Node.jsなアプリのひな形を作る。

Yeomanを使ってMEAN(MongoDB、Express、AngularJS、Node.js)なWebアプリケーションのひな形を作ってみます。

AngularJS Full-Stack generator

AngularJS Full-Stack generatorというgeneratorを使用する。

$ npm install -g generator-angular-fullstack
でインストールする。-gオプションを付けてglobalなパッケージとしてインストールする。

AngularJS Full-Stackを実行する。

$ yo angular-fullstack
を実行すると、generatorが次のような質問をしてくるので、適宜答えてあげる。
  • JavaScript、CoffeeScriptのどっちを使う?
  • HTMLとJade、どっちでマークアップする?
  • css、sass、stylus、lessのどれでスタイル書く?
  • AngularのRouterは、ngRouterとuiRouterのどっちを使う?
  • Twitter Bootstrap使う?
  • ui-bootstrapを使う?
  • MongoDBのモデリングにはmongooseを使う?
  • 認証処理のboilerplateを生成する?
  • Google、Facebook、TwitterのOAuthストラテジを有効にする?
  • socket.ioを使う?
質問に答えていくと↑のような画面になる。ここから先は、npm installとかbower installとかYoermanが自動で進めてくれる。

生成したプロジェクト

このgeneratorによって生成したプロジェクトは↓のようなディレクトリ構造になる。

.
├── Gruntfile.js
├── bower.json
├── client
├── e2e
├── karma.conf.js
├── node_modules
├── package.json
├── protractor.conf.js
└── server
clientディレクトリにはクライアントサイドのコードを、serverディレクトリにはサーバサイドのコードを格納するっていうのが、以前のバージョンから変わったところか。e2eディレクトリの目的は詳細を調べる必要がある。

アプリケーションを起動する。

$ grunt serve
でアプリケーションが起動する。