javascript – 将圈子和路径分组为D3 Force Layout中的节点?

我试图在力导向图布局中对圆圈进行分组,这样我就可以添加半圆的路径,使圆圈成为两个半圆可点击的边.我设法使双方半圆可点击与d3的工作就像
this fiddle.我似乎无法包装d3概念如何分组,并连接链接.

如何对圆圈和路径进行分组并使其与力布局一起使用?为使这项工作我无法理解的概念是什么?我做错了什么?

双面可点击半圆代码

var vis = d3.select("body").append("svg")
var pi = Math.PI;

var arc = d3.svg.arc()
    .innerRadius(0)
    .outerRadius(70)
    .startAngle(0) //converting from degs to radians
    .endAngle(pi) //just radians

var canvas = vis.attr("width", "400").attr("height", "400").append("g");


 // Added height and width so arc is visible
        canvas.append("circle")
    .attr("r", "70px")
    .attr("fill","blue")
    .attr("cx",400/2)
    .attr("cy",400/2)
    .on("click", function(d){
        console.log("View");
    })
    .on("mouseover", function(){            d3.select(this).style("fill", "blue");
    console.log(d3.select(this.parentNode).select(".view").style("visibility","visible"));
    })
    .on("mouseout", function(){
            d3.select(this).style("fill", "blue");
        console.log(d3.select(this.parentNode).select(".view").style("visibility","hidden"));
     });

    canvas.append("path")
    .attr("d", arc)
    .attr("fill", "blue")
    .attr("transform", "translate(200,200)")
    .on("click",function(d){
         console.log("Expand");

    })
    .on("mouseover", function(){            d3.select(this).style("fill", "blue");
    console.log(d3.select(this.parentNode).select(".expand").style("visibility","visible"));

    })
    .on("mouseout", function(){
            d3.select(this).style("fill", "blue");
        console.log(d3.select(this.parentNode).select(".expand").style("visibility","hidden"));

     });

   canvas.append("text")
    .attr("dx", "190")
    .attr("dy","200")
    .attr("class","view")
      .text("VIEW")

    canvas.append("text")
    .attr("dx", "190")
    .attr("dy","200")
    .attr("class","expand")
      .text("Expand")

强制使用圆作为节点代码的强制布局,受此stackoverflow question的启发

fiddle

var words = [{
  "group": "n",
  "word": "main node",
  "children": [{
    "group": "n",
    "name": "sub node 1"
  }, {
    "group": "n",
    "name": "sub node 2"
  }, {
    "group": "n",
    "name": "sub node 3"
  }, {
    "group": "v",
    "name": "sub node 4"
  }, {
    "group": "s",
    "name": "sub node 5"
  }, {
    "group": "s",
    "name": "sub node 6"
  }, {
    "group": "s",
    "name": "sub node 7"
  }, {
    "group": "s",
    "name": "sub node 8"
  }, {
    "group": "s",
    "name": "sub node 9"
  }, {
    "group": "s",
    "name": "sub node 10"
  }, {
    "group": "s",
    "name": "sub node 11"
  }, {
    "group": "r",
    "name": "sub node 12",
    "children": [{
      "group": "r",
      "name": "sub sub node 1"
    }, {
      "group": "r",
      "name": "sub sub node 2"
    }, {
      "group": "r",
      "name": "sub sub node 3"
    }]
  }]
}]


var w = 600,
  h = 600,
  radius = 30,
  node,
  link,
  root;

var pi = Math.PI;  
var arc = d3.svg.arc()
    .innerRadius(0)
    .outerRadius(radius)
    .startAngle(0) //converting from degs to radians
    .endAngle(pi)  

var force = d3.layout.force()
  .on("tick", tick)
  .charge(function(d) {
    return -1000;
  })
  .linkDistance(function(d) {
    return d.target._children ? 200 : 120;
  })
  .size([w, h - 160]);

var svg = d3.select("#viz").append("svg")
  .attr("width", w)
  .attr("height", h);

root = words[0]; //set root node
root.fixed = true;
root.x = w / 2;
root.y = h / 2 - 80;
update();

