Javascript 如何在D3力模拟中实现圆盘形状?

Javascript 如何在D3力模拟中实现圆盘形状?,javascript,d3.js,data-visualization,visualization,force-layout,Javascript,D3.js,Data Visualization,Visualization,Force Layout,我正试图重现Nadieh Bremer和Shirly Wu创作的令人敬畏的“点流”可视化效果 我特别感兴趣的是“气泡”的圆形形状和流体动力学,比如圆点到达气泡处的压缩(黑色箭头) 我的目标是通过.fx和.fy(黑点)创建(三)个固定节点,并将所有其他节点链接到相应的固定节点。当我降低力使动画运行稍微慢一点时,结果看起来非常混乱,气泡甚至没有围绕其中心节点形成 const simulation = d3.forceSimulation(nodes) .force("collide",

我正试图重现Nadieh Bremer和Shirly Wu创作的令人敬畏的“点流”可视化效果

我特别感兴趣的是“气泡”的圆形形状和流体动力学,比如圆点到达气泡处的压缩(黑色箭头)

我的目标是通过
.fx
.fy
(黑点)创建(三)个固定节点,并将所有其他节点链接到相应的固定节点。当我降低力使动画运行稍微慢一点时,结果看起来非常混乱,气泡甚至没有围绕其中心节点形成

  const simulation = d3.forceSimulation(nodes)
    .force("collide", d3.forceCollide((n, i) => i < 3 ? 0 : 7))
    .force("links", d3.forceLink(links).strength(.06))
const simulation=d3.forceSimulation(节点)
.力(“碰撞”,d3.力碰撞((n,i)=>i<3?0:7))
.力(“链环”,d3.力链环(链环).强度(.06))
有没有关于武力设置的想法可以产生更美观的效果

我确实理解,我必须随着时间的推移对组分配进行动画处理,以获得“涓涓流”效果(否则所有的点都会蜂拥到它们的目的地),但我想从模拟的一个良好的稳定状态开始

编辑

我确实检查了源代码,它只是重放预先录制的模拟数据,我想是出于性能原因

是我在D3可视化中的偶像,她绝对是明星!(OP之后的更正:看来这个datavis是由…创建的,无论如何,这并没有改变我对Bremer的看法)

第一次试图找出网页上发生的事情是看一下,不幸的是,这是一项艰巨的工作。因此,剩下的选择是试图重现这一点

这里的挑战不是创建一个循环模式,这很容易:您只需要组合
forceX
forceY
forceCollide

const svg=d3.选择(“svg”)
常量数据=d3.range(500.map)(()=>({}));
常数模拟=d3。力模拟(数据)
.力(“x”,d3.力x(200))
.力(“y”,d3.力(120))
.力(“碰撞”,d3.力碰撞(4))
.停止();
对于(设i=300;i--;)模拟。勾选();
const circles=svg.selectAll(空)
.数据(数据)
.输入()
.附加(“圆圈”)
.attr(“r”,2)
.style(“填充”、“番茄”)
.attr(“cx”,d=>d.x)
.attr(“cy”,d=>d.y)

在杰拉尔多的起点上建造

我认为避免过度熵的关键点之一是指定速度衰减-这将有助于避免超出所需位置。速度太慢,流停止时密度不会增加,速度太快,节点要么太混乱,要么超出其目的地,在太远和太短之间振荡

多体力在这里很有用-它可以保持节点间距(而不是碰撞力),节点之间的排斥力通过每个簇的定位力来抵消。下面我使用了两个中心点和一个节点属性来确定使用哪一个。这些力必须相当弱——强大的力很容易导致过度修正

我没有使用计时器,而是使用simulation.find()功能从一个集群中选择一个节点,并切换吸引它的中心。1000次滴答声后,以下模拟将停止:

var canvas=d3.选择(“canvas”);
var width=+canvas.attr(“宽度”);
var height=+canvas.attr(“height”);
var context=canvas.node().getContext('2d');
//关键变量:
var节点=[];
变量强度=-0.25;//默认排斥
var中心强度=0.01;//两个集群的定心力功率
var velocityDecay=0.15;//速度衰减:值越高,超调越小
var outerRadius=250;//此半径内的新节点
var innerRadius=100;//新节点在此半径之外,初始节点在此半径之内。
var startCenter=[250250];//新节点/初始节点中心点
var endCenter=[710250];//目的地中心
var n=200;//初始节点数
var周期=1000;//停止前的滴答数。
//创建一个随机节点:
var random=函数(){
var angle=Math.random()*Math.PI*2;
var distance=Math.random()*(outerRadius-innerRadius)+innerRadius;
var x=数学cos(角度)*距离+起始中心[0];
变量y=数学sin(角度)*距离+起始中心[1];
返回{
x:x,
y:y,
力量:力量,,
错误:错误
}
}
//初始节点:
对于(变量i=0;i循环)此.stop();
nodes.push(random());//创建一个节点
this.nodes(nodes);//更新节点。
var migrating=this.find((Math.random()-0.5)*50+startCenter[0],(Math.random()-0.5)*50+startCenter[1],10);
如果(迁移)migrating.migrated=true;
clearRect(0,0,宽度,高度);
nodes.forEach(函数(d){
context.beginPath();
context.fillStyle=d.d?“钢蓝”:“橙色”;
弧(d.x,d.y,3,0,数学PI*2);
context.fill();
})
}

在其他答案的帮助下,我继续进行实验,我想总结一下我的发现:

圆盘形状

forceManyBody
似乎比
forceCollide
更稳定。使用它而不扭曲光盘形状的关键是
.distance max
。缺点是你的可视化不再是“无标度”的,它必须是b