如何更改 D3 的 diagonal() 使用的贝塞尔曲线函数?

How can I alter the bezier function used by D3's diagonal()?

我正在基于 Bernhard Zuba's D3.js Organizational Chart 在 D3 中创建组织结构图。组织结构图模拟了一个组织,其中任何给定的人(用白色方块表示)下面可能有一百多个人(一个非常扁平的树结构,黑色贝塞尔曲线代表每个父子关系)。

这是树的一部分的屏幕截图:

还有上图中父节点底部的放大图:

问题是子节点和父节点之间的链接往往会聚在一起,导致一条非常粗的黑线和一个非常渐变的斜率,这可能有点碍眼。

我用来生成链接的函数如下:

// Diagonal function
var diagonal = d3.svg.diagonal()
.source(function (d) {
    return {
        x: d.source.x + (rectW / 2),
        y: d.source.y + rectH - 10
    };
})
.target(function (d) {
    return {
        x: d.target.x + (rectW / 2),
        y: d.target.y + 10
    };
})
.projection(function (d) {
    return [d.x, d.y];
});

这里,rectW是每个节点的宽度,rectH是每个节点的高度。

我想做的是对用于生成链接的贝塞尔函数做一些细微的调整。具体来说,我想稍微拉平控制点,使曲线起点和终点的曲线更加生动。如果有人能告诉我如何改变 diagonal() 使用的函数来生成贝塞尔曲线,我就能弄清楚剩下的部分。

如果您为此查看 svg.diagonal, I can't really see a direct way to adjust just the control points. You'd think you could use projection 的源代码,但这将转换用于生成路径的所有 4 个点。现在,我想我们可以对投影有点 hacky 并做这样的事情:

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@3.5.17" data-semver="3.5.17" src="https://d3js.org/d3.v3.min.js"></script>
</head>

<body>
  <script>
    var data = [{
        source: {
          x: 10,
          y: 10
        },
        target: {
          x: 200,
          y: 200
        }
      }, {
        source: {
          x: 50,
          y: 50
        },
        target: {
          x: 200,
          y: 200
        }
      }];

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

    var diagonal = d3.svg.diagonal()
      .projection(function(d) {
        if (!this.times) this.times = 0;
        this.times++;
        console.log(this.times);
        if (this.times === 1) {
          return [d.x, d.y];
        } else if (this.times === 2) {
          return [d.x - 25, d.y]
        } else if (this.times === 3) {
          return [d.x + 25, d.y];
        } else if (this.times === 4) {
          this.times = 0;
          return [d.x, d.y];
        }
      });

    svg.selectAll('path')
      .data(data)
      .enter()
      .append('path')
      .attr('d', diagonal)
      .style('fill', 'none')
      .style('stroke', 'black');
  </script>
</body>

</html>


我可能想多了。你最好自己画弧线:

    <!DOCTYPE html>
    <html>

    <head>
      <script data-require="d3@3.5.17" data-semver="3.5.17" src="https://d3js.org/d3.v3.min.js"></script>
    </head>

    <body>
      <script>
        var data = [{
            source: {
              x: 10,
              y: 10
            },
            target: {
              x: 200,
              y: 200
            }
          }, {
            source: {
              x: 200,
              y: 10
            },
            target: {
              x: 10,
              y: 200
            }
          }];

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

        svg.selectAll('path')
          .data(data)
          .enter()
          .append('path')
          .attr('d', function(d){
              var s = d.source,
                  t = d.target,
                  m = (s.y + t.y) / 2,
                  p0 = [s.x, s.y],
                  p1 = [s.x, m],
                  p2 = [t.x, m],
                  p3 = [t.x, t.y];
              
              // adjust constrol points
              p1[0] -= 25;
              p2[0] += 25;
                  
              return "M" + p0 + "C" + p1 + " " + p2 + " " + p3;    
          })
          .style('fill', 'none')
          .style('stroke', 'black');
      </script>
    </body>

    </html>