简体   繁体   中英

how to draw polygon by d3.js

I have created five node using d3.js, and make links each other to make a polygon but they are not adjacent position to make a polygon, instead its making a random view other than a polygon.Am I missing something here, please take a look and suggest me.

  var width = 300, height = 300 var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var force = d3.layout.force() .gravity(1) .linkDistance(200) .charge(-100) .size([width, height]); var datajson = { "nodes": [{ "name": "a", "group": 2 }, { "name": "b", "group": 1 }, { "name": "c", "group": 1 }, { "name": "d", "group": 2 }, { "name": "e", "group": 2 }], "links": [{ "source": 0, "target": 1, "value": 1, "distance": 90 }, { "source": 1, "target": 2, "value": 2, "distance": 90 }, { "source": 2, "target": 3, "value": 3, "distance": 90 }, { "source": 3, "target": 4, "value": 5, "distance": 90 }, { "source": 4, "target": 0, "value": 5, "distance": 90 }] } force .nodes(datajson.nodes) .links(datajson.links) .start(); var drag = force.drag() .on("dragstart", dblclick); var link = svg.selectAll(".link") .data(datajson.links) .enter().append("line") .attr("class", "link"); var node = svg.selectAll(".node") .data(datajson.nodes) .enter().append("g") .attr("class", "node") .call(force.drag); node.append("image") .attr("x", -8) .attr("y", -8) .attr("width", 45) .attr("height", 45) .attr("xlink:href", function(d) { var rnd = Math.floor(Math.random() * 64 + 1); return null; }); node.append("text") .attr("dx", 12) .attr("dy", ".35em") .text(function(d) { return d.name }); force.on("tick", function() { 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("transform", function(d) { return "translate(" + dx + "," + dy + ")"; }); }); function dblclick(d) { d3.select(this).classed("fixed", d.px = dx, d.py = dy); console.log(d); } 
 .link { stroke: #dfdfdf; } .node text { pointer-events: none; font: 10px sans-serif; } .link.red { stroke: blue; } 
 <!DOCTYPE html> <meta charset="utf-8"> <body> <script src="http://d3js.org/d3.v3.min.js"></script> </body> 

When you call

force
  .nodes(datajson.nodes)
  .links(datajson.links)
  .start();

d3 randomly picks starting positions for the nodes, because they don't yet have x and y properties assigned.

However, prior to calling the code above, you could loop over each node and assign it x and y of the corners of the polygon, and they should maintain that relationship. They might not bounce around much though, because they'd already be at their intended position. In that case, you can slightly vary their position relative to their final intended position, by adding some random x and y displacement to the starting values.

Working example

The code that pre-positions the nodes is

 var numNodes = datajson.nodes.length
 var r = 20;
 datajson.nodes.forEach(function(node, i) {
   node.x = width/2  + r * Math.sin(2 * Math.PI * i / numNodes)
   node.y = height/2 + r * Math.cos(2 * Math.PI * i / numNodes)
   console.log(node)
 })

I also had to tweak charge (-1000) and linkDistance (100) to make it work.


  var width = 300, height = 300 var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var force = d3.layout.force() .gravity(.5) .linkDistance(100) .charge(-1000) .size([width, height]); var datajson = { "nodes": [{ "name": "a", "group": 2 }, { "name": "b", "group": 1 }, { "name": "c", "group": 1 }, { "name": "d", "group": 2 }, { "name": "e", "group": 2 }], "links": [{ "source": 0, "target": 1, "value": 1, "distance": 90 }, { "source": 1, "target": 2, "value": 2, "distance": 90 }, { "source": 2, "target": 3, "value": 3, "distance": 90 }, { "source": 3, "target": 4, "value": 5, "distance": 90 }, { "source": 4, "target": 0, "value": 5, "distance": 90 }] } var numNodes = datajson.nodes.length var r = 20; datajson.nodes.forEach(function(node, i) { node.x = width/2 + r * Math.sin(2 * Math.PI * i / numNodes) node.y = height/2 + r * Math.cos(2 * Math.PI * i / numNodes) console.log(node) }) force .nodes(datajson.nodes) .links(datajson.links) .start(); var drag = force.drag() .on("dragstart", dblclick); var link = svg.selectAll(".link") .data(datajson.links) .enter().append("line") .attr("class", "link"); var node = svg.selectAll(".node") .data(datajson.nodes) .enter().append("g") .attr("class", "node") .call(force.drag); node.append("image") .attr("x", -8) .attr("y", -8) .attr("width", 45) .attr("height", 45) .attr("xlink:href", function(d) { var rnd = Math.floor(Math.random() * 64 + 1); return null; }); node.append("text") .attr("dx", 12) .attr("dy", ".35em") .text(function(d) { return d.name }); force.on("tick", function() { 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("transform", function(d) { return "translate(" + dx + "," + dy + ")"; }); }); function dblclick(d) { d3.select(this).classed("fixed", d.px = dx, d.py = dy); console.log(d); } 
 .link { stroke: #dfdfdf; } .node text { pointer-events: none; font: 10px sans-serif; } .link.red { stroke: blue; } 
 <!DOCTYPE html> <meta charset="utf-8"> <body> <script src="http://d3js.org/d3.v3.min.js"></script> </body> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM