[英]Side-by-side paths in d3
I'm trying out a way to get paths to display next to each other, such that they'll push each other around (factoring in widths and neighbouring points) and not overlap. 我正在尝试一种方法来获得彼此相邻的路径,这样它们就会相互推动(分解宽度和相邻点)并且不会重叠。
This is my fiddle, mostly pieced together from examples https://jsfiddle.net/crimsonbinome22/k2xqn24x/ 这是我的小提琴,大多是从例子中拼凑而成的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");
And this is what I'm hoping to achieve in this image here , basically: 这就是我希望在这张图片中实现的目的,基本上:
Some issues I'm having: 我遇到的一些问题:
I've had a search around but can't find any examples of how to do this. 我有一个搜索,但找不到任何如何做到这一点的例子。 In a way it's almost like a chord diagram but a little different, and I can't find much relevant code to reuse.
在某种程度上,它几乎像一个和弦图,但有点不同,我找不到很多相关的代码可以重用。 Any help on how to achieve this (either with the approach I've started, or something totally different if I've missed it) would be appreciated.
如何实现这一点的任何帮助(无论是我已经开始的方法,还是我错过了它的完全不同的东西)将不胜感激。
I would go with the following steps: 我会采取以下步骤:
Edit: running example https://jsfiddle.net/toh7d9tq/1/ 编辑:运行示例 https://jsfiddle.net/toh7d9tq/1/
I have used a slightly different approach for the last two steps (computing the offset): I actually create a new p
array for each series with a list of pairs {node, offset}
. 我在最后两个步骤中使用了稍微不同的方法(计算偏移量):我实际上为每个系列创建一个新的
p
数组,其中包含一对{node, offset}
的列表。 This way it is much easier to access all relevant data in the drawing function. 这样,在绘图功能中访问所有相关数据就容易得多。
I needed to add an artificial root to have a nice starting line (and to make it easier for recursion and angles and everything), you can skip it in the drawing phase if you want. 我需要添加一个人工根来获得一个很好的起始线(并使其更容易递归和角度以及所有内容),如果需要,可以在绘图阶段跳过它。
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);
And then in the drawing section: 然后在绘图部分:
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");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.