D3.js dataの使い方 - Enter, Update, Exit
基本的な使い方
基本的な使い方
datasetを次のようにすると、<div>要素にデータが割り当てられる。
var dataset = [1, 2, 3, 4, 5, 6];
var div = d3.selectAll("div")
.data(dataset);
たとえば、<div>要素がない状態でstyle、textを指定すると、
d3.selectAll("div")
.data(dataset)
.enter()
.append("div")
.style("color", "red")
.text(
function (d) {
return "this data is " + d;
}
);
次のようにデータ数分の<div>要素が生成される。
既存要素に追加する
次のように<div>要素がすでに2つあるとする。
ここに次のように新しい要素を追加すると、新しく生成された要素が更新される。
d3.select("#view")
.selectAll("div")
.data(dataset)
.enter()
.append("div")
.style("color", "red")
.text(
function (d) {
return "this data is " + d
}
);
新しく生成された部分をenter領域、すでにある部分をupdate領域という。
update領域のデータを更新する
このupdate領域にstyleを適用するには、次のようにする。
d3.selectAll("div")
.data(dataset)
.style("color", "blue")
.text(
function (d) {
return "this data is " + d;
}
);
update領域とenter領域のスタイルを同時に変更する
update領域とenter領域のスタイルを同時に変更したい場合は多い。その場合は、次のようにまとめて変更できる。
var div = d3.selectAll("div")
.data(dataset);
var divEnter = div.enter()
.append("div");
var divUpdate = divEnter.merge(div);
divUpdate.style("color", "blue")
.text(
function (d) {
return "this data is " + d
}
);
exitを使用して余分な要素領域を指定する
一方、すでに上のように6つの<div>要素があり、割り当てられるデータが少ない場合は、exitを使用して余分な要素領域を指定できる。
dataset = ['A', 'B'];
var div = d3.selectAll("div")
.data(dataset)
.style("color", "red")
.text(function(d){return "this data is " + d;});
div.exit()
.style("color", "green");
exit領域のデータを削除する
exit領域のデータは削除することが多いため、次のように削除すればよい。
div.exit().remove();
Enter selection, Exit selection
D3の最も重要な概念であるUpdate、Enter、Exitについて見ていく。
Enter selection
まず、次のHTMLでenter selectionについて説明する。
<div class="fruitlist">
<div class="fruit">Apple</div>
<div class="fruit">Banana</div>
<div class="fruit">Cherry</div>
</div>
data()でdataを割り当てた後、DOM要素よりdataの数が多い場合、dataの数が多い部分をenter selectionと呼ぶ。
enter()でenter selectionに要素を追加できる。append()でデータを追加するには、selection.selectAll()メソッドを使用して親要素から選択する必要がある。
d3.select(".fruitlist")
.selectAll(".fruit")
.data([1, 2, 3, 4, 5])
.enter()
.append("div")
.text(d => `Extra fruit number ${d}`)
Exit selection
次に、次のHTMLでExit selectionについて見ていく。
<div>
<div class="lunch">Burger</div>
<div class="lunch">Hotdog</div>
<div class="lunch">Curry</div>
<div class="lunch">Pasta</div>
<div class="lunch">Pizza</div>
</div>
DOM要素よりdataの数が少ない場合、dataの数が少ない部分をexit selectionと呼ぶ。exit()でexit selectionを削除できる。
d3.selectAll(".lunch")
.data([1, 2, 3])
.exit()
.remove()
Update, Enter, Exitを使用して必要な場合だけDOMを更新する
D3チュートリアルを見ていると、存在しない要素をselectAll()した後にenter()を実行し、append()するパターンが突然出てきて戸惑うことがある。
存在しない要素に対してselectAll()を行う理由は、データ更新時に前回のDOM要素を再利用するためである。つまり、最初は存在しない要素をselectAll()するが、2回目には存在していることになる。このパターンを使ってみる。
この例では、div要素は最初は空である。
<style>
.chart div {
background-color: powderblue;
text-align: right;
margin: 1px;
transition: width 0.5s ease-in-out;
animation: fade-in 0.5s ease 0s 1 normal;
}
@keyframes fade-in {
0% { opacity: 0 }
100% {opacity: 1 }
}
</style>
<div class="chart"/>
データの更新がわかりやすいように、簡単なアニメーションを付けている。次のコードでランダムにデータを更新する。
function barchart(data) {
const chart = d3.select(".chart")
.selectAll("div")
.data(data)
.style("width", function(d) { return d + "px"; })
.text( d => d);
chart.enter()
.append("div")
.style("width", function(d) { return d + "px"; })
.text( d => d)
chart.exit().remove();
}
function updatebar() {
ndata = Math.floor(Math.random() * 5) + 5; // [5, 10)
data = d3.range(0, ndata).map(() => Math.floor(Math.random() * 300));
barchart(data);
}
setInterval(updatebar, 1000);