带有排斥圈子的圈子图

时间:2019-03-13 07:16:11

标签: javascript angular d3.js

我尝试了一个简单的气泡图,该气泡图具有排斥功能,但整个力模拟功能不起作用,我是D3的新手,请帮忙

圈子仍然重叠,请提供帮助。

export class AppComponent {

  title = 'd3Project';

  dataset = [

    [34, 78, 14],
    [109, 280, 20],
    [310, 120, 22],
    [79, 411, 32],
    [420, 220, 23],
    [233, 145, 26],
    [333, 96, 27],
    [222, 333, 24],
    [78, 320, 35],
    [21, 123, 12],
    [22, 126, 40]
  ];

  dataSet: any = [

    [14, 78],
    [20, 280],
    [22, 120],
    [32, 411],
    [23, 220],
    [26, 145],
    [27, 96],
    [24, 333],
    [35, 320],
    [12, 123],
    [40, 126]
  ];

  w = 1000;
  h = 500;
  padding = 30;

  xScale = d3.scaleLinear()
    .domain([0, d3.max(this.dataset, (d) => d[0])])
    .range([this.padding, this.w - this.padding]);

  yScale = d3.scaleLinear()
    .domain([0, d3.max(this.dataset, (d) => d[1])])
    .range([this.h - this.padding, this.padding]);

  data = [14, 20, 22, 32, 23, 26, 27, 24, 35, 43, 40];

  ngOnInit() {

    const svg = d3.select("body")
      .append("svg")
      .attr("width", this.w)
      .attr("height", this.h)
      // .attr('x',this.w) 
      // .attr('y',this.h)
      .attr('viewBox', '-700 -300 ' + (this.w + 700) + ' ' + (this.h + 200))
    // viewBox="0 0 100 100"

    var simulation = d3.forceSimulation().nodes(this.dataset)

    //add forces
    //we're going to add a charge to each node 
    //also going to add a centering force

    simulation
      .force("charge_force", d3.forceManyBody().strength(-50))
      .force("center_force", d3.forceCenter(this.w / 2, this.h / 2))
      .on('tick', ticked);

    function ticked() {
      node.attr("cx", function(d) {
          return d[0];
        })
        .attr("cy", function(d) {
          return d[1];
        });
    }

    let node = svg.selectAll("circle")
      .data(this.dataset)
      .enter()
      .append("circle")
      //  .attr('cx',(d) =>  Math.round( this.xScale(d[0]) ) )
      //  .attr('cy',(d) =>  Math.round( this.yScale(d[1]) ) )
      .attr('r', (d) => d[2])
      .attr('position', 'relative')
      .attr('transform', 'translate(' + [this.w / 2, this.h / 2] + ')')
      .style('fill', (d) => {
        if (d[2] % 2) return 'purple';
        else if (d[2] < 200) return 'red';
        else
          return 'orange';
      })
      .append('title')
      .text((d) => 'radius: ' + d[2]);
  }

1 个答案:

答案 0 :(得分:1)

您的数据结构(数组数组)是错误的。 API清楚要传递给模拟的数据结构:

  

每个节点必须是一个对象。 (强调我的)

例如,我们可以将您的数据转换为对象数组:

dataset = dataset.map(function(d) {
  return {
    data: d
  }
});

在这里,我将内部数组作为值放在data属性中。然后,模拟将填充所有其他属性(xyindexvxvy)。

此外,您还有一个更微妙的错误:您选择的node<title>元素的选择,而不是<circle>元素。因此,ticked函数将不起作用。因此,请中断node选择,如下所示:

let node = svg.selectAll("circle")
  .data(dataset)
  .enter()
  .append("circle")
  //etc...

node.append('title')
  //etc...

这是您所做的更改的代码:

dataset = [

  [34, 78, 14],
  [109, 280, 20],
  [310, 120, 22],
  [79, 411, 32],
  [420, 220, 23],
  [233, 145, 26],
  [333, 96, 27],
  [222, 333, 24],
  [78, 320, 35],
  [21, 123, 12],
  [22, 126, 40]
];

dataset = dataset.map(function(d) {
  return {
    data: d
  }
});

w = 600;
h = 400;
padding = 30;

const svg = d3.select("body")
  .append("svg")
  .attr("width", w)
  .attr("height", h);

var simulation = d3.forceSimulation(dataset)
  .force("charge_force", d3.forceManyBody().strength(-50))
  .force("center_force", d3.forceCenter(w / 2, h / 2))
  .on('tick', ticked);

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

let node = svg.selectAll("circle")
  .data(dataset)
  .enter()
  .append("circle")
  //  .attr('cx',(d) =>  Math.round( this.xScale(d[0]) ) )
  //  .attr('cy',(d) =>  Math.round( this.yScale(d[1]) ) )
  .attr('r', (d) => d.data[2])
  .style('fill', (d) => {
    if (d.data[2] % 2) return 'purple';
    else if (d.data[2] < 200) return 'red';
    else
      return 'orange';
  });

node.append('title')
  .text((d) => 'radius: ' + d.data[2]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>