最近、Angular以外も試そうと思って、2012年春にオープンソースになったときから気になっていたMeteorを使うことにしました。 当時は、FirefoxかChromeかどちらかでしか動かず、動かない方で見ると、背景画像しか見えないというすさまじいものでした。 一方、そのコンセプトはとても共感できて、social-cms-backendを自分で開発したときも同じではないものの似た問題意識でした。

さて、Meteorのサイトは、

http://meteor.com/

です。いいドメイン持ってますね。Meteorの発音は「ミーティア」です。 T.M.Revolutionの歌にありましたね。よし、それを聞きながらコーディングしよう。

さて、Meteorの基本的な説明は他に任せるとして、今回はちょっと変わった使い方をしようと思います。そもそも、普通のWebアプリを作るなら慣れたAngularの方が早いのですが、canvasベースのアプリを作りたいと思ったのがきっかけでした。canvasベースのアプリだとAngularの恩恵があまり得られないので、Angular以外を試してみようと。細かい経緯は省きますが、下記のサイトを見てやってみようと思いました。

http://www.html5gamedevs.com/topic/4886-how-to-use-phaser-with-meteor/

Phaserというのはhttp://phaser.io/で、WebGL/Canvasでゲームを作るフレームワークです。Phaserの説明も他に任せます。上記の記事はちょっと古くて、今では、

https://atmospherejs.com/robertlowe/meteor-phaser

が使えます。MeteorのパッケージがAtmosphereというのは、かっこいいですが、慣れるまでは戸惑いそうですね。

さて、お題は1bitコミュニケーションツールを考えています。 夏の暑いときに作った「暑さをみんなでふっとばせ!」というアプリを移植してみようと思います。このアプリについては、下記を参照。

1bitで使い捨てで匿名のコミュニケーションツールを作ってみた

Famo.us/AngularのサンプルアプリをGitHubに置きました

これは、Famo.us/Angularで作りました。とてもお手軽だったのですが、ちょっとゲームのようなものに使うにはパフォーマンスに難がありました。そこで今回は同じものをMeteor/Phaserで作ってみようと思います。

この記事を書きながらコーディングするのでうまく行くか分かりません。また、読みにくくなってしまうかもしれませんがご了承ください。

さて、まずはMeteorをインストールします。https://www.meteor.com/installに従います。このチュートリアルはよくできてますね。

$ curl https://install.meteor.com/ | sh

1.0.1になってroot権限も要求しなくなりました。1.0のときも、sudoのパスワードを入れなければ同じだったのですが、これはシンプルでよいです。

冬なのでアプリは「寒さをみんなでふっとばせ!」にします。ちょっとふっとばすというのは合わないかもしれませんが。アプリ名はsamufutにします。

$ meteor create samufut
$ cd samufut

チュートリアル通りです。ここで、phaserのライブラリを入れてしまいます。

$  meteor add robertlowe:meteor-phaser

これができるようになったのは最近のようですね。

$ meteor &

で起動して準備完了です。コーディング開始。


とりあえず、Phaserを使ったコードを書くところで時間がかかっています。これはあまりMeteorは関係ないところです。 一つだけ気になったこととして、本体のjsを編集すると毎回パッケージのアップデートをしようとして遅いので、Phaserのコードはclient配下に移動しました。この場合はrefreshするだけなので比較的早いです。

Meteorの話が出てくるのは明日になりそうなので、本記事はとりあえず一時保存します。


さて、一日経過しました。その後、Phaserのコードはほぼ完成し、次に通信部分のコードに着手します。Meteorは既にsockjsを使って通信を行う仕組みになっているのですが、それをアプリからも使えるとよいです。調べたところ、

http://arunoda.github.io/meteor-streams/

というのがありました。パッケージはこちらですね。

$ meteor add lepozepo:streams

でインストールします。簡単です。サンプルコードもそのまま貼り付けます。

chatStream = new Meteor.Stream('chat');

if(Meteor.isClient) {
  sendChat = function(message) {
    chatStream.emit('message', message);
    console.log('me: ' + message);
  };

  chatStream.on('message', function(message) {
    console.log('user: ' + message);
  });
}

直感的ですね。これで実装してみましょう。今回はinsecureは入れたままにします。

完成しました。コードは237行でした。 それでは、デプロイしてみます。

% meteor deploy samufut.meteor.com

できました。メールアドレスが要求されました。

しかし、このURLはgithub pagesやherokuと同じように問題になるのではないでしょうか。そのうち、*.meteorapp.comとかになるかもしれませんね。

デプロイされたサイトは、

http://samufut.meteor.com/

です。ぜひ、遊んでみてください。使い方は書きませんでしたので、暑さをみんなでふっとばせ!の方を参照してください。

少し試した範囲だと、環境によっては通信がうまく行かないケースがあるようです。遅延というか、反映されないのです。またの機会に調べましょう。

ソースコードは下記にアップしました。

https://github.com/dai-shi/samufut

当初は、もっとMeteorのことを書こうと思っていたのですが、苦労したのはPhaserまわりだったのであまり書くことがなくなってしまいました。まだ、やったことないですが、insecureを外してまじめに実装するといろいろコード量が増えて、結局大変っていうことにならないか心配です。それでも、プロトタイプが手軽に作れるのは利点だと思います。

気になったことを一つ思い出しました。普段非同期処理で書くことが多く、比較的好んでいるのですが、Meteorのクライアント側のmongoは同期的なので戸惑いました。キャッシュされているからなせるわざなのでしょうか。事前にpublishできないようなデータの場合どうなるかなど気になります。もう少し勉強しなければいけません。

それでは、Meteorの今後に期待します。


12/28追記。

sudoがいらないと思ったのは勘違いでした。たまたま、その時の環境が/usr/local/binにwrite権限があったため。

GitHub便利です。その一つが、Compare ViewのDiffです。Pull Requestを確認するときもよく見ます。コマンドラインでgit diffと普通にやるより見やすいです。

さて、背景は省略しますが、HTMLでdiffを表示したいと思いました。AngularJSでの利用を想定しているので、JavaScriptのライブラリが欲しいです。

ところが探してもあまり見つかりません。よくまとまっているのはこちら。

http://stackoverflow.com/questions/3053587/javascript-based-diff-utility

ちょっと古い投稿ですが。一番人気なのは、これです。

https://github.com/cemerick/jsdifflib

オンラインデモはこちら。

http://cemerick.github.io/jsdifflib/demo.html

だいぶ求めているもののイメージに近いです。 コードも枯れているらしい。 HTMLが出力されるので、Angularで使うならdirectiveを書かなければいけないですが、それは仕方ないですね。

これで行こうかと思ったところでしたが、なにか物足りません。 なんというか、見た目がワクワクしないのです。 改めてGitHubのDiffと比較してみると、全体的に色が濃すぎる。 あと、単語の差分がハイライトされない。色については自分でcssを書いて調整すればよいでしょうが、単語のハイライトはそれでは済みません。

というわけで、もう一度検索しました。見つけたのがこちらです。

https://github.com/rtfpessoa/diff2html

オンラインデモはこちら。

http://rtfpessoa.github.io/diff2html/

おお、おしゃれ。これですよこれ。なんとStar数は3でした。まったく注目されていません。コードも枯れていないでしょう。まだ不具合もあります。でも、魅力的です。これを使いましょう。

ところが、使うには一つ問題がありました。diff2htmlはdiffの出力を入力としているのです。例えば、

diff --git a/foo.txt b/foo.txt
---
+++
@@ -1,4 +1,5 @@
+zero
 one
 two
-three
+tree
 four

このようなものです。つまり、次はこれを出力するライブラリを探しました。いくつかありそうでしたが、比較的すんなり結合できたのはこちらです。

https://github.com/qiao/difflib.js

入力の行が配列になることと、出力の一行目のヘッダが付かないことなど不足点はありまして、それらは自力で対応しました。

最後にこれらを全部つなげて、angular.jsのdirectiveを書いてできあがりです。下記のような感じで使えるようになりました。

<my-diff path="foo.txt" old-content="one\ntwo\nthree\nfour\n" new-content="zero\none\ntwo\n\tree\nfour\n">

便利です。ちょっと気になることと言えば、依存javascriptが3ファイルもあって、グローバルに関数を定義するようなものであることです。なにかうまく隠蔽する方法があるのでしょうか。

AngularJSの流れにちゃんとついていくためng-europeをyoutubeで見ようと思い始めて一ヶ月が過ぎてしまいました。 まだ全部は見ていませんが、今日は一本見ました。興味深かったので記事にします。

https://www.youtube.com/watch?v=tfVA1syv-3o

AngularUIのui-bootstrapのお話です。 単にラップするわけではなくAngular流に作られているのと、カスタマイズ性を重視しているあたりは参考になります。

ui-bootstrapはBootstrap 3のcssのみを利用していてjavascriptの部分は全部書き直しているようです。つまり、jQuery依存もなしです。

ちょっと昔話を。当初、Bootstrap 2を使っていたのですが、クラス名などがどうも好きになれず、その後inkというcssフレームワークを見つけて 、しばらく使っていました。

その時から、inkのcssのみを使ってコーディングしていました。ロジックが必要な場合はAngular側で自前で作ってました。 例えば、カレンダーも当初はAngularUIのui-calendarを使っていましたが、 jQuery依存に抵抗があったため、カレンダーも単純な機能ならinkで自前で実装していました。

その後、Bootstrap 3が登場し、クラス名がinkのようにシンプルになったので、少し気に入ってBootstrap 3を使い始めました。でも、cssだけで、jsは使いません。例えば、alertもロジックはangularで自前で書いていました。と言っても、あまりコーディング量は多くなく、特に困っていません。

さて、話を戻しますと、ui-bootstrapは上記でやっていたようなことをちゃんとやっているような印象です。cssだけを使って、ロジックはangular用にdirectiveを設計してあるようです。 alertを見る限りでは単純なので自前で用意しても変わりませんが、他の複雑な機能はui-bootstrapのdirectiveを使うとだいぶ楽できそうです。

というわけで、jQuery非依存のui-bootstrapはおすすめです。

夏ごろに「暑さをみんなでふっとばせ!」というアプリを作りました。

1bitで使い捨てで匿名のコミュニケーションツールを作ってみた

に経緯が書いてあります。

当時は、Famo.usやF/Aのライブラリに手を入れないといけなかったのですが、その後バージョンアップして不具合が解消されました。 新しいバージョンでは読み込み速度なども改善しています。

せっかくなので、GitHubにソースをアップロードしました。 Famo.us/Angularとsocket.ioの組み合わせでこんなことができるというサンプルによいかと思います。

ついでに、「暑」を「寒」に変更する機能もつけました。タイトルはそのままですが。

GitHubのページはこちらです。

https://github.com/dai-shi/atsufut

実際に動作しているアプリのページはこちらです。

http://atsufut.axlight.com/#?color=blue&label=%E5%AF%92

AngularJSの1.3.0がリリースされました。

これまで、1.2系を使っていたのですが、これを機に1.3も試してみようと思いました。

1.0から1.2に移行したときは、はまったのですが、今回はなにも不都合がありませんでした。

ところが、e2eテストが動かなくなってしまいました。具体的には、下記のようなテストがエラーになりました。

expect(element(by.repeater('item in list').row(0).column('{{item.name}}')).getText()).toEqual('foo');

エラー文は、

NoSuchElementError: No element found using locator: ...

です。

https://github.com/angular/protractor/blob/master/docs/api.md

のドキュメントを見ても問題なさそうですし、StackOverflowなどでも話題になっているのは見つからず、途方にくれていました。

が、試しに下記のように変更したら動きました。

expect(element(by.repeater('item in list').row(0).column('item.name')).getText()).toEqual('foo');

これって正しい解決法なのでしょうか。

ProtractorでAngularアプリのE2Eテストやってみた、PhantomJS編に引き続き、 Protractorでwindow.alertをテストする方法を調べたので書いておきます。

E2Eテストを書くときに、alertの文字列を調べたいことがあると思います。 また、confirmでOKしたりCancelしたりする場合の挙動もテストできるとよいでしょう。

ちゃんとできるようです。Protractorというよりその内部のWebDriverがすごいということですね。

http://stackoverflow.com/questions/19879631/protractor-get-text-of-an-alert

に載っていました。

https://github.com/angular/protractor/commit/196c83a9d728e40fecd7a9f206bb985533550fde

が分かりやすいです。ちなみに、現時点でのHEADではnavigation_spec.jsに載っています。これによると、

var alertDialog = browser.switchTo().alert();
expect(alertDialog.getText()).toEqual('Hello');
alertDialog.accept();

と書けばいいとのことです。confirmの場合も同様です。 confirmの場合でcancelするときは、accept()の代わりにdismiss()を使えばよいようです。

ところが、PhantomJSではこれは現時点では使えないことが分かりました。PhantomJSではGhostDriverという別のWebDriverを使っているようです。

https://github.com/detro/ghostdriver/issues/20

これが問題のIssueです。皆さんから切望されていますが、まだ実装されていないようです。しかし、workaroundが記載されていました。埋め込みJavaScriptでなんとかすることができるようです。サンプルを参考に自分でもやってみましたが、うまく行きました。

コードを貼り付けておきます。

describe('alert test spec', function() {
  var ALERT_HANDLER = '(function () { var lastAlert = null; window.alert = function (message) { lastAlert = message; }; window.confirm = function(message) { lastAlert = message; return true; }; window.getLastAlert = function () { var result = lastAlert; lastAlert = null; return result; }; }());';
  var ALERT_GETTER = 'return window.getLastAlert && window.getLastAlert();';

  it('should get register page', function() {
    browser.get('alerttest.html');
    browser.executeScript(ALERT_HANDLER);
    element(by.id('thebutton')).click();
  expect(browser.executeScript(ALERT_GETTER)).toContain('Hello');
  });
});

dismiss()相当を実現するのはちょっと工夫すればできそうです。accept()/dismiss()でタイミング制御をすることは難しそうです。

過去にKarma(Testacular)を使ったことはありますが、今回やっと時代に追いついてProtractorを使ってみました。特にPhantomJSを使ってheadlessでE2Eテストするときに気づいたことをまとめます。

Protractorは、 Seleniumの WebDriverJSのラッパーで、AngularJSのE2Eテストのためのフレームワークです。

https://docs.angularjs.org/guide/e2e-testing

がエントリーポイントになるでしょう。 しかし、これだけ読んでも最終的な実行方法は分かりづらいです。 今回の目的は、コマンド一つ、例えば、

$ npm run e2e-test

でE2Eテストを実行してするための環境セットを作ることです。また、headlessで動かしたかったので、典型的に使われるChromeではなく、PhantomJSを前提にしました。サーバはExpress/Node.jsの想定ですが、それ以外の場合にも応用できるかと思います。

初めによくある環境設定です。

$ npm install protractor
$ npm install phantomjs
$ ./node_modules/.bin/webdriver-manager update

この例ではローカルディレクトリにモジュールをインストールしていますが。グローバルにインストールしたい人はそのようにどうぞ。

まず初めにはまったことはwebdriverが起動しないことでした。

$ ./node_modules/.bin/webdriver-manager start
INFO - Launching a standalone server
WARN - null
java.net.SocketException: No such device
    at java.net.NetworkInterface.isLoopback0(Native Method)

このようなエラーがでました。ワーニングかと思って無視していたらいけませんでした。どうやら、IPv6のアドレスのみを使っていてうまく行かないようだったので、Javaのオプションを追加して次のようにするとうまく行くことが分かりました。

$ env _JAVA_OPTIONS=-Djava.net.preferIPv4Stack=true ./node_modules/.bin/webdriver-manager start

さて、Protractorのチュートリアルには、webdriverをコマンドラインで手動で実行するように書いてありますが、個人的にはこれは面倒に感じます。時間はかかりますが、毎回自動で起動して欲しいです。これは簡単で、protractor.conf.jsにseleniumAddressを書かなければよいだけでした。下記に、protractor.confを載せます。

exports.config = {
  specs: [
    '*-spec.js'
  ],
  capabilities: {
    'browserName': 'phantomjs',
    'phantomjs.binary.path': './node_modules/.bin/phantomjs'
  },
  baseUrl: 'http://localhost:' + (process.env.PORT || 3000) + '/'
};

これだけで大丈夫でした。baseUrlは、specにURLをフルパスで書かなくてもよいようにするためで、expressが下記のように起動されている想定です。

app.listen(process.env.PORT || 3000);

specの細かい内容は今回は書きませんが、もっとも単純なものは例えば次のようになります。

describe('tutorial', function() {
  it('should have a title', function() {
    browser.get('index.html');
    expect(browser.getTitle()).toEqual('The Title');
  });
});

ところで、Protractorはテストのフレームワークであるもののアプリの起動には関与せず、アプリは自分で起動しなければいけません。また、テスト終了後はアプリも終了したいです。今回はお手軽にシェルスクリプトを書きました。

#!/bin/sh

export _JAVA_OPTIONS=-Djava.net.preferIPv4Stack=true
export PORT=12345
node ./app.js &
PID=$!
./node_modules/.bin/protractor ./e2e-test/protractor.conf.js
kill $PID

このスクリプトをpackage.jsonのscriptsに書いておけば、当初の目的であったnpmで一発でE2Eテストを走らせることができました。

Happy e2e testing!

自分が興味あるものの一つにコミュニケーションツールがあります。 と言っても普通のコミュニケーションではないです。 例えば、見知らぬ人と一時的なつながりを感じられるようなそんなツールがいいと思います。言語も使わず、世界のどこかの誰かと。

FacebookのPokeはよかったです。1bitで行うコミュニケーションとでも呼びましょうか。日本では「あいさつ」となり、意味が分からなくなりました。 ちなみに、Pokeは一度機能が隠れてしまったのですが、また復活しました。 最近は、Yoが流行っているらしいです。これも1bitコミュニケーションだと思います。どこまで流行るのか、気になるところです。

