在d3强制定向中,如何通过单击更改节点形状?

时间:2016-11-11 02:51:57

标签: javascript node.js d3.js svg graph

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

我已经查看了this以及有关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以了解我应该改变什么。谢谢。

1 个答案:

答案 0 :(得分:3)

当你说:

时没用
  

我已经在SO上查看了这个问题和相关问题,但我认为它们适用于早期版本的D3,并且对我不起作用。

在我看来that answer中没有任何内容表明它在D3 v4.x中不起作用。值得一提的是,在您链接的答案(和问题)中,node是一个组元素,因此this指的是组,而不是圆/矩形。< / p>

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

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);};
};

这是一个演示:

&#13;
&#13;
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 + ")"; });
}
&#13;
.link {
  stroke: #aaa;
}

.node {
  stroke: none;
  stroke-width: 40px;
}
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="400" height="300"></svg>
&#13;
&#13;
&#13;