首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有特定目标目标的D3js兵力仿真

具有特定目标目标的D3js兵力仿真
EN

Stack Overflow用户
提问于 2019-05-29 18:37:13
回答 1查看 407关注 0票数 5

我正在尝试渲染一个d3js部队模拟,但我想确保我的节点不会传递错误信息。

下面的代码用于显示节点,但由于力布局的动态性质,它偶尔会将一些节点从其适当的x坐标位置推开。

代码语言:javascript
复制
 inOrder(){
  this.simulation
    .force("x", d3.forceX(d => this.xScale(d.value)))
    .force("y",  d3.forceY(this.height / 2))
    .alpha(1).restart();
},

这是一个惊人的例子:数字应该从左到右依次排列。

我尝试使用节点上的fx属性锁定位置:

代码语言:javascript
复制
inOrder(){
  this.releases.forEach(x => {
    x.fx = this.xScale(x.value)
  })

  this.simulation
    .force("x", d3.forceX(d => this.xScale(d.value)))
    .force("y",  d3.forceY(this.height / 2))
    .alpha(1).restart();
},

这样做的目的是保持x位置,但是当调用inOrder方法时,节点立即跳到最后的x位置。这破坏了力模拟的流体和动态性质。

有没有办法让这两个世界都发挥最大的作用?也许通过使用.on("end", () => {}).on("tick", () => {})?事件处理程序?

迈克·博斯托克(https://stackoverflow.com/users/365814/mbostock)和单卡特创作了一些作品,作为我在这里所要做的事情的灵感来源:

单击“更改”和“部门汇总”选项卡https://archive.nytimes.com/www.nytimes.com/interactive/2012/02/13/us/politics/2013-budget-proposal-graphic.html?hp

单击“整个图片与按行业选项卡查看”之间的https://archive.nytimes.com/www.nytimes.com/interactive/2013/05/25/sunday-review/corporate-taxes.html

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-05-29 19:51:22

我在这里可能遗漏了一些东西,但是对x定位力(和y)的强度进行修补可以帮助确保您的订单正确完成。forceX或forceY的默认强度为0.1,强度实现如下:

值0.1表示每个应用程序节点应该将其当前x位置的十分之一移动到目标x位置。较高的值更快地将节点移动到目标位置,通常以牺牲其他力量或约束为代价。不建议在0,1范围外设置值。(文档)

因此,我们可以增加forceX强度,并且为了使x轴上的节点更自由地移动,我们可以减少forceY --允许节点更容易地跳跃--降低碰撞强度也会有帮助。

我不给下面的圆圈贴上标签(相反,它们是顺序阴影的),但我确实运行了一次检查,看看它们是否整齐(在模拟结束时,日志用于控制台),下面的代码片段只修改x和y力(而不是碰撞力):

代码语言:javascript
复制
var height = 300;
var width = 500;

var data = d3.range(30).map(function(d,i) {
  return { size: Math.random()+1, index: i}
});

    
var svg = d3.select("body")
  .append("svg")
  .attr("width",width)
  .attr("height",height);
  
var x = d3.scaleLinear()
  .domain([1,30])
  .range([50,width-50]);
  
var color = d3.scaleLinear()
  .domain([0,29])
  .range(["#ccc","#000"])

var simulation = d3.forceSimulation()
    .force("x", d3.forceX(d => x(d.index)).strength(0.20))
    .force("y",  d3.forceY(height / 2).strength(0.05))
    .force("collide", d3.forceCollide().radius(d=> d.size*10))
    .alpha(1).restart();
    
var circles = svg.selectAll(null)
  .data(data)
  .enter()
  .append("circle")
  .attr("r", function(d) { return d.size * 10; })
  .attr("fill", function(d,i) { return color(i); })
    
simulation.nodes(data)
  .on("tick",tick)
  .on("end",verify);
  

function tick() {
  circles
  .attr("cx", function(d) { return d.x; })
  .attr("cy", function(d) { return d.y; })
}

function verify() {
  var n = 0;
  for(var i = 0; i < data.length - 1; i++) {
     if(data[i].x > data[i+1].x) n++;
  }
  console.log(n + " out of place");
}
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

这个片段将30个圆圈放置在500x300区域中,没有太多的问题:我已经测试了几次,其中0不合适。在这里放置100个圆圈会引起问题:在这样狭小的区域内,圆圈将无法改变位置:可能需要进一步修改兵力,但更大的地块可能会优先考虑(而不是小片段视图)。

另一种选择是在整个模拟过程中修改力:先以强x力和低碰撞力开始,然后慢慢拨起碰撞,以使随后的碰撞最小化。下面是修改示例函数中的作用力的一个例子--这个例子是为了链接长度,而不是放在x上--但是适配应该不会太难。

另一种可能性是保持α高,直到所有的圆都在x轴上被正确的排列,然后开始冷却,这将再次发生在滴答函数中。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56366666

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档