d3 Update pattern - Jelmerovereem/frontend-data GitHub Wiki

The d3 data update pattern is an important part of user interaction and data transformation.
So it's a crucial part to integrate into your (d3) visualization.

Enter, update & exit

My use case
In my visualization, the user can choose to view the garage capacity or if the garage is free/paid.
This is a great scenario to implement the d3 update pattern.

I have 2 sets of data for the 2 choices the user can make, one with the garages with capacity and the other one with the garages with free or paid.

The general data update pattern uses .enter() and .exit() like this:

const textEnter = textUpdate.enter().append("text");

const textExit = textUpdate.exit().remove();

But this way of updating your visualization is deprecated according to Mike Bostock on Observable.
A better way to update your visualization is with the "new" .join() method.

After studying the explanation of .join() from Mike Bostock I experimented and implemented it myself.

Let's break it down:
First you create a selection of the elements that need to be updated

let circle = group.selectAll("circle");

Join the data with .data()

circle
  .data(coordinates, d => d.areaId)

Now the interesting part with .join(), this enters circles with a radius of 4.

.join(
  enter => enter.append("circle")
     .attr("r", 4)
)

If the user chooses to view the paid/free data the old circles need to be removed with exit and .remove()

.join(
  enter => enter.append("circle")
     .attr("r", 4),
  exit => exit
     .attr("fill", "white")
     .call(exit => exit.transition().duration(500)
        .attr("opacity", 0)
	.remove())
)

And that's it! Now the visualization is updated according to the new data. You can also add the update => update in-between if you want to execute code when a circle(garage) is updated.

Final code:

let circle = group.selectAll("circle");

circle
  .join(
    enter => enter.append("circle")
       .attr("r", 4),
    exit => exit
       .attr("fill", "white")
       .call(exit => exit.transition().duration(500)
          .attr("opacity", 0)
	  .remove())
  )

Visualization

Sources