Brendan
Brendan

Reputation: 511

D3 and updating elements of a multidimensional array

Let's say that I have a 2d array called state that looks like [[0,1,0],[1,1,0],[1,2,1]]. The members of this array are constantly updating. I have D3 successfully rendering each member of the array with the following code:

function view(state)
  const vis = d3.select('body')
                .selectAll('div')
                .data(state)
                .enter()
                  .append('div')
                  .attr('style', 'display: flex')
                  .selectAll('span')
                  .data((d,i) => d)
                  .enter()
                    .append('span')
                    .text(d => d)
  return vis
}

Now consider that this view function is called every time my state changes. How can I get D3 to re-render only the elements that have changed since the previous render? Currently, the page renders initially but D3 never re-renders any of the elements, despite the view function being called at each state change.

If you'd like to see the full source, I posted it here

Upvotes: 2

Views: 792

Answers (2)

Dmitry
Dmitry

Reputation: 1706

You have 2 cases when you want to render your data: when you add new view elements (divs, spans and text), and when you update your data (text). In your code you've done the first step only. You should do the second one.

d3.js provides selections for both cases. When you write

var div = d3.select('body').selectAll('div');

you get what already exists on your view. But if you add .enter(), i.e.

var div = d3.select('body').selectAll('div').enter();

it is already the second case. You are getting what doesn't exist yet, and should be created.

Since your data are changing, you should divide your code into two parts: view creation, view updating.

Here is a JSFiddle example how it could be done for you code. The example can be improved, and the create/update code sections can be separated and put to corresponding functions, see there.

Anyway, I encourage you to read the general update pattern for d3.js.

Upvotes: 0

Cyril Cherian
Cyril Cherian

Reputation: 32327

Yeah to handle such a case you need to make use of enter which you are doing to create new elements and exit to remove any element not in the current array.

I ll recommend you to do it this way:

function view(state)
  var visData = d3.select('body')
                .selectAll('div')
                .data(state, function(d){/*uniquely identify each element in array*/return d;});

  const vis =  visData.enter()
                  .append('div')
                  .attr('style', 'display: flex')
                  .selectAll('span')
                  .data((d,i) => d)
                  .enter()
                    .append('span')
                    .text(d => d);
  //remove the unnecessary data divs.
  visData.exit().remove();

  return vis
}

Further on enter exit read

Upvotes: 2

Related Questions