【问题标题】:How to add text only on one side of the tree links如何仅在树链接的一侧添加文本
【发布时间】:2020-10-22 16:53:28
【问题描述】:

我正在使用 d3.js 绘制一棵树,当我在链接中添加方向和阈值时,它会在两侧绘制。

我这样添加文字:

.text(function(d) {
    return d.source.thresholds + ' ' + d.source.directions;
})

如何向此 .text 添加限制,使其仅绘制在链接的左侧,而不是在两者中。如何设置限制,以便仅在左侧链接中显示。

例如

var treeData = [{
  "name": "A",
  "directions": "<=",
  "thresholds": "12",
  "children": [{
      "name": "B",
      "directions": "<=",
      "thresholds": "12",
      "children": [{
          "name": "C",
          "directions": "<=",
          "thresholds": "4",
          "children": [{
              "name": "false"
            },
            {
              "name": "true"
            }
          ]
        },
        {
          "name": "A",
          "directions": "<=",
          "thresholds": "12",
          "children": [{
              "name": "B",
              "directions": "<=",
              "thresholds": "2",
              "children": [{
                  "name": "true"
                },
                {
                  "name": "false"
                }
              ]
            },
            {
              "name": "C",
              "directions": "<=",
              "thresholds": "5",
              "children": [{
                  "name": "false"
                },
                {
                  "name": "true"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "name": "B",
      "directions": "<=",
      "thresholds": "15",
      "children": [{
          "name": "D",
          "directions": "<=",
          "thresholds": "18",
          "children": [{
              "name": "E",
              "directions": "<=",
              "thresholds": "2.5",
              "children": [{
                  "name": "true"
                },
                {
                  "name": "false"
                }
              ]
            },
            {
              "name": "F",
              "directions": "<=",
              "thresholds": "4.8",
              "children": [{
                  "name": "false"
                },
                {
                  "name": "true"
                }
              ]
            }
          ]
        },
        {
          "name": "true"
        }
      ]
    }
  ]
}];


// ************** Generate the tree diagram  *****************
var margin = {
    top: 20,
    right: 120,
    bottom: 20,
    left: 120
  },
  width = 960 - margin.right - margin.left,
  height = 600 - margin.top - margin.bottom;

var i = 0;

var tree = d3.layout.tree()
  .size([height, width]);

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

var svg = d3.select("body").append("svg")
  .attr("width", width + margin.right + margin.left)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

root = treeData[0];

update(root);

function update(source) {

  // Compute the new tree layout.
  var nodes = tree.nodes(root).reverse(),
    links = tree.links(nodes);

  // Normalize for fixed-depth.
  nodes.forEach(function(d) {
    d.y = d.depth * 120;
  });

  // Declare the nodes…
  var node = svg.selectAll("g.node")
    .data(nodes, function(d) {
      return d.id || (d.id = ++i);
    });

  // Enter the nodes.
  var nodeEnter = node.enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")";
    });

  nodeEnter.append("circle")
    .attr("r", 10)
    .style("fill", "#fff");

  nodeEnter.append("text")
    .attr("x", function(d) {
      return d.children || d._children ? -13 : 13;
    })
    .attr("dy", ".35em")
    .attr("text-anchor", function(d) {
      return d.children || d._children ? "end" : "start";
    })
    .text(function(d) {
      return d.name;
    })
    .style("fill-opacity", 1);

  // Declare the links…
  var link = svg.selectAll("path.link")
    .data(links, function(d) {
      return d.target.id;
    });

  // Enter the links.
  link.enter().insert("path", "g")
    .attr("class", "link")
    .attr("d", diagonal);

  // Add threshold and directions
  link.enter().insert("text")
    .attr("font-family", "Arial, Helvetica, sans-serif")
    .attr("fill", "Black")
    .style("font", "normal 12px Arial")
    .attr("transform", function(d) {
      return "translate(" +
        ((d.source.x + d.target.x) / 2) + "," +
        ((d.source.y + d.target.y) / 2) + ")";
    })
    .attr("dy", ".35em")
    .attr("text-anchor", "middle")
    .text(function(d) {
      return d.source.thresholds + ' ' + d.source.directions;
    })

}
.node circle {
  fill: #fff;
  stroke: steelblue;
  stroke-width: 3px;
}

.node text {
  font: 12px sans-serif;
}

.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 2px;
}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"&gt;&lt;/script&gt;

任何帮助我如何解决这个问题将不胜感激。

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    您可以使用.filter() 将选择减少到仅左侧节点。具体来说,要仅选择具有左侧链接的节点,您可以使用

    .filter(function(d) {
      return d.target.x < d.source.x;
    })
    

    在一棵树中,您有nodeslinks。一个节点定义了一个打印的圆,包括它的位置(xy 坐标,从左上角算起)。链接包含对两个node 对象的引用,即它的源和目标。通过说d.target.x &lt; d.source.x,我实质上是说我只想查看目标节点的x 值低于(因此更靠近左侧)源节点的链接。

    var treeData = [{
      "name": "A",
      "directions": "<=",
      "thresholds": "12",
      "children": [{
          "name": "B",
          "directions": "<=",
          "thresholds": "12",
          "children": [{
              "name": "C",
              "directions": "<=",
              "thresholds": "4",
              "children": [{
                  "name": "false"
                },
                {
                  "name": "true"
                }
              ]
            },
            {
              "name": "A",
              "directions": "<=",
              "thresholds": "12",
              "children": [{
                  "name": "B",
                  "directions": "<=",
                  "thresholds": "2",
                  "children": [{
                      "name": "true"
                    },
                    {
                      "name": "false"
                    }
                  ]
                },
                {
                  "name": "C",
                  "directions": "<=",
                  "thresholds": "5",
                  "children": [{
                      "name": "false"
                    },
                    {
                      "name": "true"
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "name": "B",
          "directions": "<=",
          "thresholds": "15",
          "children": [{
              "name": "D",
              "directions": "<=",
              "thresholds": "18",
              "children": [{
                  "name": "E",
                  "directions": "<=",
                  "thresholds": "2.5",
                  "children": [{
                      "name": "true"
                    },
                    {
                      "name": "false"
                    }
                  ]
                },
                {
                  "name": "F",
                  "directions": "<=",
                  "thresholds": "4.8",
                  "children": [{
                      "name": "false"
                    },
                    {
                      "name": "true"
                    }
                  ]
                }
              ]
            },
            {
              "name": "true"
            }
          ]
        }
      ]
    }];
    
    
    // ************** Generate the tree diagram  *****************
    var margin = {
        top: 20,
        right: 120,
        bottom: 20,
        left: 120
      },
      width = 960 - margin.right - margin.left,
      height = 600 - margin.top - margin.bottom;
    
    var i = 0;
    
    var tree = d3.layout.tree()
      .size([height, width]);
    
    var diagonal = d3.svg.diagonal()
      .projection(function(d) {
        return [d.x, d.y];
      });
    
    var svg = d3.select("body").append("svg")
      .attr("width", width + margin.right + margin.left)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    root = treeData[0];
    
    update(root);
    
    function update(source) {
    
      // Compute the new tree layout.
      var nodes = tree.nodes(root).reverse(),
        links = tree.links(nodes);
    
      // Normalize for fixed-depth.
      nodes.forEach(function(d) {
        d.y = d.depth * 120;
      });
    
      // Declare the nodes…
      var node = svg.selectAll("g.node")
        .data(nodes, function(d) {
          return d.id || (d.id = ++i);
        });
    
      // Enter the nodes.
      var nodeEnter = node.enter().append("g")
        .attr("class", "node")
        .attr("transform", function(d) {
          return "translate(" + d.x + "," + d.y + ")";
        });
    
      nodeEnter.append("circle")
        .attr("r", 10)
        .style("fill", "#fff");
    
      nodeEnter.append("text")
        .attr("x", function(d) {
          return d.children || d._children ? -13 : 13;
        })
        .attr("dy", ".35em")
        .attr("text-anchor", function(d) {
          return d.children || d._children ? "end" : "start";
        })
        .text(function(d) {
          return d.name;
        })
        .style("fill-opacity", 1);
    
      // Declare the links…
      var link = svg.selectAll("path.link")
        .data(links, function(d) {
          return d.target.id;
        });
    
      // Enter the links.
      link.enter().insert("path", "g")
        .attr("class", "link")
        .attr("d", diagonal);
    
      // Add threshold and directions
      link.enter()
        .insert("text")
        .filter(function(d) {
          return d.target.x < d.source.x;
        })
        .attr("font-family", "Arial, Helvetica, sans-serif")
        .attr("fill", "Black")
        .style("font", "normal 12px Arial")
        .attr("transform", function(d) {
          return "translate(" +
            ((d.source.x + d.target.x) / 2) + "," +
            ((d.source.y + d.target.y) / 2) + ")";
        })
        .attr("dy", ".35em")
        .attr("text-anchor", "middle")
        .text(function(d) {
          return d.source.thresholds + ' ' + d.source.directions;
        })
    
    }
    .node circle {
      fill: #fff;
      stroke: steelblue;
      stroke-width: 3px;
    }
    
    .node text {
      font: 12px sans-serif;
    }
    
    .link {
      fill: none;
      stroke: #ccc;
      stroke-width: 2px;
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 非常感谢您的帮助! :) 如果您也能给我更多关于您为什么选择d.target.x &lt; d.source.x; 的线索,我将不胜感激。我的意思是这如何告诉只选择具有左侧链接的节点?我还想不通。再次感谢您!
    • 我用更详尽的解释扩展了我的答案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    • 1970-01-01
    • 2011-10-24
    • 2022-06-12
    • 2012-12-05
    • 1970-01-01
    相关资源
    最近更新 更多