Built with blockbuilder.org
xxxxxxxxxx
<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