Skip to content

Instantly share code, notes, and snippets.

@thunderrabbit
Forked from mbostock/.block
Last active November 22, 2021 23:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thunderrabbit/6e16ba91075e4f4f63d99bf196a4df70 to your computer and use it in GitHub Desktop.
Save thunderrabbit/6e16ba91075e4f4f63d99bf196a4df70 to your computer and use it in GitHub Desktop.
Collision Detection
license: gpl-3.0
redirect: https://observablehq.com/@d3/collision-detection/2
<!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