Skip to content

Instantly share code, notes, and snippets.

@jwilber
Last active October 9, 2018 04:18
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 jwilber/9e882b3058aeab83901fe2fde5085793 to your computer and use it in GitHub Desktop.
Save jwilber/9e882b3058aeab83901fe2fde5085793 to your computer and use it in GitHub Desktop.
collision hover
license: mit

Based on Mike Bostok's force talk.

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
const width = window.innerWidth
const height = window.innerHeight
const nodes = d3.range(150).map(function() { return {r: Math.random() * 12 + 4, s:"hello"}; }),
root = nodes[0];
var color = d3.scaleOrdinal().range(['#e54b4b', '#ffa987', '#f7ebe8'])
//root is the first node, makes an invisible fixed point in the center of the group
root.radius = 0;
root.fixed = true;
const forceX = d3.forceX(width / 2).strength(0.015)
const forceY = d3.forceY(height / 2).strength(0.015)
//forceSimulation is a d3 method that is well described here: https://d3indepth.com/force-layout/
var force = d3.forceSimulation()
.velocityDecay(0.15)
.force("x", forceX)
.force("y", forceY)
.force("collide", d3.forceCollide().radius(function(d){
// this if loop creates the empty circle in the center, by giving the first node (root),
// which is invisible because it has a radius of 0 from above,
// a huge repulsion force. Try removing the 100 and making the 50, 500. The empty circle
// will change sizes on each refresh.
if(d === root){
return Math.random() * 50 + 50;
}
return d.r + 0.5;
}).iterations(5)) //without this line the circles will bounce as they are pulled
// together and then repelled continuously. This line limits that process to 5 times.
.nodes(nodes).on("tick", ticked); //listens for the "tick" event ?
// select the body and creating a new element of the SVG, and setting the height
// and width attributes
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
// this is where the circles are created
svg.selectAll("circle")
//this applies the nodes array for the data but cuts the root out (takes out the first
// node). creates a copy of the array and creates a new one with 199 elements
.data(nodes.slice(1))
.enter().append("circle")
//iterates through nodes and sets the radius of each circle
.attr("r", function(d) { return d.r * 2; })
//this sets the color as i mod 3, i increments from 0-199
.style("fill", function(d, i) { return color(i % 3); })
.attr('stroke-width', 1)
.attr('stroke', 'black')
function ticked(e) {
svg.selectAll("circle")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
};
//this section controls what happens when the mouse moves over the graphic
svg.on("mousemove", function() {
//p1 is an array that contains the x and y coordinates of the mouse
var p1 = d3.mouse(this);
// these set the first node (root) to the x and y coordinates of the mouse
// which causes the empty circle in the center to follow the mouse
root.fx = p1[0];
root.fy = p1[1];
//this sets how quickly the graphic resets upon each move the mouse
force.alphaTarget(0.5).restart();//reheat the simulation
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment