javascript - How to make d3.js force layout gravity rectangular? -
in d3.js force layout, giving gravity value makes layout circular.
however, i'd make force layout rectangular, while nodes have negative charge , even distance. (like above)
is there way make force layout rectangular?
can achieve modifying tick function?
here code:
var background = d3.select('.background'); var width = background.node().getboundingclientrect().width, height = background.node().getboundingclientrect().height; var nodes = d3.range(50).map(function(d, i) { return { text: "hello" }; }); var messages = background.selectall('.message') .data(nodes) .enter() .append('div') .attr('class', 'message') .text(d => d.text) .each(function(d, i) { d.width = this.getboundingclientrect().width; d.height = this.getboundingclientrect().height; }); var force = d3.layout.force() .gravity(1/88) .charge(-50) .nodes(nodes) .size([width, height]); messages.call(force.drag); force.on('tick', function(e) { messages.each(d => { d.x = math.max(0, math.min(width - d.width, d.x)); d.y = math.max(0, math.min(height - d.height, d.y)); }); messages.style('left', d => `${d.x}px`) .style('top', d => `${d.y}px`); }); force.start();
body { padding: 0; margin: 0; } .background { width: 100%; height: 100vh; border: 1px solid #007aff; } .message { display: inline-block; font-family: sans-serif; border-radius: 100vh; color: white; padding: 10px; background-color: #007aff; position: absolute; } .boundary { display: inline-block; width: 10px; height: 10px; background-color: red; position: absolute; }
<script src="https://d3js.org/d3.v3.min.js"></script> <body> <div class="background"> </div> </body>
ok, edit 3: in d3v4, forcecollide can used set minimum distances between nodes, if use positive strength, draws nodes together, helping set them distance apart (although looks better circles rectangles):
var force = d3.forcesimulation(nodes) .force("charge", d3.forcemanybody().strength(-10)) .force("collide", d3.forcecollide(30).strength(1).iterations(1)) .force('x', d3.forcex(width/2).strength(0.5)) .force('y', d3.forcey(height/2).strength(10));
assuming nodes in rectangular svg, limiting them within centre of svg can out edges:
position.nodes(nodes).on('tick', function ticks() { nodes.attr("cx", function(d) { return d.x = math.max(20, math.min(width + 20, d.x)) }).attr("cy", function(d) { return d.y = math.max(20, math.min(height + 20, d.y)); }) });
and playing around force strengths can draw them in along y-axis:
var position = d3.forcesimulation(nodes).force("charge", d3.forcemanybody()) .force('x', d3.forcex(width/2).strength(1)) .force('y', d3.forcey(height/2).strength(5));
it seems forces lot more customisable in v4 v3, think forcecollide integrated workarounds library. so, can try , find v3 workaround, or maybe upgrading v4.
in v3 played around gravity, charge , limiting x , y maintain nodes in box bit better, fiddle here. don't know enough v3 improve beyond that.
Comments
Post a Comment