D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
tomshanley
Full window
Github gist
Force with links
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v4.min.js"></script> <style> body { margin:0;top:0;right:0;bottom:0;left:0; } line { stroke: black; stroke-width: 1px } </style> </head> <body> <script> //have a play adding "actor" nodes, with unique names var nodes = [ { "type": "actor", "name": "A", "value": 15 }, { "type": "actor", "name": "B", "value": 5 }, //{ "type": "actor", "name": "C", "value": 25 }, //{ "type": "actor", "name": "D", "value": 50 }, { "type": "event", "name": "event1", "value": 0 } ] var links = [] var w = 800, h = 800, r = 350 const radians = 0.0174532925 var totalActorValue = 0 var inverseTotal = 0 var numberOfActors = 0 //total the actors' values nodes.forEach(function(node){ if (node.type == "actor") { totalActorValue = totalActorValue + node.value numberOfActors = numberOfActors + 1 } }) //fix the circles to the radius nodes.forEach(function(node, i){ if (node.type == "actor") { let a = (360/numberOfActors) * i node.fx = w/2 + x(a, r) node.fy = h/2 + y(a, r) } }) //update the event total nodes.forEach(function(node){ node.value = node.type == "event" ? totalActorValue : node.value }) //set the link distances nodes.forEach(function(node){ node.valuePct = 1/(node.value/totalActorValue) inverseTotal = node.type == "actor" ? inverseTotal + node.valuePct : inverseTotal }) nodes.forEach(function(node){ node.inverseProportion = node.valuePct/inverseTotal links.push({ "source": node.name, "target": "event1", "value": node.inverseProportion }) }) var g = d3.select("body").append("svg") .attr("width", w) .attr("height", h) .append("g") g.append("circle") .attr("cx", w/2) .attr("cy", h/2) .attr("r", r) .style("fill", "none") .style("stroke", "grey") var simulation = d3.forceSimulation() .force("link", d3.forceLink().id(function(d) { return d.name; })) var link = g.append("g") .attr("class", "links") .selectAll("line") .data(links) .enter() .append("line"); var node = g.append("g") .attr("class", "nodes") .selectAll("circle") .data(nodes) .enter() .append("circle") .attr("r", function(d){ return d.value }) .style("fill", function(d){ return d.type == "event" ? "PaleVioletRed" : "MediumSeaGreen" }) .style("stroke", "white") .style("stroke-width", 3) simulation .nodes(nodes) .on("tick", ticked) simulation.force("link") .links(links) .distance(function(d){ return d.value * (r*2) //- 50 //reduce the length to get 'tighter' links }) function ticked() { 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; }) } function x (angle, radius) { // rotate 90 let a = 90 - angle return radius * Math.sin(a * radians) } function y (angle, radius) { // rotate 90 let a = 90 - angle return radius * Math.cos(a * radians) } </script> </body>
https://d3js.org/d3.v4.min.js