I'm studying d3.js force chart and I have a question. Is it possible to make a force chart inside a triangle with some coordinates?
Here is my code:
var width = 500;
var height = 500;
//margin
var marginLeft = 10;
var marginTop = 10;
var marginRight = 10;
var marginBottom = 10;
var margin = { left: marginLeft , top: marginTop, right: marginRight, bottom: marginBottom};
//size of canvas
var innerWidth = width - margin.left - margin.right;
var innerHeight = height - margin.top - margin.bottom;
var radius = 10;
var svg = d3.select(".forcechart").append("svg")
.attr("width", width)
.attr("height", height)
.style("background", "#eee");
var tr = svg.append("polygon") // attach a polygon
.style("stroke", "black") // colour the line
.style("fill", "none") // remove any fill colour
.attr("points", "250,0, 12,173, 250,250"); // x,y points
var group = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var graph = {
"nodes": [ { "x": 0, "y": 0 },
{ "x": 100, "y": 100 },
{ "x": 500, "y": 500 },
{ "x": 300, "y": 0 },
{ "x": 300, "y": 0 },
{ "x": 100, "y": 100 },
{ "x": 500, "y": 500 },
{ "x": 300, "y": 0 },
{ "x": 300, "y": 0 },
{ "x": 100, "y": 100 },
{ "x": 500, "y": 500 },
{ "x": 300, "y": 0 },
{ "x": 300, "y": 0 },
{ "x": 100, "y": 100 },
{ "x": 500, "y": 500 },
{ "x": 300, "y": 0 },
{ "x": 300, "y": 0 },
{ "x": 100, "y": 100 },
{ "x": 500, "y": 500 },
{ "x": 300, "y": 0 },
{ "x": 300, "y": 0 },
],
"links": []
};
var nodes = graph.nodes,
links = graph.links;
var force = d3.layout.force()
.size([innerWidth, innerHeight])
.nodes(nodes)
.links(links);
force.linkDistance(100);
force.charge(-200);
var link = group.selectAll('.link')
.data(links)
.enter().append('line')
.attr('class', 'link');
var node = group.selectAll('.node')
.data(nodes)
.enter().append('circle')
.attr('class', 'node');
force.on('tick', function() {
node.attr('r', radius)
.attr('cx', function(d) { return d.x; })
.attr('cy', function(d) { return d.y; });
link.attr('x1', function(d) { return d.source.x; })
.attr('y1', function(d) { return d.source.y; })
.attr('x2', function(d) { return d.target.x; })
.attr('y2', function(d) { return d.target.y; });
});
force.start();
Full code is here: http://codepen.io/Balzzac/pen/vGWXdQ. Now it is a force chart inside "group", I need to make it is inside triangle "tr" so no one node is outside of boundaries of my triangle.
Thanks for help!
PS Sorry for my English =)
There's really two parts to this question. First, you need your force layout to converge on a different foci then the default width/2, height/2. This new foci should be the centroid of the triangle. Luckily
d3
has a helper method to compute this for polygons. Second, now that we are converging on the centroid of the triangle, how do we bound our nodes inside that triangle. The method I use below calculates the intersections between lines drawn from the centroid to the node and the line of the edge of the triangle (intersection calculation from this question). No intersections on all 3 edges means the circle is in the triangle, and an intersection on any edge means we need to bring the circle onto that edge.UPDATE -- generalized the code a bit and converted it to a block here to work with N sided polygons.
Let's get to the code: