Javascript 如何在D3.js中创建蝴蝶结方法/图表?
我目前正在从事一个项目,在这个项目中,我需要根据来自应用程序的数据创建蝴蝶结图 从一些研究来看,最适合实现这一目标的图书馆是 我已经研究了这些例子: 可折叠树: 层次结构图: 下面是我想尝试和复制的一个基本蝴蝶结图示例: 正如您在图中所看到的,我需要多个顶级项目和/或一棵双树,它可以独立地打开每一侧/每棵树,数据从顶级项目的左到右(红色侧)和从右到左(蓝色侧)流动 使用D3.js可以实现吗 关于d3.js的教程只包括标准图表,如条形图和我发现只有一个顶级项目的在线树示例Javascript 如何在D3.js中创建蝴蝶结方法/图表?,javascript,d3.js,Javascript,D3.js,我目前正在从事一个项目,在这个项目中,我需要根据来自应用程序的数据创建蝴蝶结图 从一些研究来看,最适合实现这一目标的图书馆是 我已经研究了这些例子: 可折叠树: 层次结构图: 下面是我想尝试和复制的一个基本蝴蝶结图示例: 正如您在图中所看到的,我需要多个顶级项目和/或一棵双树,它可以独立地打开每一侧/每棵树,数据从顶级项目的左到右(红色侧)和从右到左(蓝色侧)流动 使用D3.js可以实现吗 关于d3.js的教程只包括标准图表,如条形图和我发现只有一个顶级项目的在线树示例 如果您能提供任何正确方
如果您能提供任何正确方向的帮助、建议或指点,我们将不胜感激。有一些有用的资料需要考虑:
s中画两棵树,并将其中一棵移到“上方”Array.from
从d3.tree
方法获取节点列表,而无需遍历层次结构- 你需要两棵树——一棵从根部向左向右,另一棵从根部向右向左
- 该方法有效地计算了节点定位的右侧
s和x
s(除了“水平”渲染,在每个Mike Bostock块的代码中翻转使用y
和x
)。我们希望了解节点之间的相对位置,但同时在右侧树(中心位于y
)和左侧树(中心位于g
)上进行平移g
- 例外情况是根节点,例如,如果“左”与“右”上有更多节点,则根节点的位置将略有不同。必须为两棵树选择一个根节点
- 可以重新计算坐标,以便:
- 在右侧树中,应添加
坐标(现在的意思是y
)的x
,以将其移动到width/2
的垂直中心,然后减半以将“分支”长度保持在g
宽度范围内
- 在左侧树中,应将
坐标(现在的意思是y
)减半(与右侧树中“分支长度”的处理相同)并取反,以将节点位置翻转到根节点的左侧(您选择的位置如左侧树的根位置)x
- 在右侧树中,应添加
//有用的链接
// https://bl.ocks.org/mbostock/3184089
// https://bl.ocks.org/d3noob/72f43406bbe9e104e957f44713b8413c
变量treeDataL={
“名称”:“根”,
“儿童”:[
{
“名称”:“L_A_1”,
“儿童”:[
{“name”:“L_B_1”},
{“名称”:“L_B_2”}
]
},
{
“名称”:“L_A_2”,
“儿童”:[
{“名称”:“L_B_3”},
{“名称”:“L_B_4”}
]
}
]
}
变量treeDataR={
“名称”:“根”,
“儿童”:[
{
“名称”:“R_A_1”,
“儿童”:[
{“name”:“R_B_1”},
{“name”:“R_B_2”},
{“name”:“R_B_3”}
]
},
{
“名称”:“R_A_2”,
“儿童”:[
{“name”:“R_B_3”},
{“name”:“R_B_4”},
{“name”:“R_B_5”},
{“name”:“R_B_6”}
]
}
]
}
//设置图表的尺寸和边距
var margin={顶部:50,右侧:50,底部:50,左侧:50},
宽度=400-margin.left-margin.right,
高度=400-margin.top-margin.bottom;
//声明树布局并指定大小
var tree=d3.tree()
.尺寸([宽度、高度]);
//使用d3层次结构创建2x树
//这是计算坐标的地方
var nodesL=树(d3.层次结构(treeDataL));
var nodesR=树(d3.层次结构(treeDataR));
//获取节点数组-需要v6
nodesLArray=Array.from(nodesL);
nodesrray=Array.from(nodesR);
//将nodesR root切换到nodesL
//这里的选择是将LH树的根坐标分配给RH
nodesLRoot=nodesLArray.find(n=>n.data.name==“根”);
nodesRRoot=nodesRArray.find(n=>n.data.name==“根”);
nodesroot.x=nodesLRoot.x;
nodesroot.y=nodesLRoot.y;
//这有点像“重要的一点”
//记住对于水平布局,翻转x和y。。。
//LH:将节点中的所有y减半并取反。L添加宽度/2
nodesLArray.forEach(n=>n.y=((n.y*0.5)*-1)+宽度/2);
//右侧:将所有y节点减半并添加宽度/2
forEach(n=>n.y=(n.y*0.5)+宽度/2);
//现在更接近链接3中的教程
//追加svg
var svg=d3.选择(“主体”)
.append(“svg”)
.attr(“宽度”,宽度+边距。左侧+边距。右侧)
.attr(“高度”,高度+边距。顶部+边距。底部);
//将g与边距对齐
var g=svg.append(“g”)
.attr(“转换”、“平移”(+margin.left+)、“+margin.top+”);
//渲染两棵树
[nodesL,nodesR].forEach(函数(节点,i){
//添加节点之间的链接
//需要根据索引选择链接,以防止渲染错误
var link=g.selectAll(`links${i}`)
.data(节点.子体().slice(1))
.输入()
.append(“路径”)
.attr(“class”,link links${i}`)//注意两个类
.attr(“d”,函数(d){
//x和y在此处翻转以实现水平放置
返回`M${d.y}、${d.x}C${d.y}、${(d.x+d.parent.x)/2}${d.parent.y}、${(d.x+d.parent.x)/2}${d.parent.y}、${d.parent.x}`
});
//将每个节点添加为一个组
//需要根据索引选择节点,以防止渲染错误
var node=g.selectAll(`.nodes${i}`)
.data(节点.子体())
.输入()
.append(“