【超初心者】D3.jpを使って相関図を書きたい①【ZoomやPanを実装する】

D3.jsを勉強中です。
D3.jsを使ってかっこいい相関図を書きたいなぁと思っていろいろ試行錯誤しています。
試行錯誤の元は、[D3js.org](https://d3js.org/)のExamplesの中にあった[これ](http://bl.ocks.org/mbostock/4062045)です。
(いつのまにやらv4系にアップデートされてますね)

<img src="https://qiita-image-store.s3.amazonaws.com/0/159216/646148a8-0c83-fe8f-d0ea-fc4acd97b298.png" alt="mizerable" title="mizerable" width="300" />

JOSNファイルを見るか●にカーソルを合わせれば判るのですが、レ・ミゼラブルの人物相関図です。これ。

#基本的なお話
相関図のようなグラフの場合、上の画像の●をnode、引かれている線をlinkと呼びます。 
あと、基本的にブラウザはChrome推奨です。

D3.jsで書いたけど、実際svgはどうかかれてるんだろうって思ったときは、svg領域上右クリックから開くことができるChromeの検証画面で確認しましょう。

![debug.PNG](https://qiita-image-store.s3.amazonaws.com/0/159216/d9283869-f054-a769-1cc2-02df6c3edc0d.png)


データを表示しようとしたら[object Object]と出てこまったなって時があります。そのときは以下のコマンドを差し込んで、データの中身をコンソールに表示させましょう。（dは適宜変更して･･･）

```js:hoge.js
console.log(JSON.stringify(d));
```




#準備
まずは上記の試行錯誤元にあるソースとJSONファイルをDLしてwebサーバに設定しましょう。404が出ちゃうときは、​IISでIMMAにJSONファイをル登録すればOK。IISじゃない場合はググってください。

上記のJSONファイルでは全てのnodeが何らかのlinkにつながっているので、テストのために、linkにつながっていないものを"nodes"と"links"の間あたり(80行目あたり)に追加しておきます。

```json:miserables.json
    {"id": "Brujon", "group": 4},
    {"id": "Mme.Hucheloup", "group": 8},
    {"id": "You", "group": 11},         ←追加
    {"id": "Reader1", "group": 12},     ←追加
    {"id": "Reader2", "group": 12}      ←追加
  ],
  "links": [
    {"source": "Reader1", "target": "Reader2", "value": 2},  ←追加
    {"source": "Reader2", "target": "Reader1", "value": 2},  ←追加
    {"source": "Napoleon", "target": "Myriel", "value": 1},
```

これで、node単体の"You"と、独立したlinkを持つ"Reader1""Reader2"が追加になります。

次に、表示領域が狭くて解りにくいので、htmlファイルのsvg領域を広くして色をつけます。

```html:hoge.html
<svg width="1024" height="768" style="background-color:#ddd"></svg>
```

次に、この例ではnodeとlinkの設定は個別に設定したいので、"style"タグごと消してしまいます。
これで、一応の準備が整いました。

#ZoomやPanを実装する
実際に表示してみると判るのですが、上で追加したlinkを持たないnode"You"や、独立している"Reader1""Reader1"が表示領域外にすっ飛んで行きます(笑)。とりあえず、こいつを探しにいけるようにします。

詳細な説明はGitHub上のREADMEを見たほうがいいです。
https://github.com/d3/d3-zoom

ZoomやPanを実装するには、svgを使用する方法とHTML5のCanvasを利用する方法がありますが、ここではsvgを利用する方法を中心に記載します。
canvasを利用する方法では、canvasのイベントとしてD3.zoomを呼び出すようですが、svgを利用する方法では、透明な矩形を作って、その矩形のイベントとしてD3.zoomを呼び出して実装するようです。
[svgでのサンプル](http://bl.ocks.org/mbostock/4e3925cdc804db257a86fdef3a032a45)
[canvasでのサンプル](http://bl.ocks.org/mbostock/d1f7b58631e71fbf9c568345ee04a60e)

では実装していきます。

##Zoomイベントを追加
まず、Zoomイベントを追加します。

```js:hoge.html

 d3.json("miserables.json", function(error, graph) {
  if (error) throw error;

//"svg"にZoomイベントを設定
svg.call(d3.zoom()
    .scaleExtent([1/4,4])
    .on('zoom', SVGzoomed));

//"svg"上に"g"をappendしてdragイベントを設定
var g = svg.append("g")
    .call(d3.drag()
    .on('drag',SVGdragged))

function SVGzoomed() {
  g.attr("transform", d3.event.transform);
}

function SVGdragged(d) {
    d3.select(this).attr('cx', d.x = d3.event.x).attr('cy', d.y = d3.event.y);
      };
```


##nodeとlinkのグループ変更

そして、nodeとlinkを透明な矩形があるグループ"g"にいれちゃう。

```js:hoge.html

  var link = g.append("g")       //svg⇒gに
      .attr("class", "links")
    .selectAll("line")

```


```js:hoge.html

  var node = g.append("g")       //svg⇒gに
      .attr("class", "nodes")
    .selectAll("circle")

```

Linkをドラッグするとなぜかchromeの検証画面でエラーがでてるので、なんとかしたい。
あと、最初に\<style>を削除しているので、輪郭線の色指定を追加しておきます。

![error1.PNG](https://qiita-image-store.s3.amazonaws.com/0/159216/c3a35e09-ab58-0c53-c0e8-f9ff74a33d03.png)


```js:hoge.html

  var link = g.append("g")  //svg⇒gに
      .attr("class", "links")
    .selectAll("line")
    .data(graph.links)
    .enter().append("line")
      .attr("stroke","#999")  //輪郭線の色指定追加
      .attr("stroke-width", function(d) { return Math.sqrt(d.value); })
      .call(d3.drag()　              //無いとエラーになる。。
          .on('start', dragstarted)
          .on('drag', dragged)
          .on('end', dragended));

```

"link"にd3.dragイベントを設定したらなんかうまくいきました。
<font color="Red">！！ここは後でちゃんと調べよう！！</font>

これで、ZoomとPanが実装できました。イメージはこちら。
![relation2.PNG](https://qiita-image-store.s3.amazonaws.com/0/159216/a7060ecd-cf3c-9954-3da8-49b498cbb385.png)


左下にある点がnode"You"です。ずいぶん遠くに飛んでいってますねw

[scaleExtent]で、Zoomの最大、最小を指定できますので、いい感じで調整しましょう。

まずはここまで。