D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
jwilber
Full window
Github gist
collision hover
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>
https://d3js.org/d3.v4.min.js