在d3中,我如何通过点击来改变一个节点的形状

In d3 force directed, how do I change a nodes shape by clicking on it?

本文关键字:一个 节点 改变 d3 何通过      更新时间:2023-09-26

我在d3中有一个力定向图,并希望能够点击圆形节点并使它们变成矩形。然后如果我点击一个矩形,我想让它恢复为圆形。

我已经看过这个和有关SO的相关问题,但我认为它们适用于D3的早期版本,不适合我。

我可以让它,所以我的圆圈的大小和颜色将改变点击,并与以下代码,我可以有圆圈节点替换为黑色矩形,但它不附加到图形,只是一个黑色的正方形上的svg。

node.on("click", function(d,i) {
      var size = 20;
      d3.select(this).remove();
      svg.append("rect")
          .attr("x", d.x)
          .attr("y", d.y)
          .attr("height", size)
          .attr("width", size)
          .style("fill", function(d) {
            return color( d.group);
          });
})
谁能告诉我我错过了什么?我怀疑rect没有附在图形数据上,但我对d3不够熟悉,无法理解我应该改变什么。谢谢你!

当你说:

我看过这个和有关SO的相关问题,但我认为它们适用于D3的早期版本,不适合我。

在我看来,这个答案中没有任何东西表明它不会在D3 v4.x中工作。值得一提的是,在您链接的答案(和问题)中,node是一个群元素,因此this指的是群,而不是圆/矩形。

继续,一个可能的解决方案(不涉及删除和添加元素)是用矩形模拟圆:

node.append("rect")
    .attr("width", 16)
    .attr("height", 16)
    .attr("rx", 8)
    .attr("ry", 8)

在点击功能内部,改变rxry:

function click() {
    if(d3.select(this).attr("rx") == 8){
        d3.select(this).attr("rx", 0).attr("ry", 0);
    } else {
        d3.select(this).attr("rx", 8).attr("ry", 8);};
};

下面是一个示例:

var nodes = [
  {"id": 1},
  {"id": 2},
  {"id": 3},
  {"id": 4},
  {"id": 5},
  {"id": 6},
  {"id": 7},
  {"id": 8},
  {"id": 9},
  {"id": 10},
  {"id": 11},
  {"id": 12}
];
var links = [
  {source: 1, target: 8},
  {source: 1, target: 3},
  {source: 1, target: 4},
	{source: 1, target: 9},
	{source: 1, target: 10},
	{source: 1, target: 11},
  {source: 2, target: 5},
  {source: 2, target: 6},
	{source: 2, target: 7},
	{source: 2, target: 12},
  {source: 2, target: 4},
	{source: 2, target: 8},
  {source: 6, target: 7},
  {source: 6, target: 8},
  {source: 6, target: 9},
	{source: 6, target: 5},
  {source: 6, target: 3},
  {source: 6, target: 9},
]
var index = 10;
var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height"),
    node,
    link;
var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) { return d.id; }))
    .force("charge", d3.forceManyBody())
		.force("collide", d3.forceCollide(30))
    .force("center", d3.forceCenter(width / 2, height / 2));
update();
function update() {
  link = svg.selectAll(".link")
    .data(links, function(d) { return d.target.id; })
  link = link.enter()
    .append("line")
    .attr("class", "link");
  node = svg.selectAll(".node")
    .data(nodes, function(d) { return d.id; })
  node = node.enter()
    .append("g")
    .attr("class", "node");
  node.append("rect")
		.attr("width", 16)
    .attr("height", 16)
		.attr("rx", 8)
		.attr("ry", 8)
		.attr("fill", "teal")
		.on("click", click);
  simulation
      .nodes(nodes)
      .on("tick", ticked);
  simulation.force("link")
      .links(links);
}
function click() {
  if(d3.select(this).attr("rx") == 8){d3.select(this).attr("rx", 0).attr("ry", 0);}
	else{d3.select(this).attr("rx", 8).attr("ry", 8);};
}
function ticked() {
  link
      .attr("x1", function(d) { return d.source.x + 8; })
      .attr("y1", function(d) { return d.source.y + 8; })
      .attr("x2", function(d) { return d.target.x+ 8; })
      .attr("y2", function(d) { return d.target.y+ 8; });
  node
      .attr("transform", function(d) { return "translate(" + d.x + ", " + d.y + ")"; });
}
.link {
  stroke: #aaa;
}
.node {
  stroke: none;
  stroke-width: 40px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="400" height="300"></svg>