Reputation: 2012
I update my data (using d3) twice with exactly the same model.
During the first update I can see that data().enter() contains some elements and data().exit() is empty. That is understandable for me.
During second update (with the same model) data().enter() is empty (as I thought), but data().exit() is not empty and because of that it removes all the nodes during second update. This is what I don't understand.
Here is simplified code (and jsfiddle; look at the console):
// http://jsfiddle.net/24yqteo0/
// http://jsfiddle.net/6du29258/ - example with displaying some data
var model = {
smth: 'test',
rows: [
{
label: 'label1',
series: [
{
test: 'test1_1'
},
{
test: 'test1_2'
}
]
},
{
label: 'label2',
series: [
{
test: 'test2'
}
]
}
]
};
var svg = d3.select("body").append("svg");
updateData(model);
console.log('// ------------- new update');
updateData(model);
function updateData(model) {
var selection = svg.selectAll('g').data(model.rows);
console.log('selection enter size: ' + selection.enter().size());
var rows = selection.enter().append('g');
var rowData = rows.append('g').selectAll('g')
.data(function (d) {
return d.series;
});
console.log('rowdata enter size: ' + rowData.enter().size());
var seriesGroup = rowData.enter().append('g');
console.log('rowdata exit size: ' + rowData.exit().size());
rowData.exit().remove();
console.log('selection exit size: ' + selection.exit().size());
selection.exit().remove();
}
Upvotes: 2
Views: 56
Reputation: 2970
Well, it is not helpful for debugging when you use just plain g
elements for nested enters and exits.
I replaced the seriesGroup
appends with text
as follows fiddle here:
var seriesGroup = rowData.enter()
.append('text')
.text(function (d) { return d.test; });
I quickly spotted the problem in you code. It is actually the first line of updateData
var selection = svg.selectAll('g').data(model.rows);
This selection includes ALL g
elements, including nested ones. (console.log selection to confirm)
To prevent this behavior, you can add a more precise selector, such as class
var selection = svg.selectAll('g.row').data(model.rows);
and then append
var rows = selection.enter()
.append('g')
.classed('row', true);
Similarly for the second level:
var rowData = rows.append('g').selectAll('g.series')
and then
var seriesGroup = rowData.enter()
.append('g')
.classed('series', true);
Hope this helps.
Upvotes: 2