Skip to content

Instantly share code, notes, and snippets.

@dianaow
Last active March 6, 2019 14:09
Show Gist options
  • Save dianaow/205a6e7b1c4347acebbba77852a6f80a to your computer and use it in GitHub Desktop.
Save dianaow/205a6e7b1c4347acebbba77852a6f80a to your computer and use it in GitHub Desktop.
Evenly spaced nodes around center: Method 1
license: mit

This method only works if all links point to the center node. I think its a neat trick using force charge strength to 'force' node placement evenly around a center, rather than coding a Mathematical formula to compute the position of each node.

Click on a node to swap position with the center node.

Built with blockbuilder.org

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js" type="text/javascript"></script>
<style>
line.node-link, path.node-link {
fill: none;
stroke: black
}
circle.node {
fill: white;
stroke: black
}
circle.node+text {
text-anchor: middle;
}
text {
font-family: sans-serif;
pointer-events: none;
}
</style>
</head>
<body>
<script>
var width = 500,
height = 500;
var dataset = {
"nodes":[
{"id":0,"name":"0"},
{"id":1,"name":"1"},
{"id":2,"name":"2"},
{"id":3,"name":"3"},
{"id":4,"name":"4"},
{"id":5,"name":"5"},
{"id":6,"name":"6"},
{"id":7,"name":"7"},
{"id":8,"name":"8"},
{"id":9,"name":"9"}
],
"links":[
{"id":1,"source":1,"target":0},
{"id":2,"source":2,"target":0},
{"id":3,"source":3,"target":0},
{"id":4,"source":4,"target":0},
{"id":5,"source":5,"target":0},
{"id":6,"source":6,"target":0},
{"id":7,"source":7,"target":0},
{"id":8,"source":8,"target":0},
{"id":9,"source":9,"target":0,}
]
};
var nodes = dataset.nodes
var links = dataset.links
var simulation = d3.forceSimulation()
.force("link", d3.forceLink()
.id(function(d,i) { return i })
.distance(100)
)
.force("charge", d3.forceManyBody().strength(function(d,i) { return i==0 ? 10*-500 : -500 }))
.force("center", d3.forceCenter(width / 2, height / 2));
simulation
.nodes(nodes)
simulation.force("link")
.links(links)
for (var i = nodes.length * nodes.length; i > 0; --i) simulation.tick();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
// Draw curved lines connecting node to center
//var lines = svg.selectAll("path")
//.data(links).enter().append("path")
//.attr("class", function(d,i) { return "node-link node-link-"+ d.id.toString()})
//.attr("d", function(d) {
//var dx = d.target.x - d.source.x,
//dy = d.target.y - d.source.y,
//dr = Math.sqrt(dx * dx + dy * dy);
//return "M" +
//d.source.x + "," +
//d.source.y + "A" +
//dr + "," + dr + " 0 0,1 " +
//d.target.x + "," +
//d.target.y;
//});
var gnodes = svg.selectAll('g.gnode')
.data(nodes).enter().append('g')
.attr("class", function(d,i) { return "gnode node-"+ d.id.toString()})
.attr("transform", function(d,i) {
return "translate(" + d.x + "," + d.y + ")";
});
d3.select(".node-0").classed("centered", true)
var node = gnodes.append("circle")
.attr("r", 25)
.attr("class", "node")
.on("mouseenter", function(d) {
node.transition().duration(100).attr("r", 25)
d3.select(this).transition().duration(100).attr("r", 30)
})
.on("mouseleave", function(d) {
node.transition().duration(100).attr("r", 25);
})
gnodes.on("click", function(d,i) {
swapPositions(d, d3.select(this))
});
var labels = gnodes.append("text")
.attr("dy", 4)
.text(function(d){return d.name})
function swapPositions(point, t) {
simulation.on("tick", tick).alpha(0.1).restart()
function tick() {
d3.select(".centered").classed("centered", false)
.transition().duration(100)
.attr("transform", t.attr("transform"))
d3.select(".node-" + point.id.toString()).classed("centered", true)
.transition().duration(100)
.attr("transform", "translate(" + width/2 + "," + height/2 + ")")
// Uncomment to animate line
//d3.select(".node-link-" + point.id.toString()).transition().duration(100)
//.style('stroke', 'salmon')
//.attr("d", function(d) {
//var dx = d.target.x - d.source.x,
//dy = d.target.y - d.source.y,
//dr = Math.sqrt(dx * dx + dy * dy);
//return "M" +
//d.target.x + "," +
//d.target.y + "A" +
//dr + "," + dr + " 0 0,1 " +
//d.source.x + "," +
//d.source.y;
//});
}
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment