GrimoireJSのシーンをスクリプトで操作したい

(この記事は[GrimoireJSアドベントカレンダー2016](http://qiita.com/advent-calendar/2016/grimoire)の９日目です。)

前回はGrimoireJSの基本的な構造についてという記事でGomlNodeとComponentについて簡単に紹介しました。
ページにgomlを埋め込むことでそれがツリーとしてパースされ、そのままのシーンがレンダリングされます。
でも、せっかくhtmlページに埋め込むなら、**ほかのhtml要素と同じように動的に操作**したくなりませんか？

ということで今回は、gomlから構築されたGomlNodeツリーをスクリプトからどのように操作するのかを紹介していきたいとおもいます。

# 3種のインタフェース
GrimoireJSは、gomlから作られたシーン中のGomlNodeを簡単に操作するためのインタフェースを提供しています。
このインタフェースは

+ **GrimoireInterface**
+ **GomlInterface**
+ **NodeInterface**

の3段階に分かれていて、それぞれ操作する対象が違います。

|Interface|対象|コード|
|:---|:---|:---|
|GrimoireInterface |環境全体|`gr` |
|GomlInterface |htmlに埋め込まれた各goml|`gr("selector")` |
|NodeInterface  |GomlNodeツリー中の各ノード  |`gr("selector")("")`  |



まずは、公式のチュートリアルから引っ張ってきた以下のコードを見てみましょう。

``` js:index.js
gr(function() {
    setTimeout(function(){
      gr("#main")("#green-mesh").setAttribute("position", "3,0,0");
    },1000);
});
```

# GrimoireInterface
`gr`は、GrimoireJSを読み込むとグローバルに定義される**GrimoireInterface**です。
よく見ると1行目と3行目で違う使い方をされていますが、まずは3行目の方を見てみましょう。
各インタフェースに共通しているのは、**関数としてセレクタを渡して対象を検索**できることです。
![alt](https://grimoire.gl/api/images/Grimoire-interface-describe.png)

それを踏まえて先程のサンプルコードを思い出してみると、
> `gr("#main")("#green-mesh").setAttribute("position", "3,0,0");`

`gr`に`"#main"`というセレクタが渡され、**idが"main"であるスクリプトタグに対応するgoml**を検索して、**GomlInterface**が返されます。
そのGomlInterfaceに対して`"#green-mesh"`を渡すことで、このgoml中の**idが"green-mesh"であるノード**が検索され、**NodeInterface**が返されてます。

また、NodeInterfaceに対しての操作は、対象となるすべてのノードに対して実行されるので、`setAttribute()`すると複数ノードに同時に属性を設定できます。
ここではid指定なので対象ノードは一つだけですが、例えば、`gr("#main")("mesh")`とすれば**すべての`mesh`タグ**を一度に操作することができます。

基本的にこれらの機能を使うことが多いですが、それぞれのインタフェースには他にもいくつか機能があるので、その辺りも紹介します。

# GrimoireInterface
まず先程のサンプルの1行目で使われていた機能。
### functionを渡して関数として呼び出す
> functionを渡すと、**Gomツリーがロードされた直後に渡した関数がコールバックされます**。
> Gomツリー上の要素をいじるときは当然ツリーのロードが完了していないといけないので、基本的にこの中で操作を行うことになります。

### `gr.registerComponent()`
>```js:
gr.registerComponent("ComponentName", {
  attribute:{},
  $awake:function(){}
  })
```
>新しいコンポーネントを作るときに使います。コンポーネント名は`CamelCase`推奨です。

### `gr.registerNode()`
>```js:
gr.registerNode("node-name",["ComponentName"],{attr:"default Value"});
```
>こちらは新しいノードの定義です。ノード名は、`snake-case`推奨です。
上のregisterComponentにも言えることですが、**registerはロード完了前にやる必要があるので、`gr(function(){})`の中で呼んではダメです。**


# GomlInterface
実はこいつにはほとんど機能がないのですが、強いて挙げるなら。
### `gr("selector").getNodeById("id")`
`gr("selector")("#id")`とするのとほぼ等価ですが、こちらのほうが高速です。
パフォーマンスが必要な場合に使ってください。
ちなみに返り値は`NodeInterface`ではなく、**GomlNodeの配列**です。

# NodeInterface
一番多機能です。よく使う順で紹介。
### setAttribute
```js
gr("slctr")("slctr").setAttribute("attrName","value")
```
そのまんま属性の設定です。よく使います。

### getAttribute
```js
gr("slctr")("slctr").getAttribute("attrName")
```
属性の取得です。
これもよく使いますが、**対象ノードが存在しないと例外を投げます。**
また、対象が複数存在するとき、**最初のノードの属性を返します。**

### forEach
```js:
gr("slctr")("slctr").forEach(function(node,gomlIndex,nodeIndex){
  // for all node.
  console.log(node);
})
```
対象ノードに反復処理ができます。ノード本体は第一引数で、そのノードの属するgomlのインデックスとnodeのインデックスも渡されます。
汎用性高いのでよく使います。


### addComponent
```js
gr("slctr")("slctr").addComponent("ComponentName",{attr:"value"})
```
コンポーネントをノードに追加します。
動的にコンポーネントを制御するのに使います。

### delete
```js
gr("slctr")("slctr").delete()
```
ノードを削除します。

### count
```js
var count = gr("slctr")("slctr").count()
```
対象ノードの個数です。

### first
```js
var node = gr("slctr")("slctr").first()
```
最初のノードを返します。**一つも存在しないとnullを返します。**

### single
```js
var node = gr("slctr")("slctr").single()
```
firstとほぼ同じですが、対象が存在しなかったり、複数存在するときには例外を投げます。
対象がひとつしかないことを期待するならこっちを使ったほうが安全です。

# まとめ
大抵、`gr()()`で取得するノードインタフェースを通して操作する。