我根据此处的示例创建了一个折线图:
http://bl.ocks.org/mbostock/3884955
但是,对于我的数据,线条标签(城市)最终会重叠,因为不同线条的y轴上的最终值经常靠近在一起。我知道我需要比较每一行的最后一个值,并在值相差12个或更少时向上或向下移动标签。我的想法是查看由这段代码写的文本标签
city.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.temperature) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
如果y(d.value.temperature)值相差12或更小,则将值移开,直到它们之间至少有12个单位。有关如何完成这项工作的任何想法?这是我的第一个d3项目,语法仍然适合我!
答案 0 :(得分:2)
你可能最好立刻传递所有标签 - 这也更符合一般d3的想法。然后你可以得到类似这样的代码:
svg.selectAll("text.label").data(data)
.enter()
.append("text")
.attr("transform", function(d, i) {
var currenty = y(d.value.temperature);
if(i > 0) {
var previousy = y(data[i-1].value.temperature),
if(currenty - previousy < 12) { currenty = previousy + 12; }
}
return "translate(" + x(d.value.date) + "," + currenty + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
这并未考虑到之前的标签可能已被移动的事实。您可以明确获取上一个标签的位置,并根据该位置移动当前标签。代码几乎相同,只是您需要保存对当前元素(this
)的引用,以便以后可以访问它。
所有这些都不会阻止标签与最终标记的线条相距很远。如果你需要移动每个标签,最后一个标签将相当遥远。更好的做法可能是单独创建一个图例,您可以根据需要对标签和行进行空格分隔。
答案 1 :(得分:1)
考虑使用D3力布局来放置标签。请在此处查看示例:https://bl.ocks.org/wdickerson/bd654e61f536dcef3736f41e0ad87786
假设您有一个data
数组,其中包含value
属性和比例y
的对象:
// Create some nodes
const labels = data.map(d => {
return {
fx: 0,
targetY: y(d.value)
};
});
// Set up the force simulation
const force = d3.forceSimulation()
.nodes(labels)
.force('collide', d3.forceCollide(10))
.force('y', d3.forceY(d => d.targetY).strength(1))
.stop();
// Execute thte simulation
for (let i = 0; i < 300; i++) force.tick();
// Assign values to the appropriate marker
labels.sort((a, b) => a.y - b.y);
data.sort((a, b) => b.value - a.value);
data.forEach((d, i) => d.y = labels[i].y);
现在,您的data
数组将具有代表其最佳位置的y
属性。
示例使用D3 4.0,请在此处阅读更多内容:https://github.com/d3/d3-force