d3js v4 子要素のデータバインド

# はじめに
[d3js Version 4.12.2](https://d3js.org/)
v4になって変更点がありデバッグ用にリアルタイムでテーブルを書こうとして
数時間はまりました。覚書です。

# シンプルな子要素の例
tableのtbodyをデータからリアルタイムに更新する。
データから配列の数だけtrを作って、propertyの数だけtdを作る。
dataはtrにバインドするけど中のtdのテキストを変える。

```html
<tbody>
	<tr>
		<td class="property1">value1</td>
		<td class="property2">value2</td>
		<td class="property3">value3</td>
	</tr>
	<tr>
		<td class="property1">value4</td>
		<td class="property2">value5</td>
		<td class="property3">value6</td>
	</tr>
	<tr>
		<td class="property1">value7</td>
		<td class="property2">value8</td>
		<td class="property3">value9</td>
	</tr>
</tbody>
```
dataからこのようなHTMLをd3jsで描画する。
trの数、valueはどんどん入れ替わるがpropertyの数は変わらない。


##data (json)
```js
[{
  property1 : value1,
  property2 : value2,
  property3 : value3
},{
  property1 : value4,
  property2 : value5,
  property3 : value6
},{
  property1 : value7,
  property2 : value8,
  property3 : value9
}]
```

## pug(HTML)
```pug
table
	thead
		tr
			th.property1 property1
			th.property2 property2
			th.property3 property3
	tbody
```

## js
```js
// trにデータを入れていく
var trAll = d3.select("tbody")
	.selectAll("tr")
	.data(data);
// 配列がなくなってたらtrを消す
trAll.exit().remove();

// 配列が増えてたらtrを追加してtdを入れておく
var trEnter = trAll.enter()
	.append("tr");
trEnter.append("td")
	.attr('class','property1');
trEnter.append("td")
	.attr('class','property2');
trEnter.append("td")
	.attr('class','property3');

// 配列が増えた時と新しいデータが来たときtdの中身を変える
trEnter = trEnter.merge(trAll);
trEnter.select("td.property1")
	.text(function(d){
		return d.property1;
	});
trEnter.select("td.property2")
	.text(function(d){
		return d.property2;
	});
trEnter.select("td.property3")
	.text(function(d){
		return d.property3;
	});
```
たったこれだけ。
jsは新しいデータがくるたびにまるごと呼びなおして大丈夫。

##はまったとこ
tdの中身を変える際にtdをselectAllで選択するとdataが更新されなくなる。
最初の１回（たぶんenter時）はちゃんと動く。

##js (ダメな例)
```js
// trにデータを入れていく
var trAll = d3.select("tbody")
	.selectAll("tr")
	.data(data);
// 配列がなくなってたらtrを消す
trAll.exit().remove();

// 配列が増えてたらtrを追加してtdを入れておく
var trEnter = trAll.enter()
	.append("tr");
trEnter.append("td")
	.attr('class','property1');
trEnter.append("td")
	.attr('class','property2');
trEnter.append("td")
	.attr('class','property3');

// 配列が増えた時と新しいデータが来たときtdの中身を変える
trEnter = trEnter.merge(trAll);

//////////////////////////
////// ↓これはだめ //////
//////////////////////////
trEnter.selectAll("td")  // <<< これはだめらしい。
	.text(function(d,index){
		// 更新のたび呼ばれるけどdが最初のデータのまま
		return d["property" + (index+1)];
	});
```
数時間調べたけどよくわからなかった。
selectAllの後にdataを見ても更新されているが、text中では更新されなくなる。
method名から考えるとバグっぽいのでこの問題はなくなるかもです。

# 子要素もさらに配列になっている例
tableのtbodyをデータからリアルタイムに更新する。
データから配列の数だけtrを作って、propertyの数だけtdを作る。
dataはtrにバインドするけど中のtd.property1のテキストを変え
さらにtd.property2の中に配列の数だけspanを作る。

```html
<tbody>
	<tr>
		<td class="property1">name1</td>
		<td class="property2">
			<span>value1</span>
			<span>value2</span>
			<span>value3</span>
		</td>
	</tr>
	<tr>
		<td class="property1">name2</td>
		<td class="property2">
			<span>value4</span>
			<span>value5</span>
		</td>
	</tr>
	<tr>
		<td class="property1">name3</td>
		<td class="property2">
			<span>value6</span>
			<span>value7</span>
			<span>value8</span>
			<span>value9</span>
		</td>
	</tr>
</tbody>
```
dataからこのようなHTMLをd3jsで描画する。
trの数、valueの数と内容はどんどん入れ替わるがpropertyの数は変わらない。

##data (json)
```js
[{
  property1 : name1,
  property2 : [value1,value2,value3]
},{
  property1 : name2,
  property2 : [value4,value5]
},{
  property1 : name3,
  property2 : [value6,value7,value8,value9]
}]
```

## pug(HTML)
```pug
table
	thead
		tr
			th.property1 property1
			th.property2 property2
	tbody
```
## js
```js
var trAll = d3.select("tbody")
	.selectAll("tr")
	.data(data);
trAll.exit().remove();

var trEnter = trAll.enter()
	.append("tr");
trEnter.append("td")
	.attr('class','property1');
trEnter.append("td")
	.attr('class','property2');

trEnter = trEnter.merge(trAll);
trEnter.select("td.property1")
	.text(function(d){
		return d.property1;
	});

var spanAll = trEnter.select("td.property2")
	.selectAll("span")
	.data(function(d){
		return d.property2;
	});
spanAll.exit().remove();
var spanEnter = spanAll.enter()
	.append('span');
spanEnter = spanEnter.merge(spanAll);
spanEnter.text(function(d){
		return d;
	});
```
jsは新しいデータがくるたびにまるごと呼びなおして大丈夫。

#さいご
かなりのデータ量と秒間何回も更新されるデータをコンソールでデバッグするのにつかれたので、htmlで見るようにするときはまりました。

d3jsは同じような感じでsvgも書けます。
かなり昔に作った地震のモニタ
![ezgif-1-9b436b33fd.gif](https://qiita-image-store.s3.amazonaws.com/0/198768/f3778405-ec84-1793-5b33-83750bb73efe.gif)
htmlですが地図の部分は地形も含めてd3のsvgで書いてます。
data drivenってすごい。