我正在尝试一种方法来获取彼此相邻的路径,这样它们就会相互推动(分解宽度和相邻点)并且不会重叠。
这是我的小提琴,大多是从例子中拼凑而成的 https://jsfiddle.net/crimsonbinome22/k2xqn24x/
var LineGroup = svg.append("g")
.attr("class","line");
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return (d.x); })
.y(function(d) { return (d.y); })
;
LineGroup.selectAll(".line")
.data(series)
.enter().append("path")
.attr("class", "line")
.attr("d", function(d){ return line(d.p); })
.attr("stroke", function(d){ return d.c; })
.attr("stroke-width", function(d){ return d.w; })
.attr("fill", "none");
这是我希望在this image here中实现的,基本上是:
我遇到的一些问题:
我已经进行了搜索,但找不到任何有关如何执行此操作的示例。在某种程度上,它几乎像一个和弦图,但有点不同,我找不到很多相关的代码可以重用。如何实现这一点的任何帮助(无论是我已经开始的方法,还是我错过了它的完全不同的东西)将不胜感激。
答案 0 :(得分:2)
我会采取以下步骤:
编辑:运行示例 https://jsfiddle.net/toh7d9tq/1/
我在最后两个步骤中使用了稍微不同的方法(计算偏移量):我实际上为每个系列创建一个新的p
数组,其中包含一对{node, offset}
对。通过这种方式,可以更轻松地访问绘图功能中的所有相关数据。
我需要添加一个人工根来获得一个漂亮的起始线(并使其更容易递归和角度以及所有内容),如果需要,可以在绘图阶段跳过它。
function key(p) {
return p.time+"_"+p.value
}
// a node has fields:
// - time/value (coordinates)
// - series (set of series going through)
// - parent/children (tree structure)
// - direction: angle of the arc coming from the parent
//artificial root
var root={time:200, value:height, series:[], direction:-Math.PI/2};
//set of nodes
var nodes = d3.map([root], key);
//create nodes, link each series to the corresponding leaf
series.forEach(function(s){
s.pWithOffset=[]; //this will be filled later on
var parent=root;
s.p.forEach(function(d) {
var n=nodes.get(key(d));
if (!n) {
//create node at given coordinates if does not exist
n={time:d.time,
value:d.value,
parent:parent,
series:[],
direction:Math.atan2(d.value-parent.value, d.time-parent.time)};
nodes.set(key(n),n);
//add node to the parent's children
if (!parent.children) parent.children=[];
parent.children.push(n);
}
//this node is the parent of the next one
parent=n;
})
//last node is the leaf of this series
s.leafNode=parent;
parent.series.push(s);
})
//sort children by direction
nodes.values().forEach(function(n){
if (n.children)
n.children.sort(function (a,b){
if (a.direction>n.direction)
return a.direction-b.direction;
});
});
//recursively list all series through each node (bottom-up)
function listSeries(n) {
if (!n.children) return;
n.children.forEach(listSeries);
n.series=d3.merge(n.children.map(function(c){return c.series}));
}
listSeries(root);
//compute offsets for each series in each node, and add them as a list to the corresponding series
//in a first time, this is not centered
function listOffsets(n) {
var offset=0;
n.series.forEach(function(s){
s.pWithOffset.push( {node:n, offset:offset+s.w/2})
offset+=s.w;
})
n.totalOffset=offset;
if (n.children)
n.children.forEach(listOffsets);
}
listOffsets(root);
然后在绘图部分:
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return (d.node.time-Math.sin(d.node.direction)*(d.offset-d.node.totalOffset/2)); })
.y(function(d) { return (d.node.value+Math.cos(d.node.direction)*(d.offset-d.node.totalOffset/2)); })
;
LineGroup.selectAll(".line")
.data(series)
.enter().append("path")
.attr("class", "line")
.attr("d", function(d){ return line(d.pWithOffset); })
.attr("stroke", function(d){ return d.c; })
.attr("stroke-width", function(d){ return d.w; })
.attr("fill", "none");