Update patterns in D3 - lennartdeknikker/frontend-data GitHub Wiki

To update data points in D3, there's an update pattern that's commonly used to get your data in, delete superfluous elements or create new elements if there's more data.

Binding data

To bind your data to elements in d3, you can use d3.data(). In my case, the update pattern then starts like this.

	const datapoints = d3
		.select('.g-datapoints')
		.selectAll('.datapoint')
		.data(objects)
		.attr('r', 0);
``
First, I select the group that contains all data points. Then, the elements that need to be updated are selected, using `.selectAll()` and the new data is connected with `data`. 
If the array of data is longer than the selection of elements, new elements need to be appended. If the new array is shorter, the surplus of elements need to be deleted.

## .enter()
By using `enter()` the possible surplus of data is selected. Then new elements need to be appended to this selection. In my code this is accomplished by `.append(circle)`. 
```js
datapoints.enter()
          .append('circle')

Because I need to change the cx and cy properties for all elements, both the new ones as the old ones, I use .merge() to combine the current selection of new elements with the old elements. Then I have the connected data define the properties for all elements in this selection like this:

datapoints		
	  .merge(datapoints)
	  .attr('class', 'datapoint')
	  .attr('data-place', d => d.placeName)
	  .attr('data-long', d => d.long)
	  .attr('data-lat', d => d.lat)
	  .attr('cx', d => projection([d.long, d.lat])[0])
	  .attr('cy', d => projection([d.long, d.lat])[1])
	  .attr('fill', '#00827b')

To bind interaction to all elements, I then add some event handlers:

datapoints
	  .on('mouseover', objectMouseoverHandler)
	  .on('mouseout', objectMouseoutHandler)
	  .on('click', objectClickHandler);

As said before, it's important to remove a possible surplus of elements. That part is accomplished using this last line of code. exit() selects the surplus and .remove() removes these elements.

	datapoints.exit().remove();

At D3InDepth, a general update pattern is defined. Alltogether, the pattern on that page with examples looks like this:

function update(data) {
  var u = d3.select('#content')
    .selectAll('div')
    .data(data);

  u.enter()
    .append('div')
    .merge(u)
    .text(function(d) {
      return d;
    });

  u.exit().remove();
}

Source

.join()

The pattern I used, found on d3InDepth is a bit outdated. The new pattern proposed by Mike Bostock uses data join. This new pattern makes it possible to add separate transitions to both the enter and the exit selection as well as the update selection. This pattern is a bit more complicated though and I didn't need to add different transitions to each selection, which is why I didn't use it.

.join combines both adding elements to the enter selection as removing elements from the exit selection. Within this function, it's possible to manipulate enter, update and exit selections separately. The syntax for this is as follows:

.join(
      enter => enter.attr(),
      update => update.attr(),
      exit => exit.attr()

The first question I would ask, was: why would you want to manipulate the exit selection if you remove it anyways. It's there because it enables you to add different transitions on this selection, so the elements don't just disappear anymore. You can make those disappear gradually now.