D3.js data usage - Enter, Update, Exit
Basic usage
Basic usage
If dataset is written as follows, data is assigned to the <div> elements.
var dataset = [1, 2, 3, 4, 5, 6];
var div = d3.selectAll("div")
.data(dataset);
For example, if there are no <div> elements and you specify style and text,
d3.selectAll("div")
.data(dataset)
.enter()
.append("div")
.style("color", "red")
.text(
function (d) {
return "this data is " + d;
}
);
<div> elements are created for the number of data items as shown below.
Adding to existing elements
Suppose there are already two <div> elements as shown below.
If you add new elements as follows, the newly created elements are updated.
d3.select("#view")
.selectAll("div")
.data(dataset)
.enter()
.append("div")
.style("color", "red")
.text(
function (d) {
return "this data is " + d
}
);
The newly created part is called the enter area, and the existing part is called the update area.
Updating data in the update area
To apply styles to this update area, write the following:
d3.selectAll("div")
.data(dataset)
.style("color", "blue")
.text(
function (d) {
return "this data is " + d;
}
);
Changing styles in the update and enter areas at the same time
There are many cases where you want to change the styles of both the update area and the enter area at the same time. In that case, you can change them together as follows:
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
}
);
Using exit to specify extra element areas
On the other hand, if there are already six <div> elements as above and fewer data items are assigned, you can use exit to specify the extra element area.
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");
Removing data in the exit area
In most cases, data in the exit area is removed, so remove it as follows:
div.exit().remove();
Enter selection, Exit selection
Now look at Update, Enter, and Exit, which are among the most important concepts in D3.
Enter selection
First, the following HTML is used to explain enter selection.
<div class="fruitlist">
<div class="fruit">Apple</div>
<div class="fruit">Banana</div>
<div class="fruit">Cherry</div>
</div>
After assigning data with data(), when there are more data items than DOM elements, the part with more data is called the enter selection.
You can add elements to the enter selection with enter(). To add data with append(), select from the parent element using the selection.selectAll() method.
d3.select(".fruitlist")
.selectAll(".fruit")
.data([1, 2, 3, 4, 5])
.enter()
.append("div")
.text(d => `Extra fruit number ${d}`)
Exit selection
Next, examine Exit selection with the following HTML.
<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>
When there are fewer data items than DOM elements, the part with fewer data items is called the exit selection. You can remove the exit selection with exit().
d3.selectAll(".lunch")
.data([1, 2, 3])
.exit()
.remove()
Updating the DOM only when needed with Update, Enter, and Exit
When following D3 tutorials, you may be surprised by the pattern where selectAll() is called for elements that do not exist, followed by enter() and append().
The reason for calling selectAll() on elements that do not exist is to reuse the previous DOM elements when data is updated. In other words, the elements do not exist the first time selectAll() is called, but they do exist the second time. Try using this pattern.
In this example, the div element is empty at first.
<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"/>
A simple animation is added so that data updates are easy to understand. The following code updates the data randomly.
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);