Built with blockbuilder.org
forked from john-guerra's block: D3 Force Simulation
license: mit |
Built with blockbuilder.org
forked from john-guerra's block: D3 Force Simulation
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<style> | |
</style> | |
</head> | |
<body> | |
<h1>Force Directed layout</h1> | |
<svg | |
width=800 | |
height=400 | |
id="network"></svg> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script> | |
// Copy drag from: https://bl.ocks.org/mbostock/4062045 | |
let svg = d3.select("#network"), | |
width = +svg.attr("width"), | |
height = + svg.attr("height"), | |
N = 100, | |
r = d3.scaleSqrt() | |
.domain([0, 50]) | |
.range([1, 15]), | |
x = d3.scaleBand() | |
.domain(["M", "F"]) | |
.range([50, width-50]), | |
c = d3.scaleOrdinal() | |
.domain(["M", "F"]) | |
.range(["steelblue", "firebrick"]), | |
y = d3.scaleLinear() | |
.domain([20, 50]) | |
.range([height, 0]) | |
let nodes = [ | |
{name:"John", age:23, gender:"M"}, | |
{name:"Edwin", age:25, gender:"M"}, | |
{name:"Santi", age:25, gender:"M"}, | |
{name:"Eliza", age:22, gender:"F"}, | |
{name:"Magda", age:32, gender:"F"}, | |
{name:"Vicente", age:43, gender:"M"}, | |
{name:"Sonia", age:44, gender:"F"} | |
] | |
let links = [ | |
{source:"John", target:"Vicente", weigth:3}, | |
{source:"Edwin", target:"Vicente"}, | |
{source:"Santi", target:"Edwin"}, | |
{source:"Eliza", target:"Vicente"}, | |
{source:"Magda", target:"Vicente"}, | |
{source:"John", target:"Sonia"}, | |
{source:"Edwin", target:"Sonia"}, | |
{source:"Eliza", target:"Sonia"}, | |
] | |
console.log(width, height); | |
let simulation = d3.forceSimulation(nodes) | |
.force("x", d3.forceX((d) => x(d.gender)) | |
.strength(0.3)) | |
.force("y", d3.forceY((d) => y(d.age)) | |
.strength(0.5)) | |
// .force("charge", d3.forceManyBody().strength(-50)) | |
.force("collide", d3.forceCollide(d => r(d.age) + 1)) | |
.force("link", d3.forceLink(links) | |
.id((d) => d.name) | |
.distance(10).strength(0.1)) | |
.on("tick", ticked); | |
console.log("nodes", nodes); | |
console.log("links", links); | |
let sellinks = svg.selectAll(".link") | |
.data(links) | |
.enter() | |
.append("line") | |
.attr("class", "link") | |
.style("stroke", "#aaa") | |
.style("stroke-width", "10px") | |
.style("opacity", 0.9) | |
let selnodes = svg.selectAll(".node") | |
.data(nodes) | |
.enter() | |
.append("circle") | |
.attr("class", "node") | |
.style("fill", d => c(d.gender)) | |
.attr("r", d => r(d.age)) | |
.call(d3.drag() | |
.on("start", dragstarted) | |
.on("drag", dragged) | |
.on("end", dragended)); | |
selnodes.append("title") | |
.text(d => d.name); | |
function ticked() { | |
sellinks.attr("x1", (l) => l.source.x) | |
.attr("y1", (l) => l.source.y) | |
.attr("x2", (l) => l.target.x) | |
.attr("y2", (l) => l.target.y); | |
selnodes.attr("cx", (d) => d.x) | |
.attr("cy", (d) => d.y); | |
}// ticked | |
function dragstarted(d) { | |
if (!d3.event.active) simulation.alphaTarget(0.3).restart(); | |
d.fx = d.x; | |
d.fy = d.y; | |
} | |
function dragged(d) { | |
d.fx = d3.event.x; | |
d.fy = d3.event.y; | |
} | |
function dragended(d) { | |
if (!d3.event.active) simulation.alphaTarget(0); | |
d.fx = null; | |
d.fy = null; | |
} | |
</script> | |
</body> |