简体   繁体   English

D3过渡时退出多系列折线图标签

[英]D3 exit mutli-series line chart labels on transition

I'm trying to create a multi-series line chart (based off the Mike Bostock example) but transitioning between multiple data sets. 我正在尝试创建多系列折线图(基于Mike Bostock示例),但是要在多个数据集之间进行转换。 I have gotten the lines to transition in and out, but the labels for each line stick around after they should have disappeared. 我已经获得了要过渡的线,但是每条线的标签在消失后仍会粘在上面。 Screenshot at this link. 此链接的屏幕截图。

Furthermore, the lines are transitioning in an odd way; 此外,线路正在以奇怪的方式过渡; almost like they are just extending the same line to create a new one (Second screenshot at this link) . 几乎就像他们只是在延伸同一行以创建新行一样(此链接的第二张屏幕截图)

Here is the relevant part of my code (where I draw the lines and add labels): 这是我的代码的相关部分(在此处绘制线并添加标签):

  var line = d3.svg.line() .interpolate("basis") .x(function(d) { return x(d.Date); }) .y(function(d) { return y(d.candidate); }); var person = svg_multi.selectAll(".candidate") .data(people); var personGroups = person.enter() .append("g") .attr("class", "candidate"); person .enter().append("g") .attr("class", "candidate"); personGroups.append("path") .attr("class", "line") .attr("d", function(d) { return line(d.values); }) .style("stroke", function(d) { return color(d.name); }); var personUpdate = d3.transition(person); personUpdate.select("path") .transition() .duration(1000) .attr("d", function(d) { return line(d.values); }); person .append("text") .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) .attr("transform", function(d) { return "translate(" + x(d.value.Date) + "," + y(d.value.candidate) + ")"; }) .attr("x", 3) .attr("dy", ".35em") .text(function(d) { return d.name; }); person.selectAll("text").transition() .attr("transform", function(d) { return "translate(" + x(d.value.Date) + "," + y(d.value.candidate) + ")"; }); person.exit().remove(); 

You are appending a new text element to each person every time you render and not removing the old ones. 您每次渲染时都会向每个人添加一个新的text元素,而不是删除旧的text元素。 Presumably the code you posted gets run every time you want to draw the chart with new data, so you end up with more text elements every time, rather than updating the existing ones. 假设您每次想用新数据绘制图表时,都会运行您发布的代码,因此,您每次都会得到更多文本元素,而不是更新现有文本元素。 You need to only append on the "enter" selection. 您只需要在“输入”选项上附加。 You did this right on the path elements, so you just need to make the text work more like the path. 您在path元素上执行了此操作,因此只需要使文本更像path即可工作。 I've updated your example with comments to highlight what I changed. 我用注释更新了您的示例,以突出显示我所做的更改。

 var line = d3.svg.line() .interpolate("basis") .x(function(d) { return x(d.Date); }) .y(function(d) { return y(d.candidate); }); var person = svg_multi.selectAll(".candidate") // I added a key function here to make sure you always update the same // line for every person. This ensures that when you re draw with different // data, the line for Trump doesn't become the line for Sanders, for example. .data(people, function(d) { return d.name}); var personGroups = person.enter() .append("g") .attr("class", "candidate"); // This isn't needed. The path and text get appended to the group above, // so this one just sits empty and clutters the DOM // person // .enter().append("g") // .attr("class", "candidate"); personGroups.append("path") .attr("class", "line") // You do this down below, so no need to duplicate it here // .attr("d", function(d) { return line(d.values); }) .style("stroke", function(d) { return color(d.name); }); // Append the text element to only new groups in the enter selection personGroups.append("text") // Set any static attributes here that don't update on data .attr("x", 3) .attr("dy", ".35em"); var personUpdate = d3.transition(person); personUpdate.select("path") .transition() .duration(1000) .attr("d", function(d) { return line(d.values); }); person.select("text") // You don't have to do this datum call because the text element will have // the same data as its parent, but it does make it easier to get to the last // value in the list, so you can do it if you want .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) .attr("transform", function(d) { return "translate(" + x(d.value.Date) + "," + y(d.value.candidate) + ")"; }) .text(function(d) { return d.name; }); // Remove this. You don't need it anymore since you are updating the text above // person.selectAll("text").transition() // .attr("transform", function(d) { return "translate(" + x(d.value.Date) + "," + y(d.value.candidate) + ")"; }); person.exit().remove(); 

The key to your question was really just doing personGroups.append('text') rather than person.append('text') . 您问题的关键实际上只是在执行personGroups.append('text')而不是person.append('text') The rest was just me going overboard and pointing out some other ways to improve your code that should make it easier to understand and maintain. 剩下的就是我全力以赴,并指出其他一些改进代码的方法,这些代码应该使它更易于理解和维护。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM