This article shows how D3's enter and exit methods can be used to achieve fine grained control over the behaviour of entering and exiting elements. This is particularly useful when dealing with transitioning elements.
This chapter explains how you can gain extra control over how HTML and SVG elements behave when they are created, updated or removed. It's particularly relevant when you're using transitions and want particular effects (such as elements fading in and out).
If you're new to D3 you can safely skip this chapter!
The examples in the data joins chapter update the HTML/SVG elements in the same manner, regardless of whether they've just been created, are already on the page or are about to be removed.
(HTML/SVG elements that have just been created are known as entering elements and ones that are about to be removed are known as exiting elements.)
In some instances it's useful to treat entering and exiting elements differently. This is especially the case when dealing with transitions. For example, if you'd like new elements to fade in you need to set their initial opacity to zero. Likewise if you'd like them to fade out before being removed, you need to set up a transition on each exiting element so that their opacity gradually reduces to zero.
Version 4 and below of D3 required you use a selection's
.enter
and.exit
methods. However from version 5 the.join
method hides the intricacies of enter and exit from you. If you're still working with version 4 you can still view the original chapter on enter and exit.
You can treat entering and exiting elements differently by passing functions into the .join
method:
.join(
function(enter) {
...
},
function(update) {
...
},
function(exit) {
...
}
)
The first, second and third functions are named the enter, update and exit functions, respectively.
Each function has a single parameter::
- the enter function's parameter
enter
is the enter selection which represents the elements that need to be created - the update function's parameter
update
is a selection containing the elements that are already in existence (and aren't exiting) - the exit function's parameter
exit
is the exit selection and contains elements that need to to be removed
The .join
method returns a selection containing the entering and existing elements (it doesn't contain exiting elements). Typically most of your style and attribute updates will follow the .join
method.
Note that the enter, update and exit functions must return the selection.
Enter function
In general the enter function must append an element to each element of the enter selection. (The enter selection consists of 'placeholder' elements that represent the elements that need to be added.)
For example:
.join(
function(enter) {
return enter.append('circle');
}
)
This is equivalent to .join('circle')
.
You can also call the usual selection methods such as .style
and .attr
on the enter selection. This allows you to modify style and attributes of the entering elements.
For example:
.join(
function(enter) {
return enter
.append('circle')
.style('opacity', 0);
}
)
Update function
The update function is optional and lets you update elements that are already in existence. For example:
.join(
function(enter) {
return enter
.append('circle')
.style('opacity', 0);
},
function(update) {
return update.style('opacity', 1);
}
)
This will set the opacity of entering circles to zero and the opacity of existing circles to 1.
Exit function
The exit function is optional and handles HTML/SVG elements that need to be removed. In general you need to remove the elements in the exit selection:
.join(
function(enter) {
return enter
.append('circle')
.style('opacity', 0);
},
function(update) {
return update
.style('opacity', 1);
},
function(exit) {
return exit.remove();
}
)
Example
If you're not using transitions you rarely need to the above techniques. However if you are using transitions and you want to control how elements enter and exit the page, you will need the above techniques. See the transitions chapter for examples using transitions.
For now, to help your understanding, here's an example that sets the opacity of entering nodes to 0.25:
function getData() {
let data = [];
let numItems = Math.ceil(Math.random() * 5);
for(let i=0; i<numItems; i++) {
data.push(40);
}
return data;
}
function update(data) {
d3.select('.chart')
.selectAll('circle')
.data(data)
.join(
function(enter) {
return enter.append('circle')
.style('opacity', 0.25);
},
function(update) {
return update.style('opacity', 1);
}
)
.attr('cx', function(d, i) {
return i * 100;
})
.attr('cy', 50)
.attr('r', function(d) {
return 0.5 * d;
})
.style('fill', 'orange');
}
function updateAll() {
let myData = getData();
update(myData);
}
updateAll();
d3.select("button")
.on("click", updateAll);
The enter function appends a circle
to each element in the enter selection and sets their opacity to 0.25. The update function sets the opacity of existing circles to 1. The .attr
and .style
methods after the .join
method apply to entering and existing elements.
Now circles that have just entered the page are feint, while those that were already in existence are solid.
The above example is not very representative of how you'd use enter, exit and update functions in practice. See the transitions for more representative examples.