Pepperのタブレット用フレームワークTapperを使ってみました

　Pepperのアプリ開発でタブレットを使用しなければならないときに、まず困るのは仕組みが違うことです。Choregrapheのボックスでもできるのですが、タブレットの座標値で制御するのは面倒ですし、もう１つの手段として、HTML/CSS/JavaScriptで作るにも１からだと大変です。
　何かいい資料はないかと探していたら[アトリエ秋葉原さん](http://pepper-atelier-akihabara.jp/)の過去のイベント[【アトリエ秋葉原】ディスプレイ(タブレット)技術勉強会](http://pepper-atelier-akihabara.jp/archives/1378)の[株式会社ヘッドウォータース](http://www.headwaters.co.jp/)さんの資料にTapperというフレームワークが紹介されていましたので、今回使用してみました。

# 参考
 こちらの資料を参考にさせていただきました。
　[株式会社ヘッドウォータース](http://www.headwaters.co.jp/)さんの資料 [Pepperディスプレイのちょっとしたコツ](http://pepper-atelier-akihabara.jp/wp/wp-content/uploads/2016/03/PepperTabletDev2.pdf)

# 注意事項
　ソフトバンクロボティクス株式会社のPepperを活用し、独自開発したものです。

#環境について
 今回使用した環境です。
 MacOS Sierra 10.12.2
 Choregraphe 2.4.3.28
 Pepper
 Tapper 0.3
 Python 2.7.10

#Tapperについて
 pepper-devさんが公開されている。ディスプレイ側の開発用フレームワークです。
 BSD-Licenceの下でライセンスされています。
 http://pepper-dev.github.io/tapper/
 [ドキュメント](http://pepper-dev.github.io/tapper/index.html　)も充実しています。

##インストール
 次のコマンドでTapperコマンドをインストールします。

```bash
sudo pip install tapper
```
##テンプレートの作成
　TapperはPepperのタブレット用のテンプレートを生成してくれます。
　tapper create を実行すると、カレントディレクトリにテンプレートが生成されます。
　以下は3画面のテンプレートの作成例です。
　-sceneオプションに画面数を指定します。

```bash
tapper create --scene 3
```

```
Tapper create.
  Scene 3
    mkdir: ./html
    mkdir: ./html/css
    mkdir: ./html/js
    mkdir: ./html/img
    mkdir: ./html/img/preloads
    create: ./html/index.html
    create: ./html/css/contents.css
    create: ./html/css/normalize.css
    create: ./html/js/tapper.js
    create: ./html/js/contents.js
  Succeeded.
```

##プロジェクトへの組み込み
　Choregrapheのプロジェクトに組み込みます。
　ビヘイビアの位置はルートに変更しておいてください。
![tapper1.png](https://qiita-image-store.s3.amazonaws.com/0/131693/8d195930-7b94-9f08-6026-07085bc30a94.png)

##sceneについて
　Tapperでは画面のことをsceneと呼びます。
　先ほどのコマンドで生成されたhtmlがこちらです。idがscene1からscene3までのsectionが作成されていますす。　また、最初に表示されるのは、scene1です。

```html:/html/index.html(一部)
    <body>
        <section id="scene1" style="display: block;">
        </section>
        <section id="scene2" style="display: none;">
        </section>
        <section id="scene3" style="display: none;">
        </section>
    </body>
```

##sceneの切り替え方法
 scene2に切り替える場合、Pythonでは次のように行います。

```py
 self.memory = ALProxy("ALMemory")
 self.memory.raiseEvent("Tapper/View/ChangeScene", "2")
```

##タッチイベントについて
 初期化時にhtml内のdata-btn-id属性を持つ全てのノード対して、touchstart、touchendのイベントが自動で割り当てられます。

```js:/html/js/tapper.js(一部)
Tapper.view = {
    init: function(){
        $(document).on('touchstart', '[data-btn-id]', function(){
            var node = $(this);
            node.addClass('touched');
        }).on('touchend', '[data-btn-id]', function(){
            var node = $(this);
            node.removeClass('touched');
            node.addClass('selected');
            Tapper.utl.raiseEvent("Tapper/View/ButtonTouched", node.attr('data-btn-id'));
        });
    },
  :
```


 また、touchend時にTapper/View/ButtonTouchedのイベントが発火するので、このイベントに対しての処理を記述することで、画面がタッチされたとか、ボタンが押されたとかの処理に対応することができます。

##画像のプレロードについて
 画像のプレロード機能もあります。html/img/preloads配下にhtmlで使用する画像を配置し、tapper updateコマンドを実行すると、tapper.jsが書き換えられ、プレロードの処理が追加されます。

```bash
tapper update
```

```bash
Tapper update.
    load: omocha_robot.png
    create: ./html/js/tapper.js
  Succeeded.
```

```js:/html/js/tapper.js(一部)
Tapper.core = function($) {

    // T.B.D
    var PROXY_LEN = 2;

    // image preload
    var _preload_img = function() {
        var image = [
        'img/preloads/omocha_robot.png'
        ];
        $.each(image, function(i, src) {
            $('<img>').attr('src', src);
        });
    }
```

##初期データについて
　タブレット側に渡す初期データをALMemoryのTapper/InitData経由で渡すことができます。htmlロード時(Tapper.coreの初期化時)に行われるため、Show Appボックスの実行前にセットする必要があります。値はTapper.init_dataに保持されます。

```py
        fileName = self.framemanager.getBehaviorPath(self.behaviorId) + "/init_data.json"
        try:
            import json
            with open(fileName, 'r') as f:
                init_data = json.load(f)
                self.memory.insertData("Tapper/InitData", json.dumps(init_data))
       :
```

##contents.js
 tapper.jsはtapperコマンドで置き換わってしまうので、基本的にはcontents.jsに処理を記述することになります。自動生成されたコードには、onLoad、onStart、onScene_[n]_の関数が用意されています。それぞれのイベント時にこれらの関数が実行されれるようになっていますので、画面表示時に何か動的に表示させたいなどといったことが記述できます。　

```js:/html/js/content.js
// pepper contents

Tapper.contents = {

    onLoad: function() {
        console.log("onLoad.");
    },

    onStart: function() {
        console.log("onStart.");
    },

    onScene1: function() {
        console.log("onScene1");
    },

    onScene2: function() {
        console.log("onScene2");
    },

    onScene3: function() {
        console.log("onScene3");
    }
}
```

例：メニューボタンの文字列をinit_dataから設定する

```js:/html/js/content.js
   onScene2: function() {
        console.log("onScene2");
        $("#s2-menu1").append("<p>" + Tapper.init_data["scene2"]["menu1"]["title"]+ "</p>");
        $("#s2-menu2").append("<p>" + Tapper.init_data["scene2"]["menu2"]["title"]+ "</p>");
    },
```

##contents.css
 スタイルシートです。テンプレート生成時は、html, body, sectionの定義しかないので、作成するコンテンツに合わせて追加する必要があります。

```css:contetns.css

/* contents.css */

html, body, section {
  height: 100%;
  width: 100%;
}
```

#サンプル
 実際にTapperを使用して作成したサンプルアプリがこちらです。
 https://github.com/piroku/TapperSample
 （HTML/CCS/JavaScriptは得意ではないので、あくまで参考ということで・・）

![TapperApp1.png](https://qiita-image-store.s3.amazonaws.com/0/131693/35c28cfd-e0a6-69ba-e50a-f766e595d071.png)

sceneごとの処理はそれぞれのボックスに分けた方が良いです。
scene1がタイトル、scene2がメニュー、scene3がメッセージを表示するような画面といったサンプルを作りました。

![TapperApp2.png](https://qiita-image-store.s3.amazonaws.com/0/131693/f7a57d35-47b4-4993-6c90-7a5624bb9f65.png)

sceneのボックスの例がこちらです。scene2はメニュー画面としています。Tapper/View/ButtonTouchedが発火したら、対応するメッセージを発話して、次のボックスに遷移します。

![TapperApp3.png](https://qiita-image-store.s3.amazonaws.com/0/131693/f759a8d3-187b-b514-05fe-5785cc927aaf.png)


```py:bx_イベント連携(一部)
   def onInput_onStart(self):
        import json
        #データの取得
        data = self.memory.getData("Tapper/InitData")
        self.initdata = json.loads(data)
        #シーン2：メニュー画面の開始
        self.memory.raiseEvent("Tapper/View/ChangeScene", "2")

    def onInput_onTapperButton(self, p):

        if(p == "btn-menu1"):
            sayText = self.initdata['scene2']['menu1']['say'].encode('utf-8')
            self.onMenu1(sayText)
            self.onStopped()

        elif(p == "btn-menu2"):
            sayText = self.initdata['scene2']['menu2']['say'].encode('utf-8')
            self.onMenu2(sayText)
            self.onStopped()
```

また、ボタンの表現ですが、data-btn-id属性のノードには selected, touchedクラスが自動付与されるので、メニューの押した感じを少し表現してみました。

```css:/html/css/contents.css
#scene2 .selected, #scene3 .selected {
    background-color:#4d639f;
}

#scene2 .touched, #scene3 .touched{
    position: absolute;
    top: 20px;
}
```

#感想
 Tapperを使用することで、HTML/CCS/JavaScriptが苦手な私でも、Pepperのタブレット連携をあれこれ悩まずに開発することができました。Choregraphe(Python)側との切り分けが明確なので、タブレット側と、Choregraphe側の分担開発もしやすいのではと思います。
 Tapperは、素晴らしいフレームワークですので、ぜひ一度使用してみてください。