动态更改附加 D3

Dynamically Change the Append D3

    var data = [
            {"name": "Lincoln", "pid":1, "sex": "M"},
            {"name": "Tad", "pid":2, "sex":"M"},
            {"name": "Mary", "pid":3, "sex": "F"},
          ];
    
    var nodes = svg.append("g")
          .selectAll("rect")
          .selectAll("circle")
          .data(information.descendants())
          .enter()
          .append(function(d){
            getPerson(d.data.child).sex === "M" ? "rect" : "circle"
          })

我想根据人物的性别设置圆形或矩形。我不知道是否有适当的约定来设置这些条件。我不知道如何在两者之间正确切换,因为如果它是男性和“矩形”,则需要设置 .attr("x") 和 .attr("y")。如果是“圆圈”,则还需要设置 .attr("cx") 和 .attr("cy") 以及 .attr("r")。

information.descendants() 基于传递到树结构中的 d3.stratify() (d3.tree())。

有很多方法可以实现这一点。下面的第一个选项仅使用矩形,第二个和第三个选项使用 svg 路径(所有三个选项都简化了定位、选择修改、从一个到另一个更改形状。)

第四个选项是追加,其中元素在矩形和圆形之间变化。

圆一些矩形

如果您的形状是圆形和方形,也许最简单的方法是使用具有 rx, ry 属性的矩形,这样一些矩形看起来像矩形,而另一些像圆形:

var data = [
  {x: 100, y: 100, circle: true},
  {x: 200, y: 100, circle: false}
]

var width = 20;

d3.select("body")
  .append("svg")
  .selectAll(null)
  .data(data)
  .enter()
  .append("rect")
  .attr("x",d=>d.x)
  .attr("y",d=>d.y)
  .attr("rx",d=>d.circle?width/2:0)
  .attr("ry",d=>d.circle?width/2:0)
  .attr("width", width)
  .attr("height",width);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

使用D3.symbol

我们可以使用路径而不是矩形或圆,d3.symbol returns 路径数据并且有一个圆和一个矩形,d3.symbol 如果我们想改变,有一个大小方法大小(符号以其中心坐标为中心,如圆圈):

var data = [
  {x: 100, y: 100, circle: true},
  {x: 200, y: 100, circle: false}
]

var width = 20;

d3.select("body")
  .append("svg")
  .selectAll(null)
  .data(data)
  .enter()
  .append("path")
  .attr("transform",d=>"translate("+[d.x,d.y]+")")
  .attr("d", function(d) {
    var symbol = d.circle ? d3.symbolCircle : d3.symbolSquare;
    return d3.symbol().type(symbol).size(300)();
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

创建自己的路径

我们可以只使用一个函数来代替符号 returns 圆形或矩形的路径数据,比 d3.symbol 给你更多的灵活性,但失去了它的一些简单性(例如符号的简单重新缩放):

var data = [
  {x: 100, y: 100, circle: true},
  {x: 200, y: 100, circle: false}
]

var width = 20;

d3.select("body")
  .append("svg")
  .selectAll(null)
  .data(data)
  .enter()
  .append("path")
  .attr("transform",d=>"translate("+[d.x,d.y]+")")
  .attr("d", pather)
  
function pather(d) {
  if(d.circle) {
    return "M10,10m-10,0a10,10 0 1,0 20,0a 10,10 0 1,0 -20,0"
  }
  else {
    return "M0,0L0,20L20,20L20,0Z";
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

一次追加同时创建矩形和圆形

selection.append() 可以接受一个函数——函数返回的任何元素都会附加到 DOM。为了制作我们的节点,我们将创建一个分离的 SVG 元素并向其添加一个圆圈。

var data = [
  {x: 100, y: 100, circle: true},
  {x: 200, y: 100, circle: false}
]

var width = 20;

d3.select("body")
  .append("svg")
  .selectAll(null)
  .data(data)
  .enter()
  .append(makeShape)
  
  
function makeShape(d) {
  // create a temporary svg
  let svg = document.createElementNS(d3.namespaces.svg, "svg")
  // create an element:
  if(d.circle) {
    return d3.select(svg)
      .append("circle")
      .attr("cx",d.x)
      .attr("cy",d.y)
      .attr("r", 10)
      .node() // return node, not selection.
  }
  else {
    return d3.select(svg)
      .append("rect")
      .attr("x",d.x)
      .attr("y",d.y)
      .attr("width", 20)
      .attr("height", 20)
      .node();
  }  
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

但是现在您可以选择圆形和矩形 - 以后处理起来会更麻烦。