d3.js 存储从力模拟中随意附加的圆的像素坐标

d3.js store pixel coordinates of circles appended haphazardly from force simulation

我有一个简化的视觉效果,我试图从一堆小圆圈(右侧)到大圆圈(左侧)绘制贝塞尔线。正在进行的片段:

var margins = {top:100, bottom:300, left:100, right:100};

var height = 600;
var width = 900;

var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;

var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);

var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");

var data = d3.range(200).map(function(v) {return {name: v.toString()+'_movie', top:false, link:'2019'} });

data.forEach(function(d, i) {
  d.x = 900;
  //d.y = 100;
  d.y = 200
});

var simulation = d3.forceSimulation(data)
  .force("x", d3.forceX(function(d) {
return 900;
  }).strength(0.4))
  .force("y", d3.forceY(function(d) {
//return 100;
return 200;
  }).strength(0.1))
  .force("collide", d3.forceCollide(4))
  .stop();

simulation.tick(75);
console.log(data)
var circles = graphGroup.selectAll(null)
  .data(data)
  .enter()
  .append("circle")
  .attr("r", function(d) {
return 2;
  })
  .attr("cx", function(d) {
return d.x;
  })
  .attr("cy", function(d) {
return d.y;
  })
  .style('fill', "#003366")
  .on('click', function(d) {
return console.log(d3.select(this).datum());
  });

var topData = [
  {year:'2019', top:true}
];

graphGroup.selectAll(null)
.data(topData)
.enter()
.append('circle')
.attr('cx', 200)
.attr('cy', 200)
.attr('r', 20)
.style('fill', "#003366");


  var topCircles = d3.selectAll('circle').filter(function(d) {return d.top == true}).data();
  var bottomCircles = d3.selectAll('circle').filter(function(d) {return d.top == false}).data();
  console.log(topCircles)
  var topLinks = topCircles.map(function(d,i) {
return {source: [200, 200], link:d.year}
  });

  var bottomLinks = bottomCircles.map(function(d,i) {
return {target: [d3.select(this).datum().cx, d3.select(this).datum().cy], link:d.year}
  });

  var multiLinkData = topLinks.map(t1 => ({...t1, ...bottomLinks.find(t2 => t2.link === t1.link)}));

  console.log(multiLinkData)


  var link = d3.linkHorizontal();


  graphGroup.selectAll(null)
  .data(multiLinkData)
  .enter()
  .append('path')
  //.join("path")
  .attr("d", link)
  .attr("fill", "none")
  //.style('stroke', function(d) {return colorMap[d.applied]})
  .attr("stroke", "#d9d9d9");
<script src="https://d3js.org/d3.v5.min.js"></script>

因此 none 行已附加;错误读取无法读取此行未定义的 cx

  var bottomLinks = bottomCircles.map(function(d,i) {
    return {target: [d3.select(this).datum().cx, d3.select(this).datum().cy], series:d.name}
  });

但我记得,这是检索 svgs 像素坐标的唯一方法。由于它们是从群体模拟中附加的,因此无法预先计算每个圆圈的确切位置。因此,我认为在圆附加后放置我的 source/target 贝塞尔线逻辑是合适的,然后我可以在模拟吐出它的渲染后获取实际像素坐标。

问题

我的临时坐标生成可能存在什么缺陷,或者是否有更简单的方法来引用我的代码片段中的那些圆心点?

+1 以获得有趣的可视化效果!

您的想法是正确的,但实际上,您可以更轻松地检索这些值,因为您已经将 xy 设置为 forEach()你的代码的开头。所以没有必要爬行每件事并查找个人 cxs 和 cys。您所需要的只是将正确的值输入 multiLinkData:

var bottomLinks = bottomCircles.map(function(d,i) {
  return {target: [d.x, d.y], link:d.link}
});


  var multiLinkData = bottomLinks.map(t1 => ({...t1, ...topLinks.find(t2 => t2.link === t1.link)}));