我正在尝试创建一个多系列折线图(基于Mike Bostock示例),但是在多个数据集之间进行转换。我已经获得了进出的线条,但是每条线条的标签在它们应该消失后仍然存在。 Screenshot at this link.
此外,线路以奇怪的方式过渡;几乎就像他们只是在同一条线上创建一个新的(Second screenshot at this link)。
以下是我的代码的相关部分(我绘制线条并添加标签):
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();
答案 0 :(得分:0)
每次渲染时都会向每个人追加一个新文本元素,而不是删除旧文本元素。据推测,每次要使用新数据绘制图表时,您发布的代码都会运行,因此每次最终都会有更多的文本元素,而不是更新现有的文本元素。您只需要附加“输入”选项。您在路径元素上执行了此操作,因此您只需要使文本更像路径。我已用注释更新了您的示例,以突出显示我更改的内容。
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();
问题的关键在于personGroups.append('text')
而不是person.append('text')
。剩下的只是我过火了,并指出了其他一些改进代码的方法,这些方法应该更容易理解和维护。