如何改变D3对角线()使用的贝塞尔函数?

时间:2016-10-14 17:06:57

标签: d3.js tree bezier orgchart

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

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

这里放大了上图中父节点底部的放大图: enter image description here

问题在于,子节点和父节点之间的链接往往全部聚集在一起,导致非常粗的黑色线条具有非常渐变的斜率,这可能会有点像眼睛。

我用来生成链接的功能如下:

// 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()生成贝塞尔曲线所使用的函数,我可以弄清楚其余部分。

1 个答案:

答案 0 :(得分:1)

如果您查看svg.diagonal的源代码,我无法真正看到调整只是控制点的直接方法。您认为可以使用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>