Mouseover to repel nodes. Adapted from my talk on force layouts. Compare to the canvas version.
-
-
Save thunderrabbit/6e16ba91075e4f4f63d99bf196a4df70 to your computer and use it in GitHub Desktop.
Collision Detection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: gpl-3.0 | |
redirect: https://observablehq.com/@d3/collision-detection/2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<body> | |
<script src="//d3js.org/d3.v6.js"></script> | |
<script> | |
// Adapted from Shan Carter's https://observablehq.com/@observablehq/simple-d3 | |
const width = window.innerWidth, | |
height = window.innerHeight; // https://stackoverflow.com/a/66143213/194309 | |
const SAMPLEJSON = '[{"bubble_id":"1","x":"1323","y":"50","radius":"20","fill":"#F0F"},{"bubble_id":"2","x":"120","y":"800","radius":"20","fill":"0"},{"bubble_id":"3","x":"250","y":"490","radius":"20","fill":"0"},{"bubble_id":"10","x":"1323","y":"150","radius":"22","fill":"0"},{"bubble_id":"12","x":"1323","y":"501","radius":"94","fill":"0"},{"bubble_id":"13","x":"1323","y":"50","radius":"22","fill":"0"},{"bubble_id":"20","x":"120","y":"600","radius":"23","fill":"0"},{"bubble_id":"22","x":"120","y":"800","radius":"20","fill":"#0F0"},{"bubble_id":"23","x":"120","y":"1800","radius":"20","fill":"0"},{"bubble_id":"30","x":"250","y":"590","radius":"28","fill":"0"},{"bubble_id":"32","x":"250","y":"190","radius":"43","fill":"0"},{"bubble_id":"33","x":"250","y":"490","radius":"33","fill":"0"}]'; | |
const circleEnter = function(enter) { | |
return enter // https://www.createwithdata.com/enter-exit-with-d3-join/ | |
.append("circle") | |
.attr("x", d => d.x) | |
.attr("y", d => d.y) | |
.attr("fill", d => d.fill) | |
.attr("r", d => d.radius) | |
} | |
const simulation = d3.forceSimulation() | |
.force('charge', d3.forceManyBody().strength(1)) | |
.force('center', d3.forceCenter(width / 2, height / 2)) | |
.force('collision', d3.forceCollide().radius(function(d) { | |
return d.radius | |
})); | |
const updateAll = function(nodes) { | |
simulation | |
.nodes(nodes) | |
.on("tick", function(){ | |
svg | |
.selectAll("circle") | |
.data(nodes, function(d) { // this keyFunction ensures bubbles stay consistent | |
return d.bubble_id; // id comes from MySQL DB bubbles.bubble_id | |
}) | |
.join(circleEnter) // https://www.createwithdata.com/enter-exit-with-d3-join/ | |
.attr("transform", function (d) { return "translate(" + d.x + ", " + d.y + ")"; }); | |
}); | |
} | |
const svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
// getData simulates reading from DB via API | |
const getData = function() { | |
// WAS: const promisetToGetBubbles = d3.json("//ppcapi.robnugen.com/api/v1/get_bubbles/"); | |
// WAS: promisetToGetBubbles.then(updateAll).catch(console.log.bind(console)); // h/t console bit https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html | |
updateAll(JSON.parse(SAMPLEJSON)); | |
}(); // immediately call this function to load circles on screen. same as `getData();` on next line | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment