【问题标题】:d3 tree diagram with straight linksd3 直链树图
【发布时间】:2020-04-06 21:24:36
【问题描述】:

我正在创建一个具有树形和径向可视化的树形图。

我正在使用

var radialDiagonal = d3.svg.diagonal.radial()
  .projection(function (d) {
    return [d.y, d.x / 180 * Math.PI];
  });

 var diagonal = d3.svg.diagonal()
  .projection(function (d) {
    return [d.x, d.y];
  });

渲染节点之间的链接,但我希望它是直的而不是圆的。

我错过了什么吗?

这是我的代码的 jsfiddle。

https://jsfiddle.net/burro92/j4q5yf7m/

【问题讨论】:

    标签: javascript d3.js svg treeview data-visualization


    【解决方案1】:

    要使用直线渲染链接,您只需设置<path>d 属性以在节点之间形成直线。 然而,d 巧合地也是 d3.js 命名回调函数参数的约定,回调函数传递给函数,如 selection.attr()selection.style() 函数。后一个d 参数是指附加到选择的数据。 对于树形布局,您可以分别用d.source.xd.source.y 访问一个节点的位置,用d.target.x and d.target.y 访问另一个节点的位置。 见https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links

    node.links()

    返回此节点的链接数组,其中每个链接都是一个对象 定义源和目标属性。每个链接的来源是 父节点,目标是子节点。

    在您的情况下,您只需定义一个函数来为每个链接创建正确的 d 属性:

    var straight = d => "M" + d.source.x + "," + d.source.y
          + "H" + d.target.x + "V" + d.target.y;
    

    然后在你绘制链接路径时调用该函数:

    var link = svg.selectAll('.link')
          .data(links)
          .enter()
          .append('path')
          .attr('class', 'link')
          .style('stroke', '#8da0cb')
          .attr('d', straight);
    

    这里你的例子是一个直线树:

       function findColor(info) {
          if (info.data.color) return info.data.color;
          if (info.parent) return findColor(info.parent)
          return '#ccc';
        }
    
        function transitionToRadialTree() {
    
          var nodes = radialTree.nodes(root), // recalculate layout
            links = radialTree.links(nodes);
    
          svg.transition().duration(duration)
            .attr('transform', 'translate(' + (width / 2) + ',' +
              (height / 2) + ')');
          // set appropriate translation (origin in middle of svg)
    
          link.data(links)
            .transition()
            .duration(duration)
            .style('stroke', '#fc8d62')
            .attr('d', radialDiagonal); //get the new radial path
    
          node.data(nodes)
            .transition()
            .duration(duration)
            .attr('transform', function (d) {
              return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')';
            });
    
          node.select('circle')
            .transition()
            .duration(duration)
            .style('stroke', '#984ea3');
    
        };
    
        function transitionToTree(isStraight) {
    
          var nodes = tree.nodes(root), //recalculate layout
            links = tree.links(nodes);
    
          svg.transition().duration(duration)
            .attr("transform", 'translate(' + margin.left + ',' + margin.top + ')');
    
          link.data(links)
            .transition()
            .duration(duration)
            .style('stroke', '#e78ac3')
            .attr('d', isStraight ? straight : diagonal); // get the new tree path
    
          node.data(nodes)
            .transition()
            .duration(duration)
            .attr('transform', function (d) {
              return 'translate(' + d.x + ',' + d.y + ')';
            });
    
          node.select('circle')
            .transition()
            .duration(duration)
            .style('stroke', '#377eb8');
    
        };
    
        const root =
        {
          name: 'Main',
          color: '#00FF00',
          children: [
            {
              name: 'First level A',
              color: '#F5FF8A',
              children: [
                {
                  name: 'Second level A',
                  children: [
                    {
                      name: 'Third level A',
                      children: [
                        {
                          name: 'Fourth level A',
                        },
                        {
                          name: 'Fourth level B',
                        }
                      ]
                    },
                  ]
                }
              ]
            },
            {
              color: '#DA59FF',
              name: 'First level B',
              children: [
                {
                  name: 'Second level B',
                  children: [
                    {
                      name: 'Third level B',
                      children: [
                        {
                          name: 'Fourth level A',
                        }
                      ]
                    },
                  ]
                }
              ]
            },
            {
              name: 'First level C',
              color: '#FA935A',
              children: [
                {
                  name: 'Second level C',
                  children: [
                    {
                      name: 'Third level C',
                      children: [
                        {
                          name: 'Fourth level A',
                        },
                        {
                          name: 'Fourth level B',
                        }
                      ]
                    },
                  ]
                }
              ]
            },
          ]
        };
    
        // set the dimensions and margins of the diagram
        var margin = { top: 40, right: 0, bottom: 50, left: 0 };
        var width = 500;
        var height = 500;
        var diameter = 500 - margin.top - margin.bottom;
        var duration = 300;
    
    
        var tree = d3.layout.tree()
          .size([height, width - 160]);
    
        var cluster = d3.layout.cluster()
          .size([height, width - 160]);
    
        var diagonal = d3.svg.diagonal()
          .projection(function (d) {
            return [d.x, d.y];
          });
    
        // var straight = d => "M" + d.target.x + "," + d.target.y
        //  + "V" + d.source.y + "H" + d.source.x;
    
        var straight = d => "M" + d.source.x + "," + d.source.y
          + "H" + d.target.x + "V" + d.target.y;
    		
        var radialTree = d3.layout.tree()
          .size([360, diameter / 2])
          .separation(function (a, b) {
            return (a.parent == b.parent ? 1 : 2) / a.depth;
          });
          
    
        var radialCluster = d3.layout.cluster()
          .size([360, diameter / 2])
          .separation(function (a, b) {
            return (a.parent == b.parent ? 1 : 2) / a.depth;
          });
    
        var radialDiagonal = d3.svg.diagonal.radial()
          .projection(function (d) {
            return [d.y, d.x / 180 * Math.PI];
          });
    
    
        var svg = d3.select('body').append('svg')
          .attr('width', width)
          .attr('height', height)
          .append('g')
          
          .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
    
    
        // var root = getData(),
        var nodes = cluster.nodes(root);
        var links = cluster.links(nodes);
    
        var link = svg.selectAll('.link')
          .data(links)
          .enter()
          .append('path')
          .attr('class', 'link')
          .style('stroke', '#8da0cb')
          .attr('d', diagonal);
    
        var node = svg.selectAll('.node')
          .data(nodes)
          .enter()
          .append('g')
          
          .attr('class', 'node')
          
          .attr('transform', function (d) {
            return 'translate(' + d.x + ',' + d.y + ')';
          })
    
        node.append('circle')
          .attr('r', 4.5)
          .style('stroke', '#e41a1c');
    /*
                node.append('text')
                    .attr('dx', function (d) { return d.children ? -8 : 8; })
                    .attr('dy', 3)
                    .style('text-anchor', function (d) { return d.children ? 'end' : 'start'; })
                    .text(function (d) { return d.name; });
            */
        // renderTree();
      /* set the CSS */
      body {
        background-color: #181833;
      }
    
      .node circle {
        fill: #fff;
        /* stroke: steelblue; */
        stroke-width: 3px;
      }
    
      .node text {
        font: 12px sans-serif;
        fill: #ccc;
      }
    
      /* .node--internal text {
        text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
      }*/
    
      .link {
        fill: none;
        stroke: #ccc;
        stroke-width: 2px;
        opacity: 0.75;
      }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
    <meta charset='utf-8'>
    
      <button onclick='transitionToRadialTree()'>Radial</button>
      <button onclick='transitionToTree(false)'>Tree</button>
      <button onclick='transitionToTree(true)'>straight Tree</button>
    
      <svg id='hostElement'></svg>

    但效果不佳的是另一个问题,即如何在不同表示之间平滑过渡。原因是如果标准转换可以“轻松”找出如何将初始路径的“结构”与目标路径匹配,则两条任意路径之间的转换只是平滑的。您的两个示例都满足该标准,因为它们都使用基于三次贝塞尔曲线的类似路径。为此,您可能正在研究 https://github.com/pbeshai/d3-interpolate-path 之类的东西(但我认为这个库适用于 d3.v4)

    【讨论】:

      猜你喜欢
      • 2019-09-13
      • 1970-01-01
      • 2013-08-16
      • 2013-07-21
      • 1970-01-01
      • 2015-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多