Here is my current fiddle. I'm using foreignObjects to define custom icons for nodes (the fiddle is just using a ? but locally I'm using font-awesome icons). This works great, however the problem is that the arrows on the paths point to the top-left corner of the element. I've tried changing toying with many of the existing parameters and have looked through the API documentation but am unable to find a solution. I'm guessing I could do some complicated math in the code below, but I'm hoping for a parameter that can set some sort of radius for the end of the path.
function linkArc(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
}
The only documentation I found on paths was geo-paths. I tried using pointRadius anyway but it didn't seem to do anything at all. Here is the path definition:
var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")
.attr("class", function (d) { return "link " + d.type; })
.attr("marker-end", function (d) { return "url(#" + d.type + ")"; });
You can use the transform attribute to adjust the position:
var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")
.attr("transform", "translate(10,10)")
.attr("class", function (d) { return "link " + d.type; })
.attr("marker-end", function (d) { return "url(#" + d.type + ")"; });
Related
I want to centralize the node when I clicked it, so I used the following code:
node.on("click", function(d){
var cX = width/2;
var cY = height/2;
var dx = cX - d.x;
var dy = cY - d.y;
link.attr("transform", function(d) { return "translate(" + dx + "," + dy + ")"; });
node.attr("transform", function(d) { return "translate(" + dx + "," + dy + ")"; });
});
It works for the "normal node", but when changed the node to image, the link is moved while the node (image) is still here.
Here is my example: http://talk.huacishu.com/t11.html
I know a little bit about d3js\javascript, anyone can tell me where is wrong?
I finally made it by another way :
Using "var g_container = svg.append(g) "
to append a "g" label(g_container), and move the "g_container" to centralize the clicked node.
here is the final project:
https://myaisv.github.io/curry/renlifang/connan/t1.html
So, I have been trying to visualize the popular tree of life data using dendogram layout of d3.js exactly similar to that of http://bl.ocks.org/mbostock/4063570.
I have problem with the links in the diagram as you can see in screenshot. I have also posted the code don't know where exactly I am going wrong.
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(40,0)");
var tree = d3.cluster()
.size([height, width - 160]);
d3.text("test.txt", function(error, data) {
if (error) throw error;
var dat = parseNewick(data);
console.log(dat);
var root = d3.hierarchy(dat)
.sort(function(a,b){return b.height - a.height });
tree(root);
var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + d.y + "," + d.x
+ "C" + (d.parent.y + 100) + "," + d.x
+ " " + (d.parent.y + 100) + "," + d.parent.x
+ " " + d.parent.y + "," + d.parent.x;
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 2.5);
});
I would like to add separate arrows (one for the path from node A to B, and the other for B to A) to a d3 graph that I have made (see the Plunker version here), instead of adding a single arrow with two arrows at each end.
I have tried the code here, by changing my 'tick' function, as well as defining a path variable to be as below:
var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter().append("svg:path")
.attr("class", "link")
.attr("marker-end", "url(#end)");
function tick() {
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" +
d.source.x + "," +
d.source.y + "A" +
dr + "," + dr + " 0 0,1 " +
d.target.x + "," +
d.target.y;
});
However, this seems to stop the nodes from displaying, as well as the zoom/filtering functionality.
Does anyone know how I can stop this happening?
Best,
Ben
Visualization Goal: Build a D3 Tree that has text at, both, nodes and links, and that transitions cleanly, when nodes are selected/deselected.
Problem: While I can get link text, called "predicates," to show up along the centroid of all link paths, I can't seem to get them to transition in and out "smoothly."
Question: Can someone please help me please help me clean up the code and better understand how tree "link" transitions are behaving so I understand the theory behind the code?
Visualization and Source Location: http://bl.ocks.org/Guerino1/raw/ed80661daf8e5fa89b85/
The existing code looks as follows...
var linkTextItems = vis.selectAll("g.linkText")
.data(tree.links(nodes), function(d) { return d.target.id; })
var linkTextEnter = linkTextItems.enter().append("svg:g")
.attr("class", "linkText")
.attr("transform", function(d) { return "translate(" + (d.target.y + 20) + "," + (getCenterX(d)) + ")"; });
// Add Predicate text to each link path
linkTextEnter.append("svg:foreignObject")
.attr("width", "120")
.attr("height", "40")
.append("xhtml:body")
.attr("xmlns", "http://www.w3.org/1999/xhtml")
.html(function(d){ return "<p>" + (linksByIdHash[d.source.id + ":" + d.target.id].predicate) + "</p>"; });
// Transition nodes to their new position.
//var linkTextUpdate = linkTextItems.transition()
//.duration(duration)
//.attr("transform", function(d) { return "translate(" + d.source.x + "," + d.source.y + ")"; })
//linkTextUpdate.select("linkText")
//.style("fill-opacity", 1);
// Transition exiting linkText to the new position of the parents.
var linkTextExit = linkTextItems.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.source.y + 20 + "," + (getCenterX(d)) + ")"; })
.remove();
linkTextExit.select("linkText")
.style("fill-opacity", 1e-6);
function getCenterX(d) {
var xS = d.source.x;
var xT = d.target.x;
if(xS == xT)
{ return (xS - (xS - xT)/2); }
else if(xS > xT)
{return (xS - (xS - xT)/2); }
else
{ return (xT - (xT - xS)/2); }
}
Some Symptoms...
When link text transitions in or out, it's choppy / not smooth
When a branch is collapse, link text doesn't transition to appropriate path centroids
My frustration is that I feel like I'm very close but that I'm missing something very simple/basic. Any help is greatly appreciate.
A very similar question has been asked here: D3 force directed layout with bounding box ... I tried implementing the suggested solutions but without success, so I'll ask again :(
This is my code
// initialization stuff happening up here...
// create graph:
this.onStateChange = function() {
svg.selectAll("g").remove();
nodes = {};
links = [];
links = eval(this.getState().string);
links.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name : link.source});
link.target = nodes[link.target] || (nodes[link.target] = {name : link.target});
});
force.nodes(d3.values(nodes)).links(links).start();
path = svg.append("g").selectAll("path")
.data(force.links()).enter()
.append("path")
.attr("class", function(d) {return "link " + d.type;})
.attr("marker-end", function(d) {return "url(#" + d.type + ")";});
circle = svg.append("g").selectAll("circle")
.data(force.nodes())
.enter()
.append("circle")
.attr("r", 8)
.call(force.drag);
text = svg.append("g").selectAll("text")
.data(force.nodes())
.enter()
.append("text")
.style("font-size","15px")
.attr("x", 10)
.attr("y", ".42em").text(function(d) {return d.name;});
};
//add gravity
function tick() {
path.attr("d", linkArc);
circle.attr("transform", transform);
text.attr("transform", transform);
circle.attr("cx", function(d) { return d.x = Math.max(r, Math.min(w - r, d.x)); })
.attr("cy", function(d) { return d.y = Math.max(r, Math.min(h - r, d.y)); });
path.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; });
}
function linkArc(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + ","
+ d.source.y + "A" + dr + "," + dr
+ " 0 0,1 " + d.target.x + "," + d.target.y;
}
function transform(d) {
return "translate(" + d.x + "," + d.y + ")";
}
};
However this doesnt work - I cannot move the nodes anymore and they are stuck in the upper right corner.
I found out how it goes. If anybody wants to add a bounding box to this mobile-patent-suits example (http://bl.ocks.org/mbostock/1153292), this might be helpful:
function tick() {
//circle.attr("transform", transform); //no need for this anymore
circle.attr("cx", function(d) { return d.x = Math.max(8, Math.min(300 - 8, d.x)); })
.attr("cy", function(d) { return d.y = Math.max(8, Math.min(280 - 8, d.y)); });
text.attr("transform", transform);
path.attr("d", linkArc);
}
function linkArc(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x
+ "," + d.source.y
+ "A" + dr
+ "," + dr
+ " 0 0,1 " + d.target.x
+ "," + d.target.y;
}
//function transform(d) { //don't need this anymore either
//return "translate(" + d.x + "," + d.y + ")";
//}
};