D3.js 静态力布局不适用于路径?

D3.js static force layout not working with path?

我正在尝试更改此示例 https://bl.ocks.org/mbostock/1667139 以使用路径而不是行,但它不起作用。 我尝试像这样使用自己的刻度函数:

function tick() {
            link.attr("d", function(d) {
            var x1 = d.source.x,
                y1 = d.source.y,
                x2 = d.target.x,
                y2 = d.target.y,
                dx = x2 - x1,
                dy = y2 - y1,
                dr = Math.sqrt(dx * dx + dy * dy),

                // z uzla do ineho uzla
                drx = dr,
                dry = dr,
                xRotation = 0,
                largeArc = 0,
                sweep = 1;

            //do sameho seba
            if ( x1 === x2 && y1 === y2 ) {
                xRotation = -45;
                largeArc = 1;
                drx = 30;
                dry = 30;
                x2 = x2 + 1;
                y2 = y2 + 1;
            }

            return "M" + x1 + "," + y1 + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + x2 + "," + y2;
        });     
}

我不知道,如果我遗漏了什么或静态力布局无法使用路径。 强制布局,路径正常工作

来自 docs(加粗我的):

simulation.tick()

Increments the current alpha by (alphaTarget - alpha) × alphaDecay; then invokes each registered force, passing the new alpha; then decrements each node’s velocity by velocity × velocityDecay; lastly increments each node’s position by velocity.

This method does not dispatch events; events are only dispatched by the internal timer when the simulation is started automatically upon creation or by calling simulation.restart. The natural number of ticks when the simulation is started is ⌈log(alphaMin) / log(1 - alphaDecay)⌉; by default, this is 300.

This method can be used in conjunction with simulation.stop to compute a static force layout. For large graphs, static layouts should be computed in a web worker to avoid freezing the user interface.

因为它不分派事件,所以永远不会调用或使用您的 tick 函数。相反,只需替换该行并设置一次路径:

<!DOCTYPE html>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
  var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height"),
    g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

  var n = 100,
    nodes = d3.range(n).map(function(i) {
      return {
        index: i
      };
    }),
    links = d3.range(n).map(function(i) {
      return {
        source: i,
        target: (i + 3) % n
      };
    });

  var simulation = d3.forceSimulation(nodes)
    .force("charge", d3.forceManyBody().strength(-80))
    .force("link", d3.forceLink(links).distance(20).strength(1).iterations(10))
    .force("x", d3.forceX())
    .force("y", d3.forceY())
    .stop();

  var loading = svg.append("text")
    .attr("dy", "0.35em")
    .attr("text-anchor", "middle")
    .attr("font-family", "sans-serif")
    .attr("font-size", 10)
    .text("Simulating. One moment please…");

  // Use a timeout to allow the rest of the page to load first.
  d3.timeout(function() {
    loading.remove();

    // See https://github.com/d3/d3-force/blob/master/README.md#simulation_tick
    for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) {
      simulation.tick();
    }

    g.append("g")
      .attr("stroke", "#000")
      .attr("stroke-width", 1.5)
      .selectAll("line")
      .data(links)
      .enter().append("path")
      .attr("d", function(d) {
        var x1 = d.source.x,
          y1 = d.source.y,
          x2 = d.target.x,
          y2 = d.target.y,
          dx = x2 - x1,
          dy = y2 - y1,
          dr = Math.sqrt(dx * dx + dy * dy),

          // z uzla do ineho uzla
          drx = dr,
          dry = dr,
          xRotation = 0,
          largeArc = 0,
          sweep = 1;

        //do sameho seba
        if (x1 === x2 && y1 === y2) {
          xRotation = -45;
          largeArc = 1;
          drx = 30;
          dry = 30;
          x2 = x2 + 1;
          y2 = y2 + 1;
        }

        return "M" + x1 + "," + y1 + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + x2 + "," + y2;
      });

    g.append("g")
      .attr("stroke", "#fff")
      .attr("stroke-width", 1.5)
      .selectAll("circle")
      .data(nodes)
      .enter().append("circle")
      .attr("cx", function(d) {
        return d.x;
      })
      .attr("cy", function(d) {
        return d.y;
      })
      .attr("r", 4.5);


  });
</script>

回复评论:

要将圆圈和文本附加为 "node",我会创建一个 g,定位它,然后将圆圈和文本放入其中:

  var g = node
    .selectAll(".node")
    .data(nodes)
    .enter()
    .append("g")
    .attr("transform", function(d){
      return "translate(" + d.x + "," + d.y + ")";
    });

  g.append("circle")
    .attr("class", "node")
    .attr("stroke", "#fff")
    .attr("r", 28);

  g.append("text")
    .text("test");