Contents

How to Add an Update Function in D3.js? [Part 2]

Hello world! Welcome to the Part 2 of this article. In the first part we saw how to update scales and axis in a bar chart using an update function. Today, we will manage the update of the size and the position of the rectangles in the chart. Let’s do it!

1. Data Join

The first step is to select all matching elements on the screen with selectAll and update the data that we are using.

const rectangles = svg.selectAll("rect").data(data);

2. Exit

Then we use the exit() selector to remove the elements that don’t exist in our new array of data.

rectangles.exit().remove();

3. Update

Now, we set attributes for existing elements on the screen.

1
2
3
4
5
rectangles
	.attr("y", d => y(d.revenue))
	.attr("x", (d) => x(d.year))
	.attr("width", x.bandwidth)
	.attr("height", d => 340 - y(d.revenue))

4. Enter

Finally, we use the enter() selector to set attributes for new items in our data array.

1
2
3
4
5
6
7

rectangles.enter().append("rect")
	.attr("y", d => y(d.revenue))
	.attr("x", (d) => x(d.year))
	.attr("width", x.bandwidth)
	.attr("height", d => 340 - y(d.revenue))
	.attr("fill", "green")

This four snippets should be add just below the yAxisGroup call. In this way, when you will add data to the domain, the position and the size of the rectangles in the chart will automatically updated.

Finally you should have a full update function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function update(data){
   y .domain([0, d3.max(data, d => d.revenue)])    // input
   x.domain(data.map(d => d.year))    // input

   const xAxisCall = d3.axisBottom(x)
   g.append("g")
        .attr("class", "x axis")
        .attr("transform", `translate(0, 340)`)
        .call(xAxisCall)
        .selectAll("text")
        .attr("y", "10")
        .attr("x", "-5")
        .attr("text-anchor", "end")
        .attr("transform", "rotate(-40)")

   const yAxisCall = d3.axisLeft(y)
    .ticks(3)
    .tickFormat(d => "$"+d)
   g.append("g")
      .attr("class", "y axis")
      .call(yAxisCall)

   const rectangles = svg.selectAll("rect").data(data);
   rectangles.exit().remove();
   rectangles
	.attr("y", d => y(d.revenue))
	.attr("x", (d) => x(d.year))
	.attr("width", x.bandwidth)
	.attr("height", d => 340 - y(d.revenue))

  rectangles.enter().append("rect")
	.attr("y", d => y(d.revenue))
	.attr("x", (d) => x(d.year))
	.attr("width", x.bandwidth)
	.attr("height", d => 340 - y(d.revenue))
	.attr("fill", "green")
}

I hope you enjoyed this article. Do not hesitate to ask your questions in DM. See you!