Bootstrap用のツリービューを使ってみた

Bootstrapは非常にメジャーで、Webを検索すると、たくさんの有用なライブラリがたくさんあります。
その中で、今回はツリービューを使ってみました。

家の中のネットワーク構成要素が増えてきて、どこに何があるか忘れてしまうので、それを管理するためのWebページを作ろうとしたことがきっかけです。

# ツリービューのライブラリ

今回採用したライブラリです。

jonmiles/bootstrap-treeview
　https://github.com/jonmiles/bootstrap-treeview

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/d9153be0-9395-de7a-42a1-86a79c2a982c.png)

私自身が、まだBootstrap v4に移行できてなく、v3.4.1を使っていて、どちらにも対応しているようでした。

#ツリーの配置

HTMLに以下を記載します。

```html:index.html
  <link rel="stylesheet" href="dist/css/bootstrap-treeview.min.css">
  <script src="dist/js/bootstrap-treeview.min.js"></script>

  <div id="tree"></div>
```

# ツリーの構築

ツリーの1要素を、こんな感じにします。

```
ノード = 
{
  text: “表示したい文字列”,
  nodes: [
    別のノード,
  ]
}
```

textを持ったオブジェクトを数珠つなぎするだけです。
nodesに、配下に持たせるオブジェクトを置くことで数珠つなぎになります。配下がない場合はnodesは無しで良いです。
ツリーの構築は、それを指定するだけです。

```js
      $('#tree').treeview({
        data: [先頭のノード]
      });
```

今回のネットワーク管理の場合、このノードに自己利用の情報を持たせたかったので以下のようにしました。

```js:start.js
function make_node(target){
  return {
    text: target.name,
    icon: target.icon,
    uuid: target.uuid,
    parent_uuid: target.parent_uuid,
  };
}
```

uuidとparent_uuidは、ネットワーク管理で保持したい情報でして、bootstrap-treeviewに一緒に保持してもらっています。
textは先ほど説明しました。
iconは、CSSでアイコン名を指定すると、ツリーに表示してくれます。bootstra-treeviewの機能です。Bootstrap標準のglyphsに対応しているので、例えば、「glyphicon glyphicon-asterisk」と指定すれば、アスタリスクのアイコンが表示されます。また、もっとアイコンを増やすために、Font Awesomeのアイコンも追加しました。

Font Awesome
　https://fontawesome.com/

上記サイトにユーザ登録するとURLが指定されるのでそれをHTMLに含めるようにします。

```html:index.html
  <script src="https://kit.fontawesome.com/XXXXX.js" crossorigin="anonymous"></script>
```

XXXXは各自に合わせてください。
そうすることで、glyphsの代わりに、fas fa-desktop などが指定できるようになります。

# ツリーのノード選択時のイベントトリガ

ツリーのノードを選択したときに、ちょっとした処理を追加したい場合があります。
そのために、bootstra-treeviewにはイベントトリガーの機能がついています。
以下を追記します。

```js:start.js
$('#tree').on('nodeSelected', this.node_selected);
```

これで、いずれかのノードが選択されると、上記の場合、「this.node_selected(event, data)」が呼び出されます。(ツリーを構築するたびに上記の設定が必要です。)
手動でノードを選択する場合は、以下を呼び出します。

```js:start.js
$('#tree').treeview('selectNode', [node]);
$('#tree').treeview('revealNode', node);
```

ただし、すでに選択されている状態で同じノードを選択した場合は、トリガーされないので、注意が必要です。
revealNodeは選択したノードが見えるようにツリーを展開するためのものです。必須ではありません。

さて、上記のselectNodeででてきたnodeというオブジェクトはどこから取得するのでしょうか。
それは、this.node_selected(event, data)で返ってきたdata がそれです。ちょっとわかりにくいですが。

選択しないとnodeを取得できないのは厳しいので、ほかのやり方を模索します。
text検索ではsearchを使う方法があるのですが、別の基準で検索したい場合は、ちょっと強引ですが以下のやり方をとっています。

```js:start.js
// UUIDからツリーのノードを検索
search_node_uuid: function(uuid){
  var data = $('#tree').treeview('getNode', 0);
  return search_tree_node(data, uuid);
},

function search_tree_node(data, uuid){
  if(data.uuid == uuid )
    return data;

  for( var i = 0 ; i < data.nodes.length ; i++ ){
    var node = search_tree_node(data.nodes[i], uuid );
    if( node != null )
      return node;
  }

  return null;
}
```

nodeの指定方法として、nodeIdでも指定ができます。
で、ノード生成時に指定した配列の一番最初のnodeオブジェクトのnodeIdは0になるようです。
ということで、まずは、0番のnodeオブジェクトを取得します。
そうすると、そのnodeオブジェクトだけでなくその配下のnodeオブジェクトもnodesに配列で保持されているのでそれをたどることで、searchと同様のことができます。
今回のネットワーク管理では、nodeオブジェクトに保持しておいたuuidで検索しています。

# ツリーにノード検索機能を付ける

先ほど、searchの方法があると述べましたが、その具体例です。

HTMLに以下を配置します。

```html:index.html
        <div class="input-group input-group-sm">
          <input type="text" class="form-control" v-on:change="do_search" v-model="search_name">
          <span class="input-group-addon" v-on:click="do_search">検索</span>
          <span class="input-group-addon" v-on:click="do_search_clear">クリア</span>
        </div><br>
```

v-on:clickに対応する実装です。

```js
    do_search: function(){
      var ret = $('#tree').treeview('search', [this.search_name]);
      if( ret.length > 0 )
        this.select_node(ret[0]);
    },
    do_search_clear: function(){
      this.search_name = '';
      $('#tree').treeview('clearSearch');
    },
```

これで、エディットボックスに文字列を入力してEnterを押下するとサーチが実行され、見つかるとノードが赤色になります。クリアボタンを押すと、選択状態が解除されます。

# サンプルアプリ：ネットワーク管理

こんな感じのネットワーク管理アプリを作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/91b1ad0c-6fc1-4482-9a24-eab0d71aa7dd.png)

ノードを追加したり、ツリー構成を変更したりできます。
IPアドレスの範囲指定ではなく、物理的な配線をイメージできるようにしました。
また、アイコン画像を指定できたり、サーバPCが公開しているWebページのURL(エンドポイント)を保持できるようにしています。
管理するネットワーク情報は、サーバ側にファイルとして保持しています。（かなり手を抜いた実装ですので、個人用と考えてください）

細かいことは、以下のGitHubにアップしておきましたので、ご興味のある方は見てみてください。

poruruba/network_manager
　https://github.com/poruruba/network_manager

セットアップ方法は以下の通りです。
・unzip network_manager.zip
・cd network_manager
・npm install
・mkdir data
・start.js内のbase_urlを配置したURLに変更
・node app.js

以上