Reputation: 511
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
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
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