Øys*_*sen 47 d3.js force-layout
我刚开始涉足d3,发现学习曲线相当陡峭.这个过程与我习惯的过程完全不同,数学大多数都超出了我的想象.
无论如何,我的项目包含一个力布局,代表系统之间的集成地图.这部分工作得非常好,但是我确实有一个主要的问题,它也出现在Michael Bostocks网站上的强制定向布局演示中:当节点启动时,它们似乎被渲染出画布.在此之后,一些严肃的物理数学正在接管,模拟一个引力,它在一个相当混乱的路径上来回发送节点,直到它们冷静下来并在一些随机坐标上稳定下来.虽然这些动作在第一次运行演示时会逐渐消失,但是当您尝试查看公司网络接口的状态时,它管理的观点和服务器不会保持静止,一段时间后会变得很烦人.
我确信我有这个项目的正确布局设置,因为我确实希望服务器自动布局,我确实希望可视化它们之间的链接.然而,我对万有引力效应感到矛盾.
我想知道; 是否可以手动设置每个节点的初始位置,以便我可以将它们放在更接近重力中心并稍微缩短"反弹时间"?
小智 36
以上所有答案都误解了ØysteinAmundsen的问题.
在它开始时稳定力的唯一方法是设置node.x和node.ya适当的值.请注意,节点是d3.js的数据,而不是表示的DOM类型.
例如,如果您加载
nodes = [{"id": a}, {"id": b}, {"id": c}]
Run Code Online (Sandbox Code Playgroud)
成
d3.layout.force().nodes(nodes)
Run Code Online (Sandbox Code Playgroud)
你必须设置节点数组中所有元素的所有.x和.y就像这样(在coffeescript中)
nodes = [{"id": a}, {"id": b}, {"id": c}]
for i in [0..2]
nodes[i].x = 500 #the initial x position of node
nodes[i].y = 300 #the initial y position of node
d3.layout.force().nodes(nodes).links(links)
Run Code Online (Sandbox Code Playgroud)
那么节点将从force.start()开始.这样可以避免混乱.
mee*_*mit 30
在内部,在"正常"使用下,强制布局反复调用自己的tick()方法(通过a setInterval或requestAnimationFrame),直到布局解决方案为止.此时,其alpha()值等于或接近0.
因此,如果您希望通过此解决方案流程"快进",则可以tick()反复调用该方法,直到布局的alpha达到一个值,根据您的特定要求,该值构成"足够接近"的解决方案.像这样:
var force = d3.layout.force(),
safety = 0;
while(force.alpha() > 0.05) { // You'll want to try out different, "small" values for this
force.tick();
if(safety++ > 500) {
break;// Avoids infinite looping in case this solution was a bad idea
}
}
if(safety < 500) {
console.log('success??');
}
Run Code Online (Sandbox Code Playgroud)
运行此代码后,您可以根据节点的状态绘制布局.或者,如果您通过绑定到tick事件(即force.on('tick', drawMyLayout))来绘制布局,那么您将需要在此代码运行后进行绑定,否则您将在while循环期间不必要地同步渲染布局数百次.
JohnS已经将这种方法归结为一个简洁的功能.在本页的某处查看他的回答.
Sup*_*gly 11
我刚才处理过类似的事情.有几点需要考虑.
1)迭代刻度模拟一个达到平衡的系统.因此,在系统稳定并且您进行自动布局之前,无法避免在需要时多次调用tick.也就是说,您无需为每个刻度更新可视化模拟工作!事实上,如果你不这样做,迭代会更快.我的代码的相关部分是:
var iters = 600; // You can get decent results from 300 if you are pressed for time
var thresh = 0.001;
if(!hasCachedLayout || optionsChanged || minorOptionsChanged) {
force.start(); // Defaults to alpha = 0.1
if(hasCachedLayout) {
force.alpha(optionsChanged ? 0.1 : 0.01);
}
for (var i = iters; i > 0; --i) {
force.tick();
if(force.alpha() < thresh) {
//console.log("Reached " + force.alpha() + " for " + data.nodes.length + " node chart after " + (iters - i) + " ticks.");
break;
}
}
force.stop();
}
Run Code Online (Sandbox Code Playgroud)
它同步运行,运行后我为所有节点和链接创建dom元素.对于小图表,这种运行速度非常快,但您会发现较大的图形(100多个节点)存在延迟 - 它们的计算成本更高.
2)您可以缓存/种子布局.如果没有设置位置,则力布局将在初始化时均匀分布节点!因此,如果您确保您的节点已设置x和y属性,则将使用这些属性.特别是当我更新现有图形时,我将重新使用先前布局中的x和y位置.
您将具有良好的初始布局找到你将需要大量的迭代次数更少,以达到稳定的配置.(这是上面代码中hasCachedLayout跟踪的内容).注意:如果您重新使用相同布局的相同节点,那么您还必须确保将px和py设置为NaN,否则您将得到奇怪的结果.
基于其他答案我已经做了这个方法:
function forwardAlpha(layout, alpha, max) {
alpha = alpha || 0;
max = max || 1000;
var i = 0;
while(layout.alpha() > alpha && i++ < max) layout.tick();
}
Run Code Online (Sandbox Code Playgroud)