流行っているついでに、Snapchatについても気になるところです。 実は使ったことありませんが、これは使い捨てコミュニケーションだと思っています。 使い捨てコミュニケーションができたら面白いだろうなぁとは思っていましたが、 まさかそんなものが流行るとは想像していませんでした。 写真だからうまくいったのでしょうか。

あとは、匿名コミュニケーションにも興味あります。 最近は実名指向で、あまり匿名を重視したコミュニケーションツールは登場していないのでしょうか。

と言うわけで、前置きが長くなりましたが、1bitで使い捨てで匿名のコミュニケーションツールを作ってみようと思いました。 1bitで伝えたいことはなんだろう、と考えたその日が暑い日だったので、「暑い」にしました。 「暑い」を伝え合うだけでは、どんどん暑苦しくなるだけですので、 ストレス発散をできるような「吹き飛ばし」機能をつけることにしました。

atsufut_title.png

これがタイトル画面です。

atsufut_main.png

これがメイン画面です。これだけです。 画面の上半分をクリック(タップ)すると、丸が落ちてきます。 何度も押すと、丸がたまってきます。 次に画面の下半分をクリックすると、丸を吹き飛ばします。 それだけです。

それでは、やってみましょう。

http://atsufut.axlight.com/

このURLをスマホで開きましょう。PCでも大丈夫です。モダンブラウザ必須です。

一人でやると、すぐに飽きます。 複数人で同時にやるとまあまあ面白いとは思います。 しかし、たまたま同時に開いている人がいることは稀です。 ここをどうするかが悩みどころです。

今回、開発に利用したライブラリは、 node.js, socket.io, angular.js, famo.us あたりです。

Famo.us Physicsで3Dの簡単なサンプル

  • 投稿日:
  • by

もうちょっとすばやくサンプルを作ってみるつもりがのんびりしてしまいました。

前回に引き続き、famo.us Physicsを使ったサンプルです。

3次元の物理演算もできるはずなので、Z軸も使った簡単なサンプルが作れないかと思ってやってみました。

こちら

当初、普通に回したらsurfaceの裏は真っ白で、180度回ると何も見えなくなってしまいました。そこで、仕方なく、各円を反対方向に回すことで表示しました。もっといい方法があればいいのですが。

また、遠くのsurfaceを縮小表示する方法が分かりませんでした。これができればだいぶ立体感がでると思うのですが。physicsとtransformを混ぜて使ってはいけないのかもしれません。

Famo.us Universityのphysicsコースは未だcoming soonのままです。

今回のサンプルのソースコードはこちらです。

angular.jsの話です。突然ですが、ng-clickというのはクリックが完了したときに実行され、ng-mousedownというのは押しただけで実行されます。しかし、ng-mousedownはタッチパネルでは発火しません。mousedownイベントはマウスだけであり、タブレットやスマートフォンのブラウザではtouchstartイベントがあります。なので、てっきりng-touchstartというのが用意されているものと思っていました。

が、それは勘違いでした。少なくとも現時点では。 ng-clickより細かい制御をしたかったので、ng-touchstartはどうしても欲しいです。

ところで、angular.jsのdirectiveはとても協力ですが、アプリケーション実装するときにdirective開発するのは無駄だと思っています。標準で用意されたdirectiveとcontrollerで済むことが多いです。directiveは再利用性が高いものを開発するときに使うものでしょう。アプリではなくライブラリ開発するときですね。

ところが、アプリ開発しているときにどうしてもng-touchstartが欲しくなってしまったので、directive書いてみました。今まで食わず嫌いでしたが、簡単なdirectiveなら書いてみるとすっきりすることもあるな、とちょっと考え直しました。

というわけで、開発したdirectiveを貼り付けておきます。

angular.module('MyModule').directive('myTouchstart', ['$parse', '$swipe',
  function($parse, $swipe) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
        var handler = $parse(attrs.myTouchstart);
        $swipe.bind(element, {
          start: function() {
            scope.$apply(function() {
              handler(scope);
            });
          }
        });
      }
    };
  }
]);

これだと、touchstartとmousedown両方に反応するのですが、ちゃんとやるならそのあたりも制御した方がいいですね。あと、touchstartだけでなく、touchmoveとtouchendもあったほうがいいでしょう。そこまでやったら、pullreqできそうです。というか、もう誰かがやっているのではないでしょうか。

これが一番近そうです。

https://github.com/angular/angular.js/issues/5334

まだ解決していない模様。確かに、ng-mousedownをoverrideしてもいいかもしれません。名前が直感的ではないですが。