Javascript d3力有向图向下力模拟
也许这不是最好的方法,但现在我已经进入了兔子洞,我想知道它是如何工作的。我试着用d3创建一棵树,在那里节点会向下沉降,就像重力一样。我希望这个,再加上每个节点的电荷和绳子的张力,能让它看起来像我想象的那样,平衡自己。我试图在d3中模拟这种恒定的向下加速度,但我是d3的初学者,不知道确切的方法。我还遇到了一个问题,模拟停止运行,d3.timer(force.resume)没有帮助Javascript d3力有向图向下力模拟,javascript,svg,d3.js,tree,force-layout,Javascript,Svg,D3.js,Tree,Force Layout,也许这不是最好的方法,但现在我已经进入了兔子洞,我想知道它是如何工作的。我试着用d3创建一棵树,在那里节点会向下沉降,就像重力一样。我希望这个,再加上每个节点的电荷和绳子的张力,能让它看起来像我想象的那样,平衡自己。我试图在d3中模拟这种恒定的向下加速度,但我是d3的初学者,不知道确切的方法。我还遇到了一个问题,模拟停止运行,d3.timer(force.resume)没有帮助 因此,本质上,我希望将根节点固定在某个特定位置,如枢轴,子节点脱离它,重力、电荷和张力都存在,这样子节点就可以自动稳定
因此,本质上,我希望将根节点固定在某个特定位置,如枢轴,子节点脱离它,重力、电荷和张力都存在,这样子节点就可以自动稳定下来,并将自己平衡到树结构中。力导向模拟是布置树、图表或图形的好方法。许多开源和商业图书馆和应用程序都使用这种方法,因此D3只是其中之一。而且,这个话题一直吸引着应用数学家的注意 我只想告诉你这是一个巨大的话题。如果你把自己局限于D3,那么还有很多方法可以实现你在问题中所描述的。由于这个答案必须有一个合理的长度,我将通过3个D3示例向您展示一些亮点。我将从一个简单的强制导向树布局示例开始(这并不是您真正想要的,但很简单),每个示例都将建立在前面的基础上,并且更接近您想要实现的目标 例1 这是通过D3力布局以径向方式布置的树的基本示例。您确实需要理解所有使用的代码。我只想在这里提到一些亮点:
- 函数getData()返回一个测试树(这是一个方便的子集 所谓的“flare”测试树)李>
- 函数
将树对象转换为数组,这是初始化D3 force布局所需的格式李>flant()
- 初始化所有节点的位置(否则D3 force布局会表现得有点奇怪和不可预测)李>
- 根节点位置初始化为图的中心,根节点声明为固定李>
- 提供了“ontick”功能,它只是按照模拟过程中的行为绘制链接和节点李>
- D3力布局算法初始化为D3重力0.2和D3电荷-200李>
- D3 force布局算法通过调用其方法start()启动
- 根节点位置初始化为(宽度/2100)而不是(宽度/2,高度/2)-这是“悬挂”布局根的自然位置
- 自定义力在“ontick”函数中定义为以下几行:
var ky=e.alpha;
links.forEach(函数(d,i){
d.target.y+=(d.target.depth*100-d.target.y)*5*ky;
});
这个自定义力将把相同深度的节点吸引到同一条水平线上。这足以在图片中生成图表
但是,您可以注意到图中某些节点的非自然排列-通常,它们看起来并不完全像是从父节点“挂起”的。下一个示例将尝试修复该问题
例3
这看起来比前面的示例更自然
本例中的新功能只是另一个自定义力:将所有父对象“居中”到其子对象水平位置的中间。您可以在“ontick()”函数中轻松找到负责此操作的代码
这看起来更接近您想要的。我并不是说这是一个满足您需求的理想布局。但是,它可以作为一个很好的起点。一旦您了解了所有这些示例,您将能够修改它们,如果您愿意,还可以根据不同的自定义力创建不同的模拟
所以,最后一个例子不是基于物理重力的模拟,但它的效果类似于物理重力。如果你想模拟物理重力,这将需要更多的代码-但如果效果几乎相同,你真的需要它吗
希望这能有所帮助。如果您有问题,需要澄清等,请告诉我。最简单的方法是调整布局中的“大小”,以便现有“重心”的中心“力位于显示屏底部,而根节点固定在显示屏顶部。但是,您可能需要对参数进行大量调整,才能使事情看起来很好 示例如下: 另一种选择是添加“自定义力”,类似于在中使用的力。该演示中使用的计算细节并不相关,但其思想很简单,在每个
tick()
函数的开头,每个数据点都会在某个方向上稍微调整。如果该方向摆脱了任何其他约束,它将在下一次勾选中被布局的内部计算反作用
示例如下:
var g=0.0005;
函数重力函数(d,i){
如果(d.固定)返回;
//用于修改每个数据对象的位置
//在
var force = d3.layout.force()
.on("tick", tick)
.charge(-30)
.linkDistance(10)
.gravity(0.005)
.size([w, 2*h]);
var g = 0.0005;
function gravityFunction(d,i) {
if (d.fixed) return;
//used to modify each data object's position
//at the start of every tick
var distToGround = h-d.y;
if (distToGround <= 0) d.y = h; //make "ground" solid
else d.y += g * (Math.min(distToGround, h/4) );
}
function tick() {
nodeCircles.each(gravityFunction)
//adjust each node according to the custom force
.attr("cx", function (d) {
return d.x;
})
/* etc. */