1

我是 d3 的新手,我正在尝试用左右节点渲染这个 d3 树形图。初始树渲染工作正常,我添加了一个切换功能,该功能将使子项为 null 并调用渲染方法,但它不起作用。请帮忙。

var data = {
  "name": "Root",
  "children": [{
      "name": "Branch 1"
    }, {
      "name": "Branch 2",
      "children": [{
        "name": "Branch 2.1"
      }, {
        "name": "Branch 2.2",
        "children": [{
          "name": "Branch 2.2.1"
        }, {
          "name": "Branch 2.2.2"
        }]
      }]
    }, {
      "name": "Branch 3"
    }, {
      "name": "Branch 4",
      "children": [{
        "name": "Branch 4.1"
      }, {
        "name": "Branch 4.2"
      }]
    }, {
      "name": "Branch 5"
    },


    {
      "name": "Branch 6"
    }, {
      "name": "Branch 7",
      "children": [{
        "name": "Branch 7.1"
      }, {
        "name": "Branch 7.2",
        "children": [{
          "name": "Branch 7.2.1"
        }, {
          "name": "Branch 7.2.2"
        }]
      }]
    }, {
      "name": "Branch 8"
    }, {
      "name": "Branch 9",
      "children": [{
        "name": "Branch 9.1"
      }, {
        "name": "Branch 9.2"
      }]
    }, {
      "name": "Branch 10"
    }
  ]
};

var split_index = Math.round(data.children.length / 2)

// Left data
var data1 = {
  "name": data.name,
  "children": JSON.parse(JSON.stringify(data.children.slice(0, split_index)))
};

// Right data
var data2 = {
  "name": data.name,
  "children": JSON.parse(JSON.stringify(data.children.slice(split_index)))
};

// Create d3 hierarchies
var right = d3.hierarchy(data1);
var left = d3.hierarchy(data2);

// Render both trees
drawTree(right, "right")
drawTree(left, "left")

// draw single tree
function drawTree(root, pos) {

  var SWITCH_CONST = 1;
  if (pos === "left") {
    SWITCH_CONST = -1;
  }

  var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height")

  // Shift the entire tree by half it's width
  var g = svg.append("g").attr("transform", "translate(" + width / 2 + ",0)");

  // Create new default tree layout
  var tree = d3.tree()
    // Set the size
    // Remember the tree is rotated
    // so the height is used as the width
    // and the width as the height
    .size([height, SWITCH_CONST * (width - 150) / 2]);

  tree(root)

  var nodes = root.descendants();
  var links = root.links();
  // Set both root nodes to be dead center vertically
  nodes[0].x = height / 2

  // Create links
  var link = g.selectAll(".link")
    .data(links)
    .enter()

  link.append("path")
    .attr("class", "link")
    .attr("d", function(d) {
      return "M" + d.target.y + "," + d.target.x + "C" + (d.target.y + d.source.y) / 2.5 + "," + d.target.x + " " + (d.target.y + d.source.y) / 2 + "," + d.source.x + " " + d.source.y + "," + d.source.x;
    });

  // Create nodes
  var node = g.selectAll(".node")
    .data(nodes)
    .enter()
    .append("g")
    .attr("class", function(d) {
      return "node" + (d.children ? " node--internal" : " node--leaf");
    })
    .attr("transform", function(d) {
      return "translate(" + d.y + "," + d.x + ")";
    }).on("click", function(e, d) {
      toggle(d, pos);
    })

  node.append("circle")
    .attr("r", function(d, i) {
      return 2.5
    });

  node.append("text")
    .attr("y", -10)
    .style("text-anchor", "middle")
    .text(function(d) {
      return d.data.name
    });
}

function toggle(d, pos) {
  console.log(d, pos);
  if (d.children) {
    d._children = d.children;
    d.children = null;
  } else {
    d.children = d._children;
    d._children = null;
  }
  this.drawTree(d, pos);
}
.node circle {
  fill: #999;
}

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

.node--internal circle {
  fill: #555;
}

