Reputation: 4212
I have a linechart, and by default I need to show just a subset of elements, then show a different subset on dropdown event.
Here is initial code:
varlines = svg.append("g")
.attr('id', 'lines')
.selectAll('g')
.data(datum.filter(function(d) {
return d.group == 'default'
}),
function(d) {
return d.name
}
).enter()
.append("g")
.attr("class", 'varline')
.append("path")
.attr("class", "line")
.attr("id", function(d) {
return 'line_' + d.name
})
.attr("d", function(d) {
return line(d.datum);
});
And it works fine. Now, here is the code that meant to update my selection:
$('.dropdown-menu a').click(function(d) {
var g = this.text;
dd.select("button").text(g) // switch header
var newdata = datum.filter(function(d) {
return d.group == g
}); # datalines for selected group
varlines.data(newdata, function(d) { return d.name })
.enter()
.merge(varlines)
.append("g")
.attr("class", 'varline')
.attr("id", function(d) {
return 'line_' + d.name
})
.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.datum);
});
varlines.exit().remove()
And it works weird. While it adds stuff and does not duplicate dom elements, it doesn't remove old ones.
Also, when I console.log(varlines);
at any step, it shows only two initial elements in the _groups
Array, and no _enter
and _exit
properties, even having 3 lines in the svg.
I am using d3v4, jquery3.1.1.slim
Upvotes: 1
Views: 787
Reputation: 102194
If you look at your varlines
, you'll see that it is just an enter selection:
varlines = svg.append("g")
.attr('id', 'lines')
.selectAll('g')
.data(datum.filter(function(d) {
return d.group == 'default'
}),
function(d) {
return d.name
}
).enter()
.append("g")
//etc...
And, of course, you cannot call exit()
on an enter selection. Therefore, this:
varlines.exit().remove()
... is useless.
Solution: make varlines
an "update" selection by breaking it (I'm using var
here, so we avoid it being a global):
var varlines = svg.append("g")
.attr('id', 'lines')
.selectAll('g')
.data(datum.filter(function(d) {
return d.group == 'default'
}),
function(d) {
return d.name
}
);
varlines.enter()
.append("g")
//etc...
Pay attention to this fact: since you're using D3 v4, you have to use merge()
, otherwise nothing will show up the first time the code runs. Alternativelly, you can just duplicate your code:
varlines = svg.append("g")
.attr('id', 'lines')
.selectAll('g')
.data(datum.filter(function(d) {
return d.group == 'default'
}),
function(d) {
return d.name
}
)
varlines.enter()
.append("g")
//all the attributes here
varlines.//all the attributes here again
EDIT: the problem in your plunker is clear: when you do...
.attr("class", "line")
... you are overwriting the previous class. Therefore, it should be:
.attr("class", "varline line")
Here is the updated plunker: https://plnkr.co/edit/43suZoDC37TOEfCBJOdT?p=preview
Upvotes: 3
Reputation: 4212
Here is my new code following Gerardo's recommendations as well as this Mike's tutorial: https://bl.ocks.org/EmbraceLife/efb531e68ce46c51cb1df2ca360348bb
function update(data) {
var varlines = svg.selectAll(".varlines")
.data(data, function(d) {return d.name});
// ENTER
// Create new elements as needed.
//
// ENTER + UPDATE
varlines.enter().append("g")
.attr("class", 'varline')
.attr("id", function(d) {
return 'line_' + d.name
})
.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.datum);
})
.style('stroke', function(d) {
return z(d.name)
});
// .merge(varlines); does not help if uncomment and move after .enter()
// EXIT
// Remove old elements as needed.
varlines.exit().remove();
}
and then in the initial code (queue.await(...)):
svg.append("g")
.attr('id', 'lines');
var data = datum.filter(function(d){return (d.group ==
settings['groups_settings']['default_group']) && (d.tp == tp)});
update(data)
and the same on dropdown change event:
var newdata = datum.filter(function(d){return (d.group == g) && (d.tp == tp)});
update(newdata);
Behaviour remains the same - correctly displays first batch, but does not remove lines on any changes (just keeps adding lines)
on print .selectAll returns this:
Selection {_groups: Array(1), _parents: Array(1), _enter: Array(1), _exit: Array(1)}
_enter:[Array(6)]_exit
:[Array(0)]_groups
:[Array(6)]
_parents:[svg]
__proto__:Object]
here is the full code: https://gist.github.com/Casyfill/78069927d2b95bf4856aa8048a4fa4be
Upvotes: 0