代码之家  ›  专栏  ›  技术社区  ›  Navin Leon

D3力模拟-使节点更靠近同一角度的点

  •  2
  • Navin Leon  · 技术社区  · 7 年前

    Move d3 circles away from center circle - force layout 当节点N1的大小改变时,我在节点上运行模拟,N1周围的节点将以相同的角度移动,但我的问题是,当它的大小改变回原来的时候,使节点回到靠近N1的位置。我怎样才能做到这一点?

    我在下面使用过,但是节点是

    simulation.nodes(nodes);
    simulation.restart();
    for (var i = 0; i < 300; ++i) simulation.tick();
    

    http://recordit.co/797i1E8ocT

    d3.forceSimulation(nodes)
        .force('x', d3.forceX(plot.x))
        .force('y', d3.forceY(plot.y))
    

    提前谢谢。

    1 回复  |  直到 7 年前
        1
  •  3
  •   Ankor    7 年前

    节点不会靠近,因为您的模拟“速度”(称为 alpha

    simulation.restart();
    

    你不需要的

    simulation.alpha(1);
    

    节点将正常工作。

    要实现它,可以在模拟初始化及其首次运行后保存初始位置:

    for (let d of data.children) {
      d.initialX = d.x;
      d.initialY = d.y;
    }
    

    然后替换 x y 将每个节点吸引到其初始位置的力:

    simulation
      .force("x", d3.forceX(d => d.initialX).strength(0.2))
      .force("y", d3.forceY(d => d.initialY).strength(0.2));
    

    强度决定了碰撞力和钉扎之间的平衡。强度越大,节点就越会试图占据其初始位置。

    也可以使用点吸引而不是 是的 d3-force-attract 包裹。

    下面的代码片段演示了所描述的方法。

    var w = 650,
      h = 650;
    var svg = d3.select("body")
      .append("svg")
      .attr("width", w)
      .attr("height", h);
    
    var color = d3.scaleOrdinal(d3.schemeCategory10)
    
    var data = {
      name: "root",
      children: [{
        label: 'RED1',
        size: 20,
        color: 'red'
      }, {
        label: 'RAD2',
        size: 20,
        color: '#c99700'
      }, {
        label: 'BIL3',
        size: 20,
        color: 'blue'
      }, {
        label: 'EEN4',
        size: 10,
        color: '#007377'
      }, {
        label: 'INO5',
        size: 40,
        color: '#b4975a'
      }, {
        label: 'RAD6',
        size: 40,
        color: '#c99700'
      }, {
        label: 'BIL7',
        size: 30,
        color: '#008ce6'
      }, {
        label: 'INO8',
        size: 30,
        color: '#b4975a'
      }, {
        label: 'INO9',
        size: 40,
        color: '#b4975a'
      }, {
        label: 'RAD10',
        size: 40,
        color: '#c99700'
      }, {
        label: 'BIL11',
        size: 30,
        color: '#008ce6'
      }, {
        label: 'INO12',
        size: 30,
        color: '#b4975a'
      }]
    };
    
    var render = function() {
    
      var simulation = d3.forceSimulation(data.children)
        .force("x", d3.forceX(w / 2))
        .force("y", d3.forceY(h / 2))
        .force("collide", d3.forceCollide(function(d) {
          return d.size + 20
        }))
        .stop();
    
      for (var i = 0; i < 100; ++i) simulation.tick();
    
      for (let d of data.children) {
        d.initialX = d.x;
        d.initialY = d.y;
      }
    
      simulation
        .force("x", d3.forceX(d => d.initialX).strength(0.2))
        .force("y", d3.forceY(d => d.initialY).strength(0.2));
    
      let nodeLevel1 = svg.selectAll('circle')
        .data(data.children, (d) => {
          // Attaching key for uniqueness
          return d.label;
        });
    
      nodeLevel1.exit().remove();
      let nodeLevel1Enter = nodeLevel1
        .enter()
        .append("circle")
        .attr("cx", function(d) {
          return d.x
        })
        .attr("cy", function(d) {
          return d.y
        })
        .attr("r", function(d) {
          return d.size
        })
        .style("fill", function(d) {
          return d.color;
        })
    
      nodeLevel1Enter = nodeLevel1Enter
        .merge(nodeLevel1)
    
      nodeLevel1Enter
        .transition()
        .duration(1600)
        .attr("cx", function(d) {
          return d.x
        })
        .attr("cy", function(d) {
          return d.y
        })
        .attr("r", function(d) {
          return d.size
        })
        .style("fill", function(d) {
          return d.color;
        })
    
      d3.select('#updatesize').on('click', function() {
        add();
      })
      d3.select('#updatebluesize').on('click', function() {
        addblue();
      })
      d3.select('#resetsize').on('click', function() {
        reset();
      })
      d3.select('#resetall').on('click', function() {
        resetall();
      })
    
      var add = function() {
        data.children[0].size = 140;
        move();
      }
      var addblue = function() {
        data.children[2].size = 100;
        move();
      }
      var reset = function() {
        data.children[0].size = 20;
        move();
      }
      var resetall = function() {
        data.children[0].size = 20;
        data.children[2].size = 20;
        move();
      }
    
      function move() {
        simulation.nodes(data.children);
        simulation.alpha(1);
        for (var i = 0; i < 300; ++i) simulation.tick();
        nodeLevel1Enter
          .transition()
          .duration(1600)
          .attr("cx", function(d) {
            return d.x
          })
          .attr("cy", function(d) {
            return d.y
          })
          .attr("r", function(d) {
            return d.size
          });
      }
    }
    
    render();
    <script src="https://d3js.org/d3.v4.min.js"></script>
    
    <a href='javascript:;' id='updatesize'>Update red resource size</a> |
    <a href='javascript:;' id='updatebluesize'>Update blue resource size</a> |
    <a href='javascript:;' id='resetsize'>Reset red resource size</a> |
    <a href='javascript:;' id='resetall'>Reset all</a>
    推荐文章