.link {
  fill: none;
  stroke: #555;
  stroke-opacity: 0.4;
  stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<svg width="900" height="600"></svg>

4

1 回答 1

0

您只附加了新节点,从未删除它们。这样,点击后旧节点将保留在那里。您可以使用.join().

此外,您将单击的节点用作树的新根,但这是无效的。相反,传递真正的根并完全重新绘制树的那部分。否则,树的其余部分将被完全遗忘。

var data = {
  "name": "Root",
  "children": [{
      "name": "Branch 1"
    }, {
      "name": "Branch 2",
      "children": [{
        "name": "Branch 2.1"
      }, {
        "name": "Branch 2.2",
        "children": [{
          "name": "Branch 2.2.1"
        }, {
          "name": "Branch 2.2.2"
        }]
      }]
    }, {
      "name": "Branch 3"
    }, {
      "name": "Branch 4",
      "children": [{
        "name": "Branch 4.1"
      }, {
        "name": "Branch 4.2"
      }]
    }, {
      "name": "Branch 5"
    },


    {
      "name": "Branch 6"
    }, {
      "name": "Branch 7",
      "children": [{
        "name": "Branch 7.1"
      }, {
        "name": "Branch 7.2",
        "children": [{
          "name": "Branch 7.2.1"
        }, {
          "name": "Branch 7.2.2"
        }]
      }]
    }, {
      "name": "Branch 8"
    }, {
      "name": "Branch 9",
      "children": [{
        "name": "Branch 9.1"
      }, {
        "name": "Branch 9.2"
      }]
    }, {
      "name": "Branch 10"
    }
  ]
};

var split_index = Math.round(data.children.length / 2)

// Left data
var data1 = {
  "name": data.name,
  "children": JSON.parse(JSON.stringify(data.children.slice(0, split_index)))
};

// Right data
var data2 = {
  "name": data.name,
  "children": JSON.parse(JSON.stringify(data.children.slice(split_index)))
};

// Create d3 hierarchies
var right = d3.hierarchy(data1);
var left = d3.hierarchy(data2);

var svg = d3.select("svg"),
  width = +svg.attr("width"),
  height = +svg.attr("height");

// Shift the entire tree by half it's width
var g = svg.append("g")
  .attr("transform", "translate(" + width / 2 + ",0)");

// Render both trees
drawTree(right, "right")
drawTree(left, "left")

// draw single tree
function drawTree(root, pos) {

  var SWITCH_CONST = 1;
  if (pos === "left") {
    SWITCH_CONST = -1;
  }

  // Create new default tree layout
  var tree = d3.tree()
    // Set the size
    // Remember the tree is rotated
    // so the height is used as the width
    // and the width as the height
    .size([height, SWITCH_CONST * (width - 150) / 2]);

  tree(root)

  var nodes = root.descendants();
  var links = root.links();
  // Set both root nodes to be dead center vertically
  nodes[0].x = height / 2

  // Create links
  var link = g.selectAll(".link." + pos)
    .data(links)
    .join(
      enter => enter.append("path"),
      update => update,
      exit => exit.remove()
    )
    .attr("class", "link " + pos)
    .attr("d", function(d) {
      return "M" + d.target.y + "," + d.target.x + "C" + (d.target.y + d.source.y) / 2.5 + "," + d.target.x + " " + (d.target.y + d.source.y) / 2 + "," + d.source.x + " " + d.source.y + "," + d.source.x;
    });

  // Create nodes
  var node = g.selectAll(".node." + pos)
    .data(nodes)
    .join(
      enter => {
        const n = enter
          .append("g")
          .on("click", (e, d) => toggle(d, pos, pos === "left" ? left : right));

        n.append("circle").attr("r", 2.5);
        n.append("text").attr("y", -10).style("text-anchor", "middle");
        return n;
      },
      update => update,
      exit => exit.remove()
    )
    .attr("class", function(d) {
      return "node " + pos + (d.children ? " node--internal" : " node--leaf");
    })
    .attr("transform", function(d) {
      return "translate(" + d.y + "," + d.x + ")";
    })
    .select("text")
    .text(function(d) {
      return d.data.name
    });
}

function toggle(d, pos, root) {
  if (d.children) {
    d._children = d.children;
    d.children = null;
  } else {
    d.children = d._children;
    d._children = null;
  }
  this.drawTree(root, pos);
}
.node circle {
  fill: #999;
}

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

.node--internal circle {
  fill: #555;
}

.link {
  fill: none;
  stroke: #555;
  stroke-opacity: 0.4;
  stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<svg width="900" height="600"></svg>

于 2020-10-21T08:04:18.343 回答