D3 V4:力布局节点内的节点

时间:2019-03-22 16:22:50

标签: javascript d3.js force-layout

我已经创建了一个连接的节点强制布局图,但是想更进一步,并在每个节点(团队)中插入节点(玩家)(类似于背包布局)

虽然在模拟开始后我已经成功地提取了每个节点(团队)的位置并将节点(玩家)置于各自团队的中心,但是我无法创建具有碰撞/抖动的间隔开的节点(玩家)在每个节点(团队)中。

我尝试再次运行新的模拟以获得碰撞效果,但是它不起作用。

到目前为止已完成的工作:https://bl.ocks.org/dianaow/722db505e9971b50b575ef0051ea0295

相关代码:

  var team_stats1 = d3.nest()
    .key(function(d) { return d.club })
    .entries(data)

  enter()

  // Initialize force simulation
  var simulation = d3.forceSimulation()
    .force("link", d3.forceLink()
      .id(function(d) { return d.id; })
      .strength(function(d) {return d.strength})
    )
    .force("collide", d3.forceCollide().radius(function(d) { return d.size }))

  simulation
      .nodes(nodes)
      .on("tick", update)

  simulation.force("link")
      .links(links)

  // Initialize second force simulation just to get collision between nodes(players) within each node(team)
  var simulation1 = d3.forceSimulation()
    .force("charge", d3.forceManyBody().strength(-300))
    .force("collide", d3.forceCollide().radius(function(d) { return d.size }))

  function enter() {

    path = svg.selectAll('line')
      .data(links).enter().append('line')
      .attr('stroke-linecap', 'round')

    circle = svg.selectAll('circle')
      .data(nodes)
      .enter().append('circle')
      .attr('stroke-width', 2)

    circle.each(function (nodeElement) {
      if(countries.indexOf(nodeElement.id) < 0){
        var idx = nodeElement.id.replace(/[^A-Z0-9]+/ig, "_")
        var data_filtered = team_stats1.filter(d=>d.key==nodeElement.id)[0].values
        svg.selectAll('#' + idx + '.team_players')
          .data(data_filtered)
          .enter().append('circle')
            .attr("class", "team_players")
            .attr('id', idx)
            .attr("r", 3)
            .attr("fill", 'grey')
            .attr("stroke", 'none')
            .attr("stroke-width", 0)  
      }
    })
  }

  function update() {

    path.attr('stroke-width', function(d) {return d.size})
      .attr('stroke', function(d) {return d.stroke})
      .attr('fill', function(d) {return d.stroke})
      .attr('x1', function(d) {return d.source.x})
      .attr('y1', function(d) {return d.source.y})
      .attr('x2', function(d) {return d.target.x})
      .attr('y2', function(d) {return d.target.y})

    circle.attr('r', function(d) {return d.size})
      .attr('fill', function(d) {return d.fill || '#fff'})
      .attr('cx', function(d) {return d.x})
      .attr('cy', function(d) {return d.y})
      .attr('id', function(d) {return d.id.replace(/[^A-Z0-9]+/ig, "_")}) // remove spaces because they cannot be contained in class names

    circle.each(function (nodeElement) {
      if(countries.indexOf(nodeElement.id) < 0){ // filter out the country nodes around team nodes
        var idx = nodeElement.id.replace(/[^A-Z0-9]+/ig, "_")
        var data_filtered = team_stats1.filter(d=>d.key==nodeElement.id)[0].values
        data_filtered.forEach((d,i) => {
          d.x = nodeElement.x
          d.y = nodeElement.y
        })

        var player = svg.selectAll('#' + idx + '.team_players')
          .data(data_filtered)
          .attr('cx', function(d) {return d.x})
          .attr('cy', function(d) {return d.y}) 

        simulation1
          .nodes(data_filtered)
          .on("tick", updatePlayers)

        function updatePlayers() {
          player.attr('cx', function(d) {return d.x})
            .attr('cy', function(d) {return d.y}) 
        }
      }
    })

  }

0 个答案:

没有答案