function update() {
  var nodes = flatten(root),
    links = d3.layout.tree().links(nodes);

  // Restart the force layout.
  force
    .nodes(nodes)
    .links(links)
    .start();

  // Update the links…
  link = svg.selectAll(".link")
    .data(links);

  // Enter any new links.
  link.enter().insert("svg:line", ".node")
    .attr("class", "link")
    .attr("x1", function(d) {
      return d.source.x;
    })
    .attr("y1", function(d) {
      return d.source.y;
    })
    .attr("x2", function(d) {
      return d.target.x;
    })
    .attr("y2", function(d) {
      return d.target.y;
    });

  // Exit any old links.
  link.exit().remove();

  // Update the nodes…
  node = svg.selectAll("circle.node")
    .data(nodes, function(d) {
      return d.name;
    })
    .style("fill", color);

  node.transition()
    .attr("r", radius);


  // Enter any new nodes.
  node.enter().append("svg:circle")
    .attr("class", "node")
    .attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    })
    .attr("r", radius)
    .style("fill", color)
    //.on("click", click)
    .on("click",function(){
          console.log("Click Main Circle")
    })
    //.call(force.drag);


  node.append("title")
    .text(function(d) {
      return d.name;
    });


  // Exit any old nodes.
  node.exit().remove();
}

function tick() {
  link.attr("x1", function(d) {
      return d.source.x;
    })
    .attr("y1", function(d) {
      return d.source.y;
    })
    .attr("x2", function(d) {
      return d.target.x;
    })
    .attr("y2", function(d) {
      return d.target.y;
    });

  node.attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    });
}

// Color leaf nodes orange, and packages white or blue.
function color(d) {
  if (d._children) {
    return "#95a5a6";
  } else {
    switch (d.group) {
      case 'r': //adverb
        return "#e74c3c";
        break;
      case 'n': //noun
        return "#3498db";
        break;
      case 'v': //verb
        return "#2ecc71";
        break;
      case 's': //adjective
        return "#e78229";
        break;
      default:
        return "#9b59b6";
    }
  }
}

// Toggle children on click.
function click(d) {
  if (d.children) {
    d._children = d.children;
    d.children = null;
  } else {
    d.children = d._children;
    d._children = null;
  }
  update();
}

// Returns a list of all nodes under the root.
function flatten(root) {
  var nodes = [],
    i = 0;

  function recurse(node) {
    if (node.children) node.size = node.children.reduce(function(p, v) {
      return p + recurse(v);
    }, 0);
    if (!node.id) node.id = ++i;
    nodes.push(node);
    return node.size;
  }

  root.size = recurse(root);
  return nodes;
}

我试图通过对圆圈进行分组并在组中添加半圆路径来对圆圈进行分组,但布局会中断.

 var arc = d3.svg.arc()
.innerRadius(0)
.outerRadius(30)
.startAngle(0) //converting from degs to radians
.endAngle(pi)

var g = node.enter().append("g")
  .attr("class", "node");

    g.append("svg:circle")
    .attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    })
    .attr("r", radius)
    .style("fill", color)
    //.on("click", click)
    .on("click",function(){
          console.log("Click Main Circle")
    })


   g.append("path")
   .attr("d", arc)
   .attr("fill", "blue")
   .attr("transform", "translate(200,200)")
   .on("click",function(d){
     console.log("path");
    })

最佳答案 以下是修复布局问题的方法.

而不是在刻度线中设置cx和cy.

做以下事项:

>组成一个小组
>在上面的组中添加圆圈(不要设置cx / cy)
>添加上述组的路径. (不要设置变换)

在tick中执行以下操作以转换其中包含的圆和路径.

function tick() {
  link.attr("x1", function(d) {
      return d.source.x;
    })
    .attr("y1", function(d) {
      return d.source.y;
    })
    .attr("x2", function(d) {
      return d.target.x;
    })
    .attr("y2", function(d) {
      return d.target.y;
    });
  //transform for nodes.
  node.attr("transform", function(d) {
    return "translate(" + d.x + "," + d.y + ")"
  })

}

工作代码here

希望这可以帮助!

